【问题标题】:Can ViewPager have multiple views in per page?ViewPager 可以在每页中有多个视图吗?
【发布时间】:2012-02-27 16:33:43
【问题描述】:

在尝试了 Gallery 和 Horizo​​ntal Scroll View 之后,我发现 View Pager 可以满足我的需要,但缺少一件小事。 View Pager 可以每页有多个视图吗?

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

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

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

【问题讨论】:

  • 你有没有试过做一个模型看看这是否有效?似乎只需编写代码并尝试一下就不会花费很长时间。
  • View Pager 本身将每个视图限制在整个屏幕上。我发表这篇文章的原因是想看看是否有人有使用 View Pager 的经验,以及是否可以在同一屏幕上显示两个以上的视图。
  • 使用this link,覆盖onInterceptTouchEvent方法并返回false。

标签: android android-viewpager


【解决方案1】:

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

https://github.com/Pixplicity/MultiViewPager

虽然 MultiViewPager 需要一个子视图来指定尺寸,但其原理围绕着设置页边距:

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

然后我在 dimens.xml 中指定了这个维度:

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

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

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

再次在dimens.xml:

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

(注意viewpager_margin_fix 维度是绝对viewpager_margin 维度的一半。)

我们实现了这个in the Dutch newspaper app De Telegraaf Krant

【讨论】:

  • 我无法将它与您的解决方案一起使用,您可以发布一个示例吗?谢谢
  • 我也无法让它工作。具体来说,虽然 viewpager 的边距似乎已设置,但在我的 FrameLayout 中补偿 android:layout_marginRight & Left 似乎没有任何作用。我看到的只是重叠的页面……Android Studio 的布局预览显示应该已经应用了边距。 (注意我使用的是android-support-v4)
  • 根据您在每个页面中的布局方式,您可能想要应用android:paddingLeftandroid:paddingRight。相邻视图可以共享边距,页面最多可以重叠一半的所需边距。
  • 很棒的技术,但不幸的是,即使我点击居中页面任一侧的页面,适配器的 itemSelected(int position) 方法也总是以居中页面的位置触发。
  • @NullPointer 很高兴你喜欢它!欢迎分享!
【解决方案2】:

马克·墨菲有an interesting blog post addressing precisely this problem。虽然我最终使用了my own solution in this thread,但还是值得看看 Dave Smith 的代码,Mark 在博文中引用了该代码:

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

警告! 在您采用这种方法之前,请注意这种方法的一些非常严重的问题,在本文末尾和下面的 cmets 中都有提及。

你最终会得到这个:

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

在 XML 中,很简单:

<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 无效。

【讨论】:

  • 这种技术存在各种问题,包括触摸事件。恐怕我不能分享代码,因为它在一个专有项目中,但建议你去the other solution
  • 根据我的经验,这种技术的动画/响应不是很清晰。不确定某些东西是否会重新绘制额外的时间或什么。我也不相信我在使用非常复杂的内容视图。这似乎是一个简单的视图/组件......令人失望的Android没有原生的非弃用解决方案:(
  • 嗨@PaulLammertsma 我使用了上述解决方案并面临 setCurrentItem(2) 方法的大问题。你能帮我解决这个问题吗?
  • 非常详尽的博客。帮助我解决了我正在寻找的某些变化。 @Paul Lammertsma 感谢您重定向到该博客。真的很感激
【解决方案3】:

可以在同一屏幕上显示多个页面。 其中一种方法是覆盖 PAgerAdapter 中的 getPageWidth() 方法。 getPageWidth() 返回一个介于 0 和 1 之间的浮点数,指示页面应该占用多少 Viewpager 的宽度。默认情况下,它设置为 1。因此,您可以将其更改为您想要的宽度。 您可以阅读更多关于此heregithub project 的信息。

【讨论】:

  • 这行得通,但请记住,它不会在您的视图中居中页面;即最左边的页面将与 ViewPager 的左侧齐平。
  • 那么,我们可以在中心做吗?
  • 简单的一行解决了我的问题.. 在我的情况下,我想显示 3 个项目.. 所以 pagewidth=0.33... 未来用户的示例代码 @Override public float getPageWidth(int position) { return 0.33f; }
【解决方案4】:

这就是我得到它的方式:

<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"/>

在活动中,我使用这个:

markPager.setPageMargin(64);

希望对你有帮助!

【讨论】:

  • 工作,不需要活动 setPagerMargin :)
【解决方案5】:

我遇到了同样的问题,唯一的区别是我需要一次显示 3 页(前一页、当前页和下一页)。经过长时间的研究以获得最佳解决方案,我想我找到了。 解决方案是这里的几个答案的混合:

正如@Paul Lammertsma 的answer 指出的那样——Mark Murphy 博客中的 Dave Smith 的代码是解决方案的基础。对我来说唯一的问题是ViewPager 仅在屏幕的顶部,因为它们在 xml 文件中给出了它的大小:

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

这对我的目的不利,因为我一直在寻找会遍布整个屏幕的东西。所以我改变了它来包装你可以在这里看到的内容:

  <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 的answer,我一次可以显示超过一页:正好是2!当前和下一个。 通过如下覆盖来做到这一点:

        @Override 
    public float getPageWidth(int position) {
        return(0.9f); 
    }

这几乎是我所需要的......(尽管我认为它足以满足你的要求),但对于其他可能需要我所需要的东西的人来说: 对于解决方案的最后一部分,我再次使用了@Paul Lammertsma 在this answer 中的想法。 在 Dave Smith 的代码中,您会在 onCreate 方法中找到这一行:

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

我替换为:

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

现在在第一页看起来:

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

而在 2 日它看起来像:

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

希望它会帮助别人!我浪费了2天的时间... 祝你好运。

【讨论】:

    【解决方案6】:
    viewPager.setPageMargin(-18);// adjust accordingly ,-means less gap
    

    在图像适配器中

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

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

    【讨论】:

    • 这是一个同时处理多个页面的好解决方案。但不完整。最好看看这个帖子:commonsware.com/blog/2012/08/20/…。但主要问题是,它没有回答 OP 的问题。
    • 现在用水平或垂直模式的 RecyleView 替换 ViewPager 要好得多。
    【解决方案7】:
    LayoutParams lp = new LayoutParams(width,height);
    viewpager.setLayoutParams(lp);
    

    【讨论】:

      【解决方案8】:

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

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

      【讨论】:

        【解决方案9】:

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

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

        主要活动代码

        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 查看 pagercontainer 类

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

        及其适配器

        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文件

        <?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>
        

        效果很好

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-20
          • 1970-01-01
          • 1970-01-01
          • 2011-08-15
          • 2011-10-06
          • 1970-01-01
          • 2012-05-17
          • 2012-01-27
          相关资源
          最近更新 更多