141

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

setPageMargin(-100);

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

4

14 回答 14

216

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

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

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

viewpager.setPageMargin(int);
于 2014-04-29T05:14:23.303 回答
162

使用新 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

于 2019-09-24T21:30:55.143 回答
81

@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 的最终外观。

于 2015-12-11T06:52:12.073 回答
29

RecyclerView在 2017 年,通过使用PagerSnapHelper(在 v7 支持库的 25.1.0 版中添加) 可以轻松实现这种行为:</p>

在此处输入图像描述

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

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

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

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

于 2017-08-09T19:37:42.757 回答
15

您可以在 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" />

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

于 2019-05-28T06:06:41.630 回答
9

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

于 2018-02-23T11:37:58.480 回答
8

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方法中,我为左和offsetPx右保留了 0。因此,如果您也想显示右侧项目,offsetPx也可以在方法中添加到右侧。setPadding

  2. 我已经使用了维度文件中的 dp,您可以使用自己的。

谢谢你,快乐的编码。

于 2021-07-24T14:27:05.223 回答
4

对于那些努力在不同屏幕上拥有它的人来说,

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

于 2019-02-07T07:28:33.210 回答
1

感谢这篇文章的作者。这是我找到的最好的解决方案。

只需创建一个函数,例如。在您的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)

在您的活动/片段中

于 2021-12-16T09:50:29.743 回答
0

请注意,当为 viewpager 设置 none 零填充时,viewpager 的边缘效果放置会被搞砸,这是 viewpager 的错误,请参见此处:viewpager edgeeffect bug

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

于 2019-06-21T08:33:59.837 回答
0

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

viewpager.setPageTransformer(new MarginPageTransformer(14));
于 2021-07-16T04:05:57.663 回答
0
 override fun getPageWidth(position: Int): Float {
    return 0.7f
}

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

于 2020-09-11T15:01:36.223 回答
0

在 XML 文件中,您应该像这样设置填充: 在此处输入图像描述

在片段中:

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

并设置好,使用这个

myViewPager.setPageMargin(-margin);

应该做的伎俩:)

于 2021-11-04T19:11:22.893 回答
-12

使用此片段适配器和类在左右滚动中查看 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;
    }

}
于 2012-11-05T07:12:18.520 回答