ViewPager2是ViewPager的升级版。ViewPager2是基于RecyclerView实现的,在解决了很多使用ViewPager时遇到的问题的同时,还加入自己的一些新特性。下面我们来介绍他的使用。
一:ViewPager2使用
1.1 添加依赖
在app的build.gradle里添加如下依赖
dependencies {
implementation "androidx.viewpager2:viewpager2:1.0.0"
}
1.2 ViewPager2布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="300dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
1.3 ViewPager2的Adapter
因为ViewPager2是基于RecyclerView的,所以它使用的Adapter也是RecyclerView的Adapter。所以自定义一个叫MyAdapter的来作为ViewPager2的Adapter
class MyAdapter :RecyclerView.Adapter<MyAdapter.MHolder>(){
private var mColorsList = ArrayList<Int>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_page,parent,false)
return MHolder(itemView)
}
override fun onBindViewHolder(holder: MHolder, position: Int) {
holder.view.setBackgroundColor(mColorsList[position])
}
override fun getItemCount(): Int {
return mColorsList.size
}
fun setData(colors:List<Int>){
mColorsList.clear()
if(colors?.isNotEmpty()){
mColorsList.addAll(colors)
}
notifyDataSetChanged()
}
class MHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val view = itemView.findViewById<View>(R.id.view_item)
}
}
item_page.xml的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<View
android:id="@+id/view_item"
android:background="@color/colorAccent"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
根据传入的不同的颜色值去设置View的背景。
1.4 ViewPager2的绑定Adapter
class ViewPager2TestActivity :AppCompatActivity(){
private val list = arrayListOf<Int>(Color.RED,Color.YELLOW,Color.BLUE,Color.GREEN)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_viewpager2test)
val adapter = MyAdapter()
adapter.setData(list)
view_pager.adapter = adapter
}
}
这样简单的ViewPager2的使用就完成了。
1.5 ViewPager2支持竖直方向
除了传统的水平分页之外,ViewPager2 还支持垂直分页。您可以通过设置 ViewPager2 元素的 android:orientation 属性为其启用垂直分页:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:orientation="vertical" />
您还可以使用 setOrientation() 方法,以编程方式设置此属性。
view_pager.orientation = ViewPager2.ORIENTATION_VERTICAL
1.6 ViewPager2支持从右到左
ViewPager2 支持从右到左 (RTL) 分页。系统会根据语言区域在适当的情况下自动启用 RTL 分页,不过您也可以通过设置 ViewPager2 元素的 android:layoutDirection 属性为其手动启用 RTL 分页:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layoutDirection="rtl" />
您还可以使用 setLayoutDirection() 方法,以编程方式设置此属性。
view_pager.layoutDirection = LayoutDirection.RTL
1.7 ViewPager2滑动监听
view_pager.registerOnPageChangeCallback(object :ViewPager2.OnPageChangeCallback(){
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
Toast.makeText(this@ViewPager2TestActivity, "ccm== $position", Toast.LENGTH_SHORT).show()
}
})
1.8 setUserInputEnabled禁止滑动
在使用ViewPager的时候想要禁止用户滑动需要重写ViewPager的onInterceptTouchEvent。而ViewPager2,我们可以直接通过setUserInputEnabled为false禁止滑动
view_pager.isUserInputEnabled = false
1.9 setCurrentItem
切换到某个位置下,跟ViewPager一样,ViewPager2也是通过setCurrentItem设置。
view_pager.currentItem = 1
1.10 fakeDragBy
ViewPager2新增了一个fakeDragBy的方法,我们可以通过fakeDragBy来移动,fakeDragBy(-10),负数是说明向下一个页面,正数表示向前一个页面滑动,但使用fakeDragBy前需要先调用beginFakeDrag方法才能生效。可以使用endFakeDrag停止
btn_fake.setOnClickListener {
view_pager.beginFakeDrag()
view_pager.fakeDragBy(-500f)
}
btn_fake.setOnClickListener {
view_pager.beginFakeDrag()
if(view_pager.fakeDragBy(-310f)) view_pager.endFakeDrag()
}
1.11 ViewPager2的offScreenPageLimit
offScreenPageLimit在ViewPager中就已经存在,这个参数用来控制ViewPager左右两端预加载页面的个数。为了保证ViewPager的流畅性,offScreenPageLimit被强制规定为大于0的数,即使我们将其设置为0,ViewPager内部也会将其改为1。因此ViewPager就被强制左右两边至少加载一个页面。而在ViewPager2中针对这一问题做了优化。我们点开ViewPager2的源码来看下:
...
public static final int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1;
private @OffscreenPageLimit int mOffscreenPageLimit = OFFSCREEN_PAGE_LIMIT_DEFAULT;
/** @hide */
@SuppressWarnings("WeakerAccess")
@RestrictTo(LIBRARY_GROUP_PREFIX)
@Retention(SOURCE)
@IntDef({OFFSCREEN_PAGE_LIMIT_DEFAULT})
@IntRange(from = 1)
public @interface OffscreenPageLimit {}
public void setOffscreenPageLimit(@OffscreenPageLimit int limit) {
if (limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT) {
throw new IllegalArgumentException(
"Offscreen page limit must be OFFSCREEN_PAGE_LIMIT_DEFAULT or a number > 0");
}
mOffscreenPageLimit = limit;
// Trigger layout so prefetch happens through getExtraLayoutSize()
mRecyclerView.requestLayout();
}
我们发现ViewPager2中offScreenPageLimit的默认值被设置为了-1,而当offScreenPageLimit为-1的时候,使用的是RecyclerView的缓存机制。而当offScreenPageLimit大于1时,才会去实现预加载。 以前我们想要去实现ViewPager只初始化一个Fragment的时候,根据Fragment的生命周期去写了很多的代码去实现懒加载。现在使用ViewPager2不需要了,只要把offScreenPageLimit设置成-1就可以了。ViewPager2就会去使用RecyclerView的缓存机制了。
二:ViewPager2的PageTransformer
ViewPager2的Transformer功能有了很大的扩展。ViewPager2不仅可以通过PageTransformer用来设置页面动画,还可以用PageTransformer设置页面间距以及同时添加多个PageTransformer。
2.1:ViewPager2的给页面设置间距
ViewPager2中可以通过setPageTransformer给页面之间设置间距
view_pager.setPageTransformer(MarginPageTransformer(30))
2.2:ViewPager2的给页面之间设置跳转动画
先自定义一个ScaleInTransformer去实现ViewPager2.PageTransformer
class ScaleInTransformer :ViewPager2.PageTransformer{
private val minScale = 0.85f
private val centerF = 0.5f
override fun transformPage(page: View, position: Float) {
page.elevation = -abs(position)
val pageW = page.width
val pageH = page.height
page.pivotY = pageH/2f
page.pivotX = pageW/2f
if(position<-1){
page.scaleX = minScale
page.scaleY = minScale
page.pivotX = pageW.toFloat()
}else if(position<=1){
if (position < 0) {
val scaleFactor = (1 + position) * (1 - minScale) + minScale
page.scaleX = scaleFactor
page.scaleY = scaleFactor
page.pivotX = pageW * (centerF + centerF * -position)
} else {
val scaleFactor = (1 - position) * (1 - minScale) + minScale
page.scaleX = scaleFactor
page.scaleY = scaleFactor
page.pivotX = pageW * ((1 - position) * centerF)
}
}else{
page.scaleX = minScale
page.scaleY = minScale
page.pivotX = 0f
}
}
}
上面定义了一个缩放的动画,把他作为页面切换的时候的动画。再通过CompositePageTransformer的addTransformer方法添加页面切换动画,代码如下:
val compositePageTransformer = CompositePageTransformer()
compositePageTransformer.addTransformer(ScaleInTransformer())
compositePageTransformer.addTransformer(MarginPageTransformer(40))
view_pager.setPageTransformer(compositePageTransformer)
2.3:ViewPager2实现跨屏的效果
为了实现扩屏的效果,我们可以通过padding来实现。给ViewPager2里的RecyclerView设置Padding
view_pager.apply {
offscreenPageLimit = 1
val recyclerView = getChildAt(0) as RecyclerView
recyclerView.apply {
val padding = resources.getDimensionPixelOffset(R.dimen.dp_20)
setPadding(padding,0,padding,0)
clipToPadding = false
}
}
val compositePageTransformer = CompositePageTransformer()
compositePageTransformer.addTransformer(ScaleInTransformer())
compositePageTransformer.addTransformer(MarginPageTransformer(40))
view_pager.setPageTransformer(compositePageTransformer)
三:ViewPager2跟Fragment的配合使用
ViewPager2中新增的FragmentStateAdapter 替代了ViewPager的FragmentStatePagerAdapter跟FragmentPagerAdapter
3.1:实现FragmentStateAdapter
class HomeAdapterTest(activity: FragmentActivity) : FragmentStateAdapter(activity) {
companion object {
const val HOME_COUNT = 3
const val PAGE_ONE = 0
const val PAGE_TWO = 1
const val PAGE_THREE = 2
}
override fun createFragment(position: Int): Fragment {
return when (position) {
PAGE_ONE -> {
FragmentTest1()
}
PAGE_TWO -> {
FragmentTest2()
}
PAGE_THREE -> {
FragmentTest3()
}
else -> FragmentTest1()
}
}
override fun getItemCount(): Int {
return HOME_COUNT
}
}
3.2:Activity中的ViewPager2
布局文件的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="@+id/btn_one"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_one"
android:layout_width="0dp"
android:layout_height="50dp"
app:layout_constrainedWidth="true"
android:text="切换到一"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn_two"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/btn_two"
android:layout_width="0dp"
android:layout_height="50dp"
android:text="切换到二"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn_three"
app:layout_constraintStart_toEndOf="@+id/btn_one" />
<Button
android:id="@+id/btn_three"
android:layout_width="0dp"
android:layout_height="50dp"
android:text="切换到三"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/btn_two" />
</androidx.constraintlayout.widget.ConstraintLayout>
布局文件中存在一个ViewPager2和三个按钮,三个按钮点击分别可以切换到三个Fragment,Activity里的代码如下。
class ViewPagerFragmentActivity :AppCompatActivity(),View.OnClickListener{
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_viewpager2fragment)
btn_one.setOnClickListener(this)
btn_two.setOnClickListener(this)
btn_three.setOnClickListener(this)
view_pager.adapter = HomeAdapterTest(this)
view_pager.isUserInputEnabled = false
}
override fun onClick(v: View?) {
when(v){
btn_one->view_pager.setCurrentItem(0,false)
btn_two->view_pager.setCurrentItem(1,false)
btn_three->view_pager.setCurrentItem(2,false)
}
}
}
- view_pager.isUserInputEnabled = false设置ViewPager2为不可滑动
- view_pager.adapter = HomeAdapterTest(this) 设置ViewPager2的Adapter为HomeAdapterTest
- view_pager.setCurrentItem(0,false) 按钮监听事件里切换viewPager2的内容
四:ViewPager2跟TabLayout的配合使用
由于需要使用到类TabLayoutMediator,所以需要在app的build.gradle 文件中添加如下的依赖:
implementation "com.google.android.material:material:1.1.0-beta01"
布局文件中的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tab_layout" />
</androidx.constraintlayout.widget.ConstraintLayout>
对应的Activity的代码
view_pager.adapter = HomeAdapterTest(this)
view_pager.isUserInputEnabled = false
TabLayoutMediator(tab_layout,view_pager){
tab, position ->
tab.text = "Tab ${(position+1)}"
}.attach()
今天的文章ViewPager2使用详解分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/14932.html