我正在使用安卓的ViewPager
。我的需求是在左右两边都显示页面的预览。我已经发现可以使用负数的pageMargin
来实现右侧预览的效果。
setPageMargin(-100);
有没有办法也显示左侧的预览?我正在寻找类似于相册小部件的东西。
我正在使用安卓的ViewPager
。我的需求是在左右两边都显示页面的预览。我已经发现可以使用负数的pageMargin
来实现右侧预览的效果。
setPageMargin(-100);
有没有办法也显示左侧的预览?我正在寻找类似于相册小部件的东西。
若要显示左右页面预览,请设置以下两个值:
viewpager.setClipToPadding(false);
viewpager.setPadding(left,0,right,0);
如果需要在视图页之间添加间距,则需添加:
viewpager.setPageMargin(int);
现在,您应该考虑使用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://dev59.com/KGAf5IYBdhLWcg3wdCl1#27664023
* @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>
Google在ViewPager2上添加了一个指南,其中包含两个PageTransformer
实现,可以用作灵感来源:https://developer.android.com/training/animation/screen-slide-2
setOffscreenPageLimit(1)
:) - Muhammad Saqib更新:ViewPager 2.0
请使用以下内容
viewPager2.setPageTransformer(new MarginPageTransformer(1500));
另请参见,Android ViewPager2 setPageMargin unresolved
旧回答
@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
页面的任何宽度。没有额外的代码需要在ViewPager
中查看前一页和后一页。然而,如果您想在每个页面的顶部和底部添加空白间隔,您可以将以下代码设置为ViewPager
子页面的父布局。
android:paddingTop="20dp"
android:paddingBottom="20dp"
这将是ViewPager的最终外观。
viewPager.setPageMargin(20);
。 - Mahmoud Mabrok在2017年,可以通过使用带有PagerSnapHelper的RecyclerView
(添加在v7支持库的25.1.0版本中)轻松实现此类行为:
不久前,我需要这样的viewpager-like功能,并准备了一个小型库:
MetalRecyclerPagerView - 您可以在那里找到所有代码和示例。
主要由单个类文件组成:MetalRecyclerViewPager.java(以及两个xml:attrs.xml和ids.xml)。
希望它能帮助某些人并节省一些时间 :)
new PagerSnapHelper().attachToRecyclerView(recyclerView)
,我就可以实现页面捕捉了。 - Steve
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" />
注意:如果您需要在页面之间添加间距,请将内边距/外边距设置为子片段。Kotlin + ViewPager2
我晚了一步,但是上面的答案对我没用。所以我来帮助其他仍在寻找答案的人。
您的XML:
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/newsHomeViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
您的item布局根视图应该像这样:
<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" />
您的 Activity/Fragment:
在设置您的 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)
将dp转为像素的函数:
fun Int.dpToPx(displayMetrics: DisplayMetrics): Int = (this * displayMetrics.density).toInt()
通用注释:
我只需要显示下一页,所以在setPadding
方法中,左侧保持0,右侧保持offsetPx
。如果您想要显示右侧的项目,请在setPadding
方法中也将offsetPx
添加到右侧。
我使用了维度文件中的dp,您可以使用自己的。
谢谢,愉快编码。
mPager.setPageMargin(像素间距);
来定义页面间距。
Single Line Implementation in your Activity or Fragment.
binding.viewpager2.setPreviewBothSide(R.dimen._20sdp,R.dimen._35sdp)
Add Below Code in HorizontalMarginItemDecoration.kt
file in your Project
import android.content.Context
import android.graphics.Rect
import android.view.View
import androidx.annotation.DimenRes
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
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
}
}
fun ViewPager2.setPreviewBothSide(@DimenRes nextItemVisibleSize: Int,@DimenRes currentItemHorizontalMargin: Int) {
this.offscreenPageLimit = 1
val nextItemVisiblePx = resources.getDimension(nextItemVisibleSize)
val currentItemHorizontalMarginPx = resources.getDimension(currentItemHorizontalMargin)
val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
val pageTransformer = ViewPager2.PageTransformer { page: View, position: Float ->
page.translationX = -pageTranslationX * position
page.scaleY = 1 - (0.25f * kotlin.math.abs(position))
}
this.setPageTransformer(pageTransformer)
val itemDecoration = HorizontalMarginItemDecoration(
context,
currentItemHorizontalMargin
)
this.addItemDecoration(itemDecoration)
}
And Yes Here you got this Amazing Output
这是对Albert Vila Calvo的答案进行优化后的版本。
对于那些在不同屏幕上使用此功能有困难的人,
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);
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)
setPageMargin(-100)
能正常工作吗? - MacarseViewPager2
实现,请查看此答案 https://dev59.com/olMH5IYBdhLWcg3w1TuK#58056129 - AskNilesh