关于android:ViewPager可以在每个页面中有多个视图吗?

Can ViewPager have multiple views in per page?

在尝试了"画廊"和"水平滚动视图"之后,我发现"视图寻呼机"可以满足我的需求,但缺少一小部分内容。 查看寻呼机每页可以有多个视图吗?

我知道View Pager每次滑动仅显示1个视图/页面。 我想知道是否可以限制视图宽度,以便显示下面的第二个视图?

例如:我有3个视图,并且我希望屏幕显示视图1和视图2的一部分,以便用户知道还有更多内容,因此他们可以滑动视图2。

1
2
|view 1|view 2|view 3|
|screen   |


通过为ViewPager指定负边距,我发现了一个甚至更简单的解决方案。我已经在GitHub上创建了MultiViewPager项目,您可能需要看一下:

https://github.com/Pixplicity/MultiViewPager

尽管MultiViewPager期望使用子视图来指定尺寸,但是原理围绕着设置页边距进行:

1
2
ViewPager.setPageMargin(
    getResources().getDimensionPixelOffset(R.dimen.viewpager_margin));

然后,在dimens.xml中指定此尺寸:

1
<dimen name="viewpager_margin">-64dp</dimen>

为了补偿重叠的页面,每个页面的内容视图都有相反的边距:

1
2
android:layout_marginLeft="@dimen/viewpager_margin_fix"
android:layout_marginRight="@dimen/viewpager_margin_fix"

再次在dimens.xml中:

1
<dimen name="viewpager_margin_fix">32dp</dimen>

(请注意,viewpager_margin_fix尺寸是绝对viewpager_margin尺寸的一半。)

我们在荷兰报纸应用程序De Telegraaf Krant中实现了这一点:

Phone example in De Telegraaf Krant Tablet example


马克·墨菲(Mark Murphy)有一篇有趣的博客文章专门针对此问题。尽管我最终在该线程中使用了自己的解决方案,但值得一看的是Dave Smith的代码,Mark在博客文章中引用了该代码:

https://gist.github.com/8cbe094bb7a783e37ad1/

警告!在采用这种方法之前,请注意这种方法的一些非常严重的问题,这些问题在本文结尾处和下面的评论中均提到。

您将得到以下结果:

Screenshot of Dave Smiths PagerContainer

通过将ViewPager包装到FrameLayout的子类中,将其设置为特定大小并调用setClipChildren(false),可以有效地工作。这会阻止Android裁剪超出ViewPager边界的视图,并在视觉上完成您想要的操作。

在XML中,这非常简单:

1
2
3
4
5
6
7
8
9
10
<com.example.pagercontainer.PagerContainer
    android:id="@+id/pager_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#CCC">
    <android.support.v4.view.ViewPager
        android:layout_width="150dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal" />
</com.example.pagercontainer.PagerContainer>

添加一些代码来处理ViewPager外部的触摸事件,并在滚动时使显示无效,然后就完成了。

话虽这么说,虽然总体上可以正常工作,但我确实注意到,存在一个边缘情况,用这种相当简单的结构无法解决:在ViewPager上调用setCurrentPage()时。我能找到解决此问题的唯一方法是将ViewPager本身子类化,并使其invalidate()函数也使PagerContainer无效。


可以在同一屏幕上显示多个页面。
一种方法是通过重写PAgerAdapter中的getPageWidth()方法。 getPageWidth()返回一个介于0和1之间的浮点数,指示该页面应占据Viewpager多少宽度。默认情况下,它设置为1。因此,您可以将其更改为所需的宽度。
您可以在此处和github项目中阅读有关此内容的更多信息。


这是我的方法:

1
2
3
4
5
6
7
8
9
10
<android.support.v4.view.ViewPager
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_gravity="center"
    android:layout_marginBottom="8dp"
    android:clipToPadding="false"
    android:gravity="center"
    android:paddingLeft="36dp"
    android:paddingRight="36dp"/>

在活动中,我使用这个:

1
markPager.setPageMargin(64);

希望能帮助到你!


我有一个相同的问题,唯一的区别是我需要一次显示3页(上一页,当前页和下一页)。经过对最佳解决方案的长期研究,我认为我找到了它。
解决方案是这里的一些答案的混合:

正如@Paul Lammertsma的回答所指出的那样-Mark Murphy博客中Dave Smith的代码是解决方案的基础。对我来说,唯一的问题是ViewPager仅位于屏幕的顶部,这是由于它们在xml文件中提供的大小:

1
2
 android:layout_width="150dp"
 android:layout_height="100dp"

这对我的目的不利,因为我一直在寻找会散布在整个屏幕上的东西。所以我将其更改为包装内容,如您在此处看到的:

1
2
3
4
5
6
7
8
9
10
  <com.example.nutrino_assignment.PagerContainer
    android:id="@+id/pager_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#CCC">
    <android.support.v4.view.ViewPager
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />
  </com.example.nutrino_assignment.PagerContainer>

现在,我失去了本教程尝试执??行的所有操作。使用@andro的答案,我一次可以显示多于1页:正好2张!当前和下一个。
通过覆盖如下内容来做到这一点:

1
2
3
4
        @Override
    public float getPageWidth(int position) {
        return(0.9f);
    }

那几乎是我所需要的...(即使我认为足以满足您的要求),但对于其他可能需要我所需要的东西的人:
对于解决方案的最后一部分,我还是在@Paul Lammertsma的回答中使用了这个想法。
在Dave Smith的代码中,您会在onCreate方法中找到以下行:

1
2
   //A little space between pages
    pager.setPageMargin(15);

我替换为:

1
2
   //A little space between pages
    pager.setPageMargin(-64);

现在在第一页上看起来:

1
2
|view 1|view 2|view 3|
|screen   |

而在第二个看起来像:

1
2
|view 1|view 2|view 3|
     |screen    |

希望它能对某人有所帮助!我浪费了大约2天的时间...
祝好运。


1
viewPager.setPageMargin(-18);// adjust accordingly ,-means less gap

在图像适配器中

1
2
3
4
5
6
7
8
9
10
11
12
private class ImagePagerAdapter2 extends PagerAdapter {
    private int[] mImages = new int[] {

            R.drawable.add1,
            R.drawable.add3,
            R.drawable.add4,
            R.drawable.add2,
    };
    @Override
    public float getPageWidth(int position) {
        return .3f;
    }

调整返回值...少表示更多图像...... 0.3表示一次至少3张图像。


主要活动xml文件添加此代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
      <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="130dp"
                    android:layout_marginLeft="5dp"
                    android:layout_marginRight="5dp"
                    android:orientation="vertical"
                    android:weightSum="1">
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="130dp">
                        <com.wonderla.wonderla.muthootpathanamthitta.activity_muthootpathanm.PagerContainer
                            android:id="@+id/pager_container"
                            android:layout_width="match_parent"
                            android:layout_height="fill_parent">
                            <android.support.v4.view.ViewPager
                                android:id="@+id/viewpager"
                                android:layout_width="100dip"
                                android:layout_height="100dip"/>
                      </com.wonderla.wonderla.muthootpathanamthitta.activity_muthootpathanm.PagerContainer>
                    </RelativeLayout>
                </LinearLayout>

主要活动代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class MainActivity extends Activity{
 final Integer[] XMEN2= {R.mipmap.bookticket,R.mipmap.safty,R.mipmap.privacy};
 private ArrayList<Integer> XMENArray2 = new ArrayList<Integer>();
 PagerContainer mContainer;
 int currentPage2 = 0;
 private static int NUM_PAGES2 = 0;
 ViewPager mPager2;

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
        initData2();}
 private void initViews() {
  mPager2 = (ViewPager)findViewById(R.id.viewpager);
  mContainer = (PagerContainer)findViewById(R.id.pager_container);
  mPager2.setOffscreenPageLimit(5);
  mPager2.setPageMargin(15);
  mPager2.setClipChildren(false);
 }

   private void initData2() {

        for(int i=0;i<XMEN2.length;i++)
            XMENArray2.add(XMEN2[i]);
        mPager2.setAdapter(new Sliding_Adaptertwo(getActivity(),XMENArray2));
        NUM_PAGES2 =XMEN2.length;
        final Handler handler = new Handler();
        final Runnable Update = new Runnable() {
            public void run() {
                if (currentPage2 == NUM_PAGES2) {
                    currentPage2= 0;
                }mPager2.setCurrentItem(currentPage2++, true);
            }
        };
        Timer swipeTimer = new Timer();
        swipeTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                handler.post(Update);
            }
        }, 3000, 3000);

    }



}

Pager View pagercontainer类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import android.content.Context;

import android.graphics.Point;

import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import android.widget.FrameLayout;


public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener {

    private ViewPager mPager;
    boolean mNeedsRedraw = false;

    public PagerContainer(Context context) {
        super(context);
        init();
    }

    public PagerContainer(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PagerContainer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        //Disable clipping of children so non-selected pages are visible
        setClipChildren(false);

        //Child clipping doesn't work with hardware acceleration in Android 3.x/4.x
        //You need to set this value here if using hardware acceleration in an
        // application targeted at these releases.
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        try {
            mPager = (ViewPager) getChildAt(0);
            mPager.setOnPageChangeListener(this);
        } catch (Exception e) {
            throw new IllegalStateException("The root child of PagerContainer must be a ViewPager");
        }
    }

    public ViewPager getViewPager() {
        return mPager;
    }

    private Point mCenter = new Point();
    private Point mInitialTouch = new Point();

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mCenter.x = w / 2;
        mCenter.y = h / 2;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //We capture any touches not already handled by the ViewPager
        // to implement scrolling from a touch outside the pager bounds.
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mInitialTouch.x = (int)ev.getX();
                mInitialTouch.y = (int)ev.getY();
            default:
                ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y);
                break;
        }

        return mPager.dispatchTouchEvent(ev);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        //Force the container to redraw on scrolling.
        //Without this the outer pages render initially and then stay static
        if (mNeedsRedraw) invalidate();
    }

    @Override
    public void onPageSelected(int position) { }

    @Override
    public void onPageScrollStateChanged(int state) {
        mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
    }
}

及其适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class Sliding_Adaptertwo extends PagerAdapter {


    private ArrayList<Integer> IMAGES;
    private LayoutInflater inflater;
    private Context context;


    public Sliding_Adaptertwo(Context context, ArrayList<Integer> IMAGES) {
        this.context = context;
        this.IMAGES=IMAGES;
        inflater = LayoutInflater.from(context);
    }

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

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

    @Override
    public Object instantiateItem(ViewGroup view, int position) {
        View imageLayout = inflater.inflate(R.layout.sliding_layout, view, false);

        assert imageLayout != null;
        final ImageView imageView = (ImageView) imageLayout
                .findViewById(R.id.image);


        imageView.setImageResource(IMAGES.get(position));

        view.addView(imageLayout, 0);

        return imageLayout;
    }

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

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

    @Override
    public Parcelable saveState() {
        return null;
    }


}

适配器类的xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    >

    <ImageView
        android:id="@+id/image"
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:adjustViewBounds="true"
        android:layout_gravity="center"
        android:scaleType="fitXY"
        android:src="@drawable/ad1"
       />
</FrameLayout>

它工作正常


在使用此代码的xml文件中(主要活动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="130dp"
                    android:layout_marginLeft="5dp"
                    android:layout_marginRight="5dp"
                    android:orientation="vertical"
                    android:weightSum="1">
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="130dp">
                        <com.wonderla.wonderla.muthootpathanamthitta.activity_muthootpathanm.PagerContainer
                            android:id="@+id/pager_container"
                            android:layout_width="match_parent"
                            android:layout_height="fill_parent">
                            <android.support.v4.view.ViewPager
                                android:id="@+id/viewpager"
                                android:layout_width="100dip"
                                android:layout_height="100dip"/>
                      </com.wonderla.wonderla.muthootpathanamthitta.activity_muthootpathanm.PagerContainer>
                    </RelativeLayout>
                </LinearLayout>

1
2
LayoutParams lp = new LayoutParams(width,height);
viewpager.setLayoutParams(lp);