【问题标题】:Android ViewPager - Show preview of page on left and rightAndroid ViewPager - 在左右显示页面预览
【发布时间】:2012-04-23 07:00:12
【问题描述】:

我正在使用 Android 的 ViewPager。我想要做的是在左侧和右侧显示页面的预览。我已经看到在哪里可以使用否定的pageMargin 来显示右侧的预览。

setPageMargin(-100);

无论如何,我也可以显示左侧的预览吗?它基本上类似于我正在寻找的画廊小部件。

【问题讨论】:

  • 好问题!最近查了源码,如果不想修改src代码,感觉没有更好的办法了。 setPageMargin(-100) 工作正常吗?
  • GalleryView 会做得更好,除非您使用带有片段的 ViewPger。
  • 我可以使用图库视图来做到这一点。在任何方面都与 viewpager 相同。不知道为什么不推荐使用画廊
  • 这个问题已经在 [post here][1] [1]: stackoverflow.com/questions/13914609/…
  • 我正在使用 Vierpager 和 Fragments。所以我可以使用相同的方法吗?

标签: android android-viewpager


【解决方案1】:

要显示左右页面的预览,请设置以下两个值

  1. viewpager.setClipToPadding(false);
  2. viewpager.setPadding(left,0,right,0);

如果您需要在 viewpager 中的两个页面之间留出空间,请添加

viewpager.setPageMargin(int);

【讨论】:

  • 是的,我同意你的观点。
  • 酷,就是这么简单:) 是否可以在视图寻呼机的切换页面上调整左右大小的预览大小?例如 - 如果片段失焦 - 它的比例将是 ~0.8,但是当我们将它拖到中心时 - 比例将增加到 1,并且当离开屏幕时,来自中心视图的前一个片段将比例更改为 0.8?
  • 这行得通!但是当我尝试缩放中心布局时,它会缩放到顶部和底部。由于填充,左右不可见。请看问题stackoverflow.com/questions/52710076/…
【解决方案2】:

使用新 ViewPager2 的解决方案

现在您应该考虑使用ViewPager2,它“取代了 ViewPager,解决了其前身的大部分痛点”

  • 基于 RecyclerView
  • 支持 RTL(从右到左)布局
  • 垂直方向支持
  • 可靠的 Fragment 支持(包括处理对底层 Fragment 集合的更改)
  • 数据集更改动画(包括DiffUtil 支持)

结果

代码

在您的 Activity/Fragment 中,设置 ViewPager2:

// MyRecyclerViewAdapter is an standard RecyclerView.Adapter :)
viewPager2.adapter = MyRecyclerViewAdapter() 

// You need to retain one page on each side so that the next and previous items are visible
viewPager2.offscreenPageLimit = 1

// Add a PageTransformer that translates the next and previous items horizontally
// towards the center of the screen, which makes them visible
val nextItemVisiblePx = resources.getDimension(R.dimen.viewpager_next_item_visible)
val currentItemHorizontalMarginPx = resources.getDimension(R.dimen.viewpager_current_item_horizontal_margin)
val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
val pageTransformer = ViewPager2.PageTransformer { page: View, position: Float ->
    page.translationX = -pageTranslationX * position
    // Next line scales the item's height. You can remove it if you don't want this effect
    page.scaleY = 1 - (0.25f * abs(position))
    // If you want a fading effect uncomment the next line:
    // page.alpha = 0.25f + (1 - abs(position))
}
viewPager2.setPageTransformer(pageTransformer)

// The ItemDecoration gives the current (centered) item horizontal margin so that
// it doesn't occupy the whole screen width. Without it the items overlap
val itemDecoration = HorizontalMarginItemDecoration(
    context,
    R.dimen.viewpager_current_item_horizontal_margin
)
viewPager2.addItemDecoration(itemDecoration)

添加HorizontalMarginItemDecoration,这是一个微不足道的ItemDecoration

/**
 * Adds margin to the left and right sides of the RecyclerView item.
 * Adapted from https://stackoverflow.com/a/27664023/4034572
 * @param horizontalMarginInDp the margin resource, in dp.
 */
class HorizontalMarginItemDecoration(context: Context, @DimenRes horizontalMarginInDp: Int) :
    RecyclerView.ItemDecoration() {

    private val horizontalMarginInPx: Int =
        context.resources.getDimension(horizontalMarginInDp).toInt()

    override fun getItemOffsets(
        outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
    ) {
        outRect.right = horizontalMarginInPx
        outRect.left = horizontalMarginInPx
    }

}

添加控制上一个/下一个项目的可见程度以及当前项目水平边距的尺寸:

<dimen name="viewpager_next_item_visible">26dp</dimen>
<dimen name="viewpager_current_item_horizontal_margin">42dp</dimen>

最后将ViewPager2 添加到您的布局中:

<androidx.viewpager2.widget.ViewPager2
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

一件重要的事情:ViewPager2 项目必须有 layout_height="match_parent"(否则它会引发 IllegalStateException),因此您应该执行以下操作:

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" <-- this!
    app:cardCornerRadius="8dp"
    app:cardUseCompatPadding="true">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="280dp">

        <!-- ... -->

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

PageTransformer 示例

Google 在 ViewPager2 上添加了一个指南,其中包含 2 个 PageTransformer 实现,您可以将其用作灵感:https://developer.android.com/training/animation/screen-slide-2

关于新的 ViewPager2

【讨论】:

  • 在 oreo 设备上存在同样的问题,填充开始和结束在其他设备上按预期工作,但在 ViewPager2 之后是 oreo。 PageTransformer 解决了这个问题,填充仍然相同,我必须添加 viewpager.setPageTransformer { page, position -&gt; page.translationX = -1 * position }
  • 我必须稍微移动视图寻呼机的页面才能获得这种效果
  • 没关系,我忘了添加这一行setOffscreenPageLimit(1) :)
  • 这是我找到的最好的解决方案。它工作得很好,但是不要忘记将 ViewPager2 的项目宽度、高度设置为 MATCH_PARENT。
  • @akubi 不幸的是我不能给你代码,因为它属于一家私人公司。但请注意,您在这里拥有所需的所有代码。
【解决方案3】:

@JijuInduchoodan 的答案是完美且有效的。但是,由于我对 Android 比较陌生,所以我花了一段时间来理解和正确设置它。因此,我发布此答案以供将来参考,并帮助与我处境相同的其他人。

if (viewPager == null) 
        {

            // Initializing view pager
            viewPager = (ViewPager) findViewById(R.id.vpLookBook);

            // Disable clip to padding
            viewPager.setClipToPadding(false);
            // set padding manually, the more you set the padding the more you see of prev & next page
            viewPager.setPadding(40, 0, 40, 0);
            // sets a margin b/w individual pages to ensure that there is a gap b/w them
            viewPager.setPageMargin(20);
        }

无需在适配器中为ViewPager's 页面设置任何宽度。在ViewPager 中查看上一页和下一页不需要额外的代码。但是,如果要在每个页面的顶部和底部添加空格,可以将以下代码设置为ViewPager's子页面的父布局。

android:paddingTop="20dp"
android:paddingBottom="20dp"

这将是 ViewPager 的最终外观。

【讨论】:

    【解决方案4】:

    在 2017 年,还可以通过使用 RecyclerViewPagerSnapHelper(在 v7 支持库的 25.1.0 版中添加)轻松实现此类行为: 

    前段时间我需要这种类似viewpager的功能并准备了一个小库:

    MetalRecyclerPagerView - 您可以在此处找到所有代码以及示例。

    主要由一个类文件组成:MetalRecyclerViewPager.java(和两个 xml:attrs.xmlids.xml)。

    希望它可以帮助某人并节省一些时间:)

    【讨论】:

    • 离题,因为有时只需要寻呼机,但很高兴知道!感谢分享!
    • 这太棒了。我已经有大量的 RecyclerView 帮助代码。只需添加一个简单的new PagerSnapHelper().attachToRecyclerView(recyclerView),我就会进行页面捕捉。
    【解决方案5】:

    您可以在 xml 文件中执行此操作,只需使用以下代码:

     android:clipToPadding="false"
     android:paddingLeft="XX"
     android:paddingRight="XX"
    

    例如:

    <androidx.viewpager.widget.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"
            android:paddingLeft="30dp"
            android:paddingRight="30dp" />
    

    注意:如果您需要页面之间的空间,请将填充/边距设置为子片段

    【讨论】:

    • 我投了反对票。兄弟抱歉。这次成功了!!再次点赞
    【解决方案6】:

    如果有人还在寻找解决方案,我已经自定义了 ViewPage 以在不使用负边距的情况下实现它,请在此处找到示例项目 https://github.com/44kksharma/Android-ViewPager-Carousel-UI 它应该在大多数情况下工作,但您仍然可以定义页边距 mPager.setPageMargin(margin in pixel);

    【讨论】:

      【解决方案7】:

      Kotlin + ViewPager2

      我迟到了,但上述答案对我不起作用。所以我来这里是为了帮助那些仍在寻找答案的人。

      1. 您的 XML:

             <androidx.viewpager2.widget.ViewPager2
             android:id="@+id/newsHomeViewPager"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
        
      2. 你的项目布局根视图应该是这样的:

             <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:paddingStart="@dimen/dp_10"
         xmlns:tools="http://schemas.android.com/tools"
         android:orientation="vertical" />
        
      3. 您的活动/片段:

      在设置 viewpager 适配器之前添加它

              newsHomeViewPager.apply {
              clipToPadding = false   // allow full width shown with padding
              clipChildren = false    // allow left/right item is not clipped
              offscreenPageLimit = 2  // make sure left/right item is rendered
          }
      
          //increase this offset to show more of left/right
          val offsetPx =
              resources.getDimension(R.dimen.dp_30).toInt().dpToPx(resources.displayMetrics)
          newsHomeViewPager.setPadding(0, 0, offsetPx, 0)
      
          //increase this offset to increase distance between 2 items
          val pageMarginPx =
              resources.getDimension(R.dimen.dp_5).toInt().dpToPx(resources.displayMetrics)
          val marginTransformer = MarginPageTransformer(pageMarginPx)
          newsHomeViewPager.setPageTransformer(marginTransformer)
      
      1. dp转像素函数:

        fun Int.dpToPx(displayMetrics: DisplayMetrics): Int = (this * displayMetrics.density).toInt()

      一般说明:

      1. 我只显示下一页,所以在setPadding 方法中,我为左保留了0,为右保留了offsetPx。因此,如果您也想显示右侧项目,请在 setPadding 方法中添加 offsetPx 到右侧。

      2. 我用过维度文件中的dp,你可以自己用。

      谢谢你,编码愉快。

      【讨论】:

        【解决方案8】:

        对于那些在不同屏幕上努力实现这一点的人,

        mPager.setClipToPadding(false);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        self.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        int paddingToSet = width/4; //set this ratio according to how much of the next and previos screen you want to show.
        mPager.setPadding(paddingToSet,0,paddingToSet,0);
        
        

        【讨论】:

          【解决方案9】:

          感谢this article的作者。这是我找到的最佳解决方案。

          只需创建一个函数,例如。在您的 Helpers 类中,例如:

          fun ViewPager2.showHorizontalPreview(offsetDpLeft : Int, offsetDpRight : Int, marginBtwItems : Int){
                  this.apply {
                      clipToPadding = false   // allow full width shown with padding
                      clipChildren = false    // allow left/right item is not clipped
                      offscreenPageLimit = 2  // make sure left/right item is rendered
                  }
          
                  // increase this offset to show more of left/right
                  val offsetPxLeft = offsetDpLeft.toPx()
                  val offsetPxRight = offsetDpRight.toPx()
                  this.setPadding(offsetPxLeft, 0, offsetPxRight, 0)
          
                  // increase this offset to increase distance between 2 items
                  val pageMarginPx = marginBtwItems.toPx()
                  val marginTransformer = MarginPageTransformer(pageMarginPx)
                  this.setPageTransformer(marginTransformer)
              }
          

          然后这样称呼它:

          mViewPager.showHorizontalPreview(40,40,5)
          

          在您的活动/片段中

          【讨论】:

            【解决方案10】:

            请注意,当给 viewpager 设置 none 零填充时,viewpager 的边缘效果位置会被弄乱,这是 viewpager 的一个错误,请参见此处:viewpager edgeeffect bug

            您可以通过将 android:overScrollMode="never" 设置为 viewpager 来禁用边缘效果,或者您可以使用 EdgeEffect 类的略微修改版本来修复错误:ViewPagerEdgeEffect fix

            【讨论】:

              【解决方案11】:
               override fun getPageWidth(position: Int): Float {
                  return 0.7f
              }
              

              在适配器类文件中添加这个,这对我有用

              【讨论】:

                【解决方案12】:

                根据 Jiju 的回答,如果您想为 VIEWPAGER 2 设置页间距,请使用如下代码:

                viewpager.setPageTransformer(new MarginPageTransformer(14));
                

                【讨论】:

                  【解决方案13】:

                  在 XML 文件中,您应该像这样设置填充:

                  在片段中:

                  int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20*2,     getResources().getDisplayMetrics());
                  

                  要全部设置好,请使用此

                  myViewPager.setPageMargin(-margin);
                  

                  应该做的伎俩:)

                  【讨论】:

                    【解决方案14】:

                    使用这个片段适配器和类在左右滚动中查看viewpager。添加必要的类来滚动查看下一页。

                    package com.rmn.viewpager;
                    
                    import java.util.List;
                    
                    import android.support.v4.app.Fragment;
                    import android.support.v4.app.FragmentManager;
                    import android.support.v4.app.FragmentPagerAdapter;
                    
                    /**
                     * The <code>PagerAdapter</code> serves the fragments when paging.
                     * @author mwho
                     */
                    public class PagerAdapter extends FragmentPagerAdapter {
                    
                        private List<Fragment> fragments;
                        /**
                         * @param fm
                         * @param fragments
                         */
                        public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
                            super(fm);
                            this.fragments = fragments;
                        }
                        /* (non-Javadoc)
                         * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
                         */
                        @Override
                        public Fragment getItem(int position) {
                            return this.fragments.get(position);
                        }
                    
                        /* (non-Javadoc)
                         * @see android.support.v4.view.PagerAdapter#getCount()
                         */
                        @Override
                        public int getCount() {
                            return this.fragments.size();
                        }
                    }
                    
                    
                    
                    package com.manishkpr.viewpager;
                    
                    
                    import android.content.Context;
                    import android.support.v4.app.Fragment;
                    import android.support.v4.app.FragmentManager;
                    import android.support.v4.app.FragmentPagerAdapter;
                    
                    public class ViewPagerAdapter extends FragmentPagerAdapter {
                        private Context _context;
                    
                        public ViewPagerAdapter(Context context, FragmentManager fm) {
                            super(fm);  
                            _context=context;
                    
                            }
                        @Override
                        public Fragment getItem(int position) {
                            Fragment f = new Fragment();
                            switch(position){
                            case 0:
                                f=LayoutOne.newInstance(_context);  
                                break;
                            case 1:
                                f=LayoutTwo.newInstance(_context);  
                                break;
                            }
                            return f;
                        }
                        @Override
                        public int getCount() {
                            return 2;
                        }
                    
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多