ViewPager inside ViewPager

2019-01-07 02:44发布

I would like to create a ViewPager (with three items) where each of its view is another ViewPager (with two items). User then swipe items like this:

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

How would that be possible?

8条回答
我命由我不由天
2楼-- · 2019-01-07 03:26

I just test this case, you can make it without extra working, below is my demo

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

The xml is simple, outer ViewPager in my main layout and the inner ViewPager in another LinearLayout

查看更多
来,给爷笑一个
3楼-- · 2019-01-07 03:35

override canScroll in the parent 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);
}
查看更多
冷血范
4楼-- · 2019-01-07 03:37

Try this:

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;
    }
}
查看更多
SAY GOODBYE
5楼-- · 2019-01-07 03:37

First create a custom ViewPager class in this way:

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

The return (boolean) of the method canScroll will tell you if the horizontal gesture to change page for ViewPager needs to be in the right or left border of the fragment(true) or if it works for full fragment screen (false). If you want, for example, that only your first fragment use the right border to move to the next fragment because the first fragment has another horizontal scrolling event, this will be the code to overriding the method 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);
}

The Last Step will be to use your CustomViewPager class in your main class:

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

and the xml:

<my.cool.package.name.CustomViewPager
        android:id="@+id/myCustomViewPager"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
查看更多
冷血范
6楼-- · 2019-01-07 03:45

I don't understand why don't you just create 1 view pager and make the instantiate item logic to get data from different sources, which would make you reach your goal equally I do not see a case where you need 2 viewpagers

Example

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

and in the code:

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

this way you have virtually 2 viewpagers logic, you may customize it more than that I am just giving you ideas

P.S. I coded this here so if there are character case mistakes or spelling mistakes forgive me.

hope this helps, if you get more specific and need more help to add a comment on my answer and I will amend it

查看更多
The star\"
7楼-- · 2019-01-07 03:48

I solve this task by creating two custom ViewPager's inheritors. In my case - OuterViewPager and 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);
    }
}

Outer pager starts scroll left only when inner pager on last page. And vice versa.

查看更多
登录 后发表回答