46

Jon Willisは、彼のコードで無限スクロールを有効にする方法について投稿しました。

そこで彼はViewPager、Android サポート ライブラリのクラスにいくつかの変更を加えたと述べました。どのような変更が加えられましたか?また、そのViewPager変更でライブラリを「再コンパイル」するにはどうすればよいですか?

4

10 に答える 10

40

アダプターの小さなハックを使用して、この問題を非常に簡単に解決しました。これが私のコードです:

public class MyPagerAdapter extends FragmentStatePagerAdapter
{
    public static int LOOPS_COUNT = 1000;
    private ArrayList<Product> mProducts;


    public MyPagerAdapter(FragmentManager manager, ArrayList<Product> products)
    {
        super(manager);
        mProducts = products;
    }


    @Override
    public Fragment getItem(int position)
    {
        if (mProducts != null && mProducts.size() > 0)
        {
            position = position % mProducts.size(); // use modulo for infinite cycling
            return MyFragment.newInstance(mProducts.get(position));
        }
        else
        {
            return MyFragment.newInstance(null);
        }
    }


    @Override
    public int getCount()
    {
        if (mProducts != null && mProducts.size() > 0)
        {
            return mProducts.size()*LOOPS_COUNT; // simulate infinite by big number of products
        }
        else
        {
            return 1;
        }
    }
} 

次に、ViewPager で、現在のページを中央に設定します。

mAdapter = new MyPagerAdapter(getSupportFragmentManager(), mProducts);
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(mViewPager.getChildCount() * MyPagerAdapter.LOOPS_COUNT / 2, false); // set current item in the adapter to middle
于 2012-03-04T14:59:47.200 に答える
38

ご回答ありがとうございます。

私はそれを少し違った方法で解決しました。

Android サポート ライブラリの ViewPager クラスのコードを変更しました。方法setCurrentItem(int)

アニメーションでページを切り替えます。このメソッドは、スムーズ スクロールを可能にするインデックスとフラグを必要とする内部メソッドを呼び出します。このフラグはboolean smoothScroll. このメソッドを2番目のパラメーターで拡張すると、boolean smoothScroll解決しました。このメソッドを呼び出すと、setCurrentItem(int index, boolean smoothScroll)無限にスクロールできました。

完全な例を次に示します。

真ん中のページしか表示されていないことを考慮してください。さらに、ページを個別に保存して、より簡単に処理できるようにしました。

private class Page {
  View page;
  List<..> data;
}
// page for predecessor, current, and successor
Page[] pages = new Page[3];




mDayPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

        @Override
        public void onPageScrollStateChanged(int state) {

            if (state == ViewPager.SCROLL_STATE_IDLE) {

                if (mFocusedPage == 0) {
                    // move some stuff from the 
                                            // center to the right here
                    moveStuff(pages[1], pages[2]);

                    // move stuff from the left to the center 
                    moveStuff(pages[0], pages[1]);
                    // retrieve new stuff and insert it to the left page
                    insertStuff(pages[0]);
                }
                else if (mFocusedPage == 2) {


                    // move stuff from the center to the left page
                    moveStuff(pages[1], pages[0]); 
                    // move stuff from the right to the center page
                    moveStuff(pages[2], pages[1]); 
                    // retrieve stuff and insert it to the right page
                                            insertStuff(pages[2]);
                }

                // go back to the center allowing to scroll indefinitely
                mDayPager.setCurrentItem(1, false);
            }
        }
    });

ただし、Jon Willis Code がなければ、自分で解決することはできなかったでしょう。

編集:これについてのブログ投稿は次のとおりです。

于 2011-12-01T21:41:42.077 に答える
10

実際、私はこの「無限」のページネーションを行うためのさまざまな方法を検討してきました.人間の時間の概念は無限であるということですが(時間の始まりと終わりの概念がありますが)、コンピューターはディスクリートで。最小時間と最大時間があります (時間の経過とともに調整できます。2000 年問題の根拠を覚えていますか?)。

とにかく、この議論のポイントは、実際には有限の日付範囲を介して比較的無限の日付範囲をサポートするのに十分である/すべきであるということです。この好例は、Android フレームワークのCalendarView実装とそのWeeksAdapter中の です。デフォルトの最小日付は 1900 年であり、デフォルトの最大日付は 2100 年です。これは、今日から半径 10 年の範囲内にいる人のカレンダー使用の 99% を簡単にカバーするはずです。

彼らが実装で行っていること (週に焦点を当てている) は、最小日と最大日の間の週数を計算することです。これがページャーのページ数になります。ページャーは、これらのページすべてを同時に維持する必要はなく ( setOffscreenPageLimit(int))、ページ番号 (またはインデックス/位置) に基づいてページを作成できればよいことに注意してください。この場合、インデックスは、その週が最小日から何週間離れているかです。このアプローチでは、最小日付とページ数 (最大日付までの距離) を維持するだけでよく、どのページについても、そのページに関連付けられた週を簡単に計算できます。ループ (別名、無限のページネーション) をサポートしていないという事実を回避したり、ViewPager無限にスクロールできるように動作させようとしたりしないでください。

new FragmentStatePagerAdapter(getFragmentManager()) {
    @Override
    public Fragment getItem(int index) {
        final Bundle arguments = new Bundle(getArguments());
        final Calendar temp_calendar = Calendar.getInstance();
        temp_calendar.setTimeInMillis(_minimum_date.getTimeInMillis());
        temp_calendar.setFirstDayOfWeek(_calendar.getStartOfWeek());
        temp_calendar.add(Calendar.WEEK_OF_YEAR, index);
        // Moves to the first day of this week
        temp_calendar.add(Calendar.DAY_OF_YEAR,
                -UiUtils.modulus(temp_calendar.get(Calendar.DAY_OF_WEEK) - temp_calendar.getFirstDayOfWeek(),
                7));
        arguments.putLong(KEY_DATE, temp_calendar.getTimeInMillis());
        return Fragment.instantiate(getActivity(), WeekDaysFragment.class.getName(), arguments);
    }

    @Override
    public int getCount() {
        return _total_number_of_weeks;
    }
};

次にWeekDaysFragment、引数で渡された日付から始まる週を簡単に表示できます。

または、Android のカレンダー アプリの一部のバージョンでは、ViewSwitcher(表示されるページと非表示のページの 2 つのページしかないことを意味します) を使用しているようです。次に、ユーザーがスワイプした方法に基づいて遷移アニメーションを変更し、それに応じて次/前のページをレンダリングします。このようにして、2 つのページを無限に切り替えるだけなので、無限のページネーションが得られます。ただし、これにはページに a を使用する必要がViewあります。これは、最初のアプローチで行った方法です。

一般に、「無限のページネーション」が必要な場合は、ページが何らかの形で日付または時刻に基づいていることが原因である可能性があります。この場合は、代わりに比較的無限である有限の時間サブセットを使用することを検討してください。これはCalendarView、たとえば実装方法です。ViewSwitcherまたは、アプローチを使用することもできます。これらの 2 つのアプローチの利点は、どちらもViewSwitcherorViewPagerで特に異常なことを行わず、それらが無限に動作するように強制するためのトリックや再実装を必要としないことです (ViewSwitcherは既にビューを無限に切り替えるように設計されていますがViewPager、有限で動作するように設計されています、必ずしも一定ではない、一連のページ)。

于 2012-12-26T22:42:00.627 に答える
9

あなたがする必要があるのは、ここの例を見るだけです

295 行目では、ページが常に 1 に設定されているため、スクロール可能であり、メソッド内のページ数が 3 であることがわかりますgetCount()

変更する必要があるのは主に 2 点です。残りはロジックであり、別の方法で処理できます。

295 行目で常に現在のページを 1 に設定すると、位置が使用できなくなるため、現在の実際のページをカウントする個人用カウンターを作成するだけです。

psこのコードは私のものではありません。質問でリンクした質問で参照されました

于 2011-11-23T10:16:53.950 に答える
2

CustomPagerAdapterによってハッキングされました:

MainActivity.java :

import android.content.Context;
import android.os.Handler;
import android.os.Parcelable;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private List<String> numberList = new ArrayList<String>();
    private CustomPagerAdapter mCustomPagerAdapter;
    private ViewPager mViewPager;
    private Handler handler;
    private Runnable runnable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        numberList.clear();
        for (int i = 0; i < 10; i++) {
        numberList.add(""+i);
        }

        mViewPager = (ViewPager)findViewById(R.id.pager);
        mCustomPagerAdapter = new CustomPagerAdapter(MainActivity.this);
        EndlessPagerAdapter mAdapater = new EndlessPagerAdapter(mCustomPagerAdapter);
        mViewPager.setAdapter(mAdapater);


        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                int modulo = position%numberList.size();
                Log.i("Current ViewPager View's Position", ""+modulo);

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

        handler = new Handler();
        runnable = new Runnable() {
            @Override
            public void run() {

                mViewPager.setCurrentItem(mViewPager.getCurrentItem()+1);
                handler.postDelayed(runnable, 1000);
            }
        };

        handler.post(runnable);

    }

    @Override
    protected void onDestroy() {
        if(handler!=null){
            handler.removeCallbacks(runnable);
        }
        super.onDestroy();
    }

    private class CustomPagerAdapter extends PagerAdapter {

        Context mContext;
        LayoutInflater mLayoutInflater;

        public CustomPagerAdapter(Context context) {
            mContext = context;
            mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        @Override
        public int getCount() {
            return numberList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == ((LinearLayout) object);
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View itemView = mLayoutInflater.inflate(R.layout.row_item_viewpager, container, false);

            TextView textView = (TextView) itemView.findViewById(R.id.txtItem);
            textView.setText(numberList.get(position));
            container.addView(itemView);
            return itemView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((LinearLayout) object);
        }
    }

    private class EndlessPagerAdapter extends PagerAdapter {

        private static final String TAG = "EndlessPagerAdapter";
        private static final boolean DEBUG = false;

        private final PagerAdapter mPagerAdapter;

        EndlessPagerAdapter(PagerAdapter pagerAdapter) {
            if (pagerAdapter == null) {
                throw new IllegalArgumentException("Did you forget initialize PagerAdapter?");
            }
            if ((pagerAdapter instanceof FragmentPagerAdapter || pagerAdapter instanceof FragmentStatePagerAdapter) && pagerAdapter.getCount() < 3) {
                throw new IllegalArgumentException("When you use FragmentPagerAdapter or FragmentStatePagerAdapter, it only supports >= 3 pages.");
            }
            mPagerAdapter = pagerAdapter;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            if (DEBUG) Log.d(TAG, "Destroy: " + getVirtualPosition(position));
            mPagerAdapter.destroyItem(container, getVirtualPosition(position), object);

            if (mPagerAdapter.getCount() < 4) {
                mPagerAdapter.instantiateItem(container, getVirtualPosition(position));
            }
        }

        @Override
        public void finishUpdate(ViewGroup container) {
            mPagerAdapter.finishUpdate(container);
        }

        @Override
        public int getCount() {
            return Integer.MAX_VALUE; // this is the magic that we can scroll infinitely.
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mPagerAdapter.getPageTitle(getVirtualPosition(position));
        }

        @Override
        public float getPageWidth(int position) {
            return mPagerAdapter.getPageWidth(getVirtualPosition(position));
        }

        @Override
        public boolean isViewFromObject(View view, Object o) {
            return mPagerAdapter.isViewFromObject(view, o);
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            if (DEBUG) Log.d(TAG, "Instantiate: " + getVirtualPosition(position));
            return mPagerAdapter.instantiateItem(container, getVirtualPosition(position));
        }

        @Override
        public Parcelable saveState() {
            return mPagerAdapter.saveState();
        }

        @Override
        public void restoreState(Parcelable state, ClassLoader loader) {
            mPagerAdapter.restoreState(state, loader);
        }

        @Override
        public void startUpdate(ViewGroup container) {
            mPagerAdapter.startUpdate(container);
        }

        int getVirtualPosition(int realPosition) {
            return realPosition % mPagerAdapter.getCount();
        }

        PagerAdapter getPagerAdapter() {
            return mPagerAdapter;
        }

    }
}

activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="180dp">
    </android.support.v4.view.ViewPager>

</RelativeLayout>

row_item_viewpager.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtItem"
        android:textAppearance="@android:style/TextAppearance.Large"/>

</LinearLayout>

終わり

于 2015-12-03T08:09:23.133 に答える
0

日を無限にスクロールするには、ページャーに適切なフラグメントがあることが重要であるため、このページに私の答えを書きました(AndroidのViewpagerで日を際限なく切り替える

それは非常にうまくいっています!上記の回答は、うまくいきたかったのでうまくいきませんでした。

于 2014-05-01T15:32:30.637 に答える