Jon Willisは、彼のコードで無限スクロールを有効にする方法について投稿しました。
そこで彼はViewPager
、Android サポート ライブラリのクラスにいくつかの変更を加えたと述べました。どのような変更が加えられましたか?また、そのViewPager
変更でライブラリを「再コンパイル」するにはどうすればよいですか?
Jon Willisは、彼のコードで無限スクロールを有効にする方法について投稿しました。
そこで彼はViewPager
、Android サポート ライブラリのクラスにいくつかの変更を加えたと述べました。どのような変更が加えられましたか?また、そのViewPager
変更でライブラリを「再コンパイル」するにはどうすればよいですか?
アダプターの小さなハックを使用して、この問題を非常に簡単に解決しました。これが私のコードです:
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
ご回答ありがとうございます。
私はそれを少し違った方法で解決しました。
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 がなければ、自分で解決することはできなかったでしょう。
編集:これについてのブログ投稿は次のとおりです。
実際、私はこの「無限」のページネーションを行うためのさまざまな方法を検討してきました.人間の時間の概念は無限であるということですが(時間の始まりと終わりの概念がありますが)、コンピューターはディスクリートで。最小時間と最大時間があります (時間の経過とともに調整できます。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 つのアプローチの利点は、どちらもViewSwitcher
orViewPager
で特に異常なことを行わず、それらが無限に動作するように強制するためのトリックや再実装を必要としないことです (ViewSwitcher
は既にビューを無限に切り替えるように設計されていますがViewPager
、有限で動作するように設計されています、必ずしも一定ではない、一連のページ)。
あなたがする必要があるのは、ここの例を見るだけです
295 行目では、ページが常に 1 に設定されているため、スクロール可能であり、メソッド内のページ数が 3 であることがわかりますgetCount()
。
変更する必要があるのは主に 2 点です。残りはロジックであり、別の方法で処理できます。
295 行目で常に現在のページを 1 に設定すると、位置が使用できなくなるため、現在の実際のページをカウントする個人用カウンターを作成するだけです。
psこのコードは私のものではありません。質問でリンクした質問で参照されました
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>
終わり
日を無限にスクロールするには、ページャーに適切なフラグメントがあることが重要であるため、このページに私の答えを書きました(AndroidのViewpagerで日を際限なく切り替える)
それは非常にうまくいっています!上記の回答は、うまくいきたかったのでうまくいきませんでした。