ViewPager中的ViewPager

我想创build一个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] 

这怎么可能?

覆盖父ViewPager中的canScroll:

 @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; } } 

我search了很长时间,使另一个ViewPager中的ViewPager工作,并在这里find了“Android Noob”的解决scheme。 非常感谢你!

我也想分享我的解决scheme。 一旦内部ViewPager的最后(最右)元素到达,我添加了将滑动pipe理切换到周围的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; } } 

希望这有助于未来的人!

如果子viewpager在最后,请滚动父级

 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); } 

首先以这种方式创build一个自定义的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的水平手势是否需要位于片段的右边或左边(true),或者是否适用于全片段屏幕(false)。 如果你想,例如,只有你的第一个片段使用右边界移动到下一个片段,因为第一个片段有另一个水平滚动事件,这将是覆盖方法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); } 

最后一步将是在您的主类中使用您的CustomViewPager类:

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

和xml:

 <my.cool.package.name.CustomViewPager android:id="@+id/myCustomViewPager" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1" /> 

我不明白你为什么不创build一个视图寻呼机,并使实例化的项目逻辑,以获得来自不同来源的数据,这将使你达到你的目标同样我没有看到一个情况下,你需要2个查看寻呼机

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

并在代码中:

 @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个viewpage的逻辑,你可以自定义它比我更jsut给你的想法

PS我在这里编码,所以如果有字符大小写错误或拼写错误原谅我。

希望这有助于,如果你得到更具体的,需要更多的帮助添加评论我的答案,我会修改它

我通过创build两个自定义ViewPager的inheritance者来解决这个任务。 在我的情况 – 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); } } 

只有在最后一页上的内部寻呼机时,外部寻呼机才开始向左滚动。 反之亦然。

我只是testing这个案例,你可以做到没有额外的工作,下面是我的演示

 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<ViewPager> pagers = new ArrayList<ViewPager>(); for(int j = 0; j < 3; j++) { List<LinearLayout> list = new ArrayList<LinearLayout>(); 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<LinearLayout> data; public MyViewPagerAdapter(List<LinearLayout> 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<ViewPager> data; public MyParentViewPagerAdapter(List<ViewPager> 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; } } } 

xml是简单的,在我的主布局中的外部ViewPager和另一个LinearLayout的内部ViewPager