ViewPager внутри ViewPager

Я хотел бы создать ViewPager (с тремя элементами), где каждый из его представлений – другой ViewPager (с двумя элементами). Затем пользователь пролистет такие элементы:

ViewPager1[0] ViewPager2[0] ViewPager1[0] ViewPager2[1] ViewPager1[1] ViewPager2[0] ViewPager1[1] ViewPager2[1] ViewPager1[2] ViewPager2[0] ViewPager1[2] ViewPager2[1] 

Как это возможно?

переопределить canScroll в родительском ViewPager:

 @Override protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if(v != this && v instanceof ViewPager) { return true; } return super.canScroll(v, checkV, dx, x, y); } 

Попробуй это:

 public class CustomViewPager extends ViewPager { private int childId; public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (childId > 0) { ViewPager pager = (ViewPager)findViewById(childId); if (pager != null) { pager.requestDisallowInterceptTouchEvent(true); } } return super.onInterceptTouchEvent(event); } public void setChildId(int id) { this.childId = id; } } 

Я долго искал, чтобы сделать ViewPager внутри другой работы ViewPager и нашел решение «Android Noob» здесь. Большое вам спасибо за это!

Я тоже хотел поделиться своим решением. Я добавил возможность переключить управление салфеткой на окружающий ViewPager, когда достигнут последний (самый правый) элемент во внутреннем ViewPager. Чтобы предотвратить сбои, я также сохраняю первое направление прокрутки для последних элементов: т. Е. Если вы сначала проведите пальцем влево, минимальный правый салфет не сбросит состояние прокрутки.

 public class GalleryViewPager extends ViewPager { /** the last x position */ private float lastX; /** if the first swipe was from left to right (->), dont listen to swipes from the right */ private boolean slidingLeft; /** if the first swipe was from right to left (<-), dont listen to swipes from the left */ private boolean slidingRight; public GalleryViewPager(final Context context, final AttributeSet attrs) { super(context, attrs); } public GalleryViewPager(final Context context) { super(context); } @Override public boolean onTouchEvent(final MotionEvent ev) { final int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // Disallow parent ViewPager to intercept touch events. this.getParent().requestDisallowInterceptTouchEvent(true); // save the current x position this.lastX = ev.getX(); break; case MotionEvent.ACTION_UP: // Allow parent ViewPager to intercept touch events. this.getParent().requestDisallowInterceptTouchEvent(false); // save the current x position this.lastX = ev.getX(); // reset swipe actions this.slidingLeft = false; this.slidingRight = false; break; case MotionEvent.ACTION_MOVE: /* * if this is the first item, scrolling from left to * right should navigate in the surrounding ViewPager */ if (this.getCurrentItem() == 0) { // swiping from left to right (->)? if (this.lastX <= ev.getX() && !this.slidingRight) { // make the parent touch interception active -> parent pager can swipe this.getParent().requestDisallowInterceptTouchEvent(false); } else { /* * if the first swipe was from right to left, dont listen to swipes * from left to right. this fixes glitches where the user first swipes * right, then left and the scrolling state gets reset */ this.slidingRight = true; // save the current x position this.lastX = ev.getX(); this.getParent().requestDisallowInterceptTouchEvent(true); } } else /* * if this is the last item, scrolling from right to * left should navigate in the surrounding ViewPager */ if (this.getCurrentItem() == this.getAdapter().getCount() - 1) { // swiping from right to left (<-)? if (this.lastX >= ev.getX() && !this.slidingLeft) { // make the parent touch interception active -> parent pager can swipe this.getParent().requestDisallowInterceptTouchEvent(false); } else { /* * if the first swipe was from left to right, dont listen to swipes * from right to left. this fixes glitches where the user first swipes * left, then right and the scrolling state gets reset */ this.slidingLeft = true; // save the current x position this.lastX = ev.getX(); this.getParent().requestDisallowInterceptTouchEvent(true); } } break; } super.onTouchEvent(ev); return true; } } 

Надеюсь, это поможет кому-то в будущем!

Если дочерний просмотрщик находится в конце, прокрутите родительский

 protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if(v != this && v instanceof ViewPager) { int currentItem = ((ViewPager) v).getCurrentItem(); int countItem = ((ViewPager) v).getAdapter().getCount(); if((currentItem==(countItem-1) && dx<0) || (currentItem==0 && dx>0)){ return false; } return true; } return super.canScroll(v, checkV, dx, x, y); } 

Сначала создайте собственный class ViewPager следующим образом:

 public class CustomViewPager extends ViewPager { public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if(v instanceof ViewPager) { return true; } return super.canScroll(v, checkV, dx, x, y); } } 

Возврат (логический) метода canScroll скажет вам, должен ли горизонтальный жест изменить страницу для ViewPager должен находиться в правой или левой границе fragmentа (true) или если он работает для полного экрана fragmentа (false). Если вы хотите, например, чтобы только ваш первый fragment использовал правую границу для перехода к следующему fragmentу, потому что первый fragment имеет другое событие горизонтальной прокрутки, это будет код для переопределения метода canScroll:

 @Override protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if(v instanceof ViewPager) { int currentItem = ((ViewPager) v).getCurrentItem(); if((currentItem==0)){ return true; } return false; } return super.canScroll(v, checkV, dx, x, y); } 

Последним шагом будет использование classа CustomViewPager в вашем основном classе:

 ViewPager myPager= (CustomViewPager)myContext.findViewById(R.id.myCustomViewPager); 

и xml:

  

Я не понимаю, почему бы вам просто не создать 1 просмотр пейджера и не создать логику элементарных данных для получения данных из разных источников, что позволило бы вам достичь своей цели в равной степени. Я не вижу случая, когда вам нужно 2 пейджера представления

пример

 ViewPager1[0] ViewPager2[0] = page 0 (position/2) = 0
ViewPager1[0] ViewPager2[1] = page 1 ((position-1)/2) = 0
ViewPager1[1] ViewPager2[0] = page 2 (position/2) = 1
ViewPager1[1] ViewPager2[1] = page 3 ((position-1)/2) = 1
ViewPager1[2] ViewPager2[0] = page 4 (position/2) = 2
ViewPager1[2] ViewPager2[1] = page 5 ((position-1)/2) = 2

и в коде:

 @Override public Object instantiateItem(View collection, int position) { LayoutInflater inflater = THISCLASSNAME.this.getLayoutInflater(); View v = null; if(position%2 == 0) { // viewpager 1 code int vp1pos = position/2; v = inlater.inflate(R.layout.somelayout, collection, false); Button b = (Button)v.findViewById(R.id.somebutton); b.setText(array1[vp1pos]); } else { int vp2pos = (position-1)/2; v = inlater.inflate(R.layout.somelayout, collection, false); Button b = (Button)v.findViewById(R.id.somebutton); b.setText(array2[vp2pos]); } ((DirectionalViewPager) collection).addView(v, 0); return v; } 

таким образом у вас есть фактически 2 логика просмотра, вы можете настроить ее больше, чем я jsut дает вам идеи

PS Я закодировал это здесь, поэтому, если есть ошибки в случае символов или орфографические ошибки, простите меня.

надеюсь, что это поможет, если вы получите более конкретную информацию и вам потребуется дополнительная помощь, добавьте комментарий к моему ответу, и я поправлю его

Я решаю эту задачу, создавая два собственных виджета ViewPager. В моем случае – OuterViewPager и InnerViewPager.

 public class InnerViewPager extends ViewPager { private int mPrevMoveX; public InnerViewPager(Context context) { super(context); } public InnerViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPrevMoveX = (int) event.getX(); return super.onTouchEvent(event); case MotionEvent.ACTION_MOVE: int distanceX = mPrevMoveX - (int) event.getX(); mPrevMoveX = (int) event.getX(); boolean canScrollLeft = true; boolean canScrollRight = true; if(getCurrentItem() == getAdapter().getCount() - 1) { canScrollLeft = false; } if(getCurrentItem() == 0) { canScrollRight = false; } if(distanceX > 0) { return canScrollRight; } else { return canScrollLeft; } } return super.onInterceptTouchEvent(event); } public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPrevMoveX = (int) event.getX(); return super.onTouchEvent(event); case MotionEvent.ACTION_MOVE: int distanceX = mPrevMoveX - (int) event.getX(); mPrevMoveX = (int) event.getX(); boolean canScrollLeft = true; boolean canScrollRight = true; if(getCurrentItem() == getAdapter().getCount() - 1) { canScrollLeft = false; } if(getCurrentItem() == 0) { canScrollRight = false; } if(distanceX > 0) { super.onTouchEvent(event); return canScrollLeft; } else { super.onTouchEvent(event); return canScrollRight; } } return super.onTouchEvent(event); } } public class OuterViewPager extends ViewPager { private int mPrevMoveX; public OuterViewPager(Context context) { super(context); init(); } public OuterViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setOnPageChangeListener(new CustomPageChangeListener()); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mPrevMoveX = (int) ev.getX(); return super.onInterceptTouchEvent(ev); case MotionEvent.ACTION_MOVE: /*there you should get currentInnerPager - instance of InnerPager on current page of instance of OuterPager*/ int distanceX = mPrevMoveX - (int) ev.getX(); mPrevMoveX = (int) ev.getX(); boolean canScrollLeft = true; boolean canScrollRight = true; if(currentInnerPager.getCurrentItem() == currentInnerPager.getAdapter().getCount() - 1) { canScrollLeft = false; } if(currentInnerPager.getCurrentItem() == 0) { canScrollRight = false; } if(distanceX > 0) { return !canScrollLeft; } else { return !canScrollRight; } } return super.onInterceptTouchEvent(ev); } } 

Внешний пейджер начинает прокрутку влево только при внутреннем пейджере на последней странице. И наоборот.

Я просто проверяю этот случай, вы можете сделать это без дополнительной работы, ниже моя демонстрация

 public class MainActivity extends AppCompatActivity { public static final String TAG = "TAG"; ViewPager parentPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); initViews(); initData(); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); } private void initViews() { parentPager = (ViewPager) findViewById(R.id.parent_pager); } private void initData() { List pagers = new ArrayList(); for(int j = 0; j < 3; j++) { List list = new ArrayList(); for (int i = 0; i < 5; i++) { LinearLayout layout = new LinearLayout(this); TextView textView = new TextView(this); textView.setText("This is the" + i + "th page in PagerItem" + j); layout.addView(textView); textView.setGravity(Gravity.CENTER); LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams(); params.gravity = Gravity.CENTER; list.add(layout); } MyViewPagerAdapter adapter = new MyViewPagerAdapter(list); final ViewPager childPager = (ViewPager) LayoutInflater.from(this).inflate(R.layout.child_layout, null).findViewById(R.id.child_pager); childPager.setAdapter(adapter); childPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { Log.d(TAG, "onPageScrolled: position: " + position + ", positionOffset: " + positionOffset); } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } }); pagers.add(childPager); } MyParentViewPagerAdapter parentAdapter = new MyParentViewPagerAdapter(pagers); parentPager.setAdapter(parentAdapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } class MyViewPagerAdapter extends PagerAdapter { private List data; public MyViewPagerAdapter(List data) { this.data = data; } @Override public int getCount() { return data.size(); } @Override public int getItemPosition(Object object) { return data.indexOf(object); } @Override public Object instantiateItem(ViewGroup container, int position) { LinearLayout linearLayout = data.get(position); container.addView(linearLayout); return data.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { LinearLayout layout = data.get(position); container.removeView(layout); layout = null; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } } class MyParentViewPagerAdapter extends PagerAdapter { private List data; public MyParentViewPagerAdapter(List data) { this.data = data; } @Override public int getCount() { return data.size(); } @Override public int getItemPosition(Object object) { return data.indexOf(object); } @Override public Object instantiateItem(ViewGroup container, int position) { ViewPager pager = data.get(position); if(pager.getParent() != null) { ((ViewGroup) pager.getParent()).removeView(pager); } container.addView(pager); return data.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { ViewPager pager = data.get(position); container.removeView(pager); pager = null; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } } } 

ViewPager прост, внешний ViewPager в моем основном макете и внутренний ViewPager в другом LinearLayout

Давайте будем гением компьютера.