由潜入深使用viewPage2
概述
viewPage2是由Google在2011发布用于替代viewPage的新控件.该控件运行在水平或者垂直滑动在当前屏幕进行导航,大多用于轮播图或者导航切换
简单的图片切换
- 新建项目
MysViewPage2
- 下载资源,移动到
res/drawable
文件夹下. - 修改
activity_main.xml
文件,代码如下:这1
2
3
4
5
6
7
8
9
10<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>activity_main.xml
文件中,只创建了一个ViewPager2控件用于显示切换的视图且为其id名为viewpager2
. - 新建需要被切换的视图(轮播图)的布局
item.xml
这里仅仅创建了一个1
2
3
4
5
6
7
8
9
10<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>ImageView
用于代表一个被切换的视图. 新建适配器文件
MyViewPage2Adapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 可以继承的适配器不止RecyclerView
class MyViewPage2Adapter(private val imageList: ArrayList<Int>) : RecyclerView.Adapter<MyViewPage2Adapter.ViewHolder>(){
inner class ViewHolder(val view:View) : RecyclerView.ViewHolder(view) {
// 将imageView放入Holder
val imageView: ImageView = view.findViewById(R.id.image)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// 加载被切换的布局
val view = LayoutInflater.from(parent.context).inflate(R.layout.item,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// 设置当前视图图片ID
holder.imageView.setImageResource(imageList[position])
}
override fun getItemCount(): Int = imageList.size
}viewPage2
不能继承viewPage
,除了继承RecyclerView,FragmentStateAdapter等.可以前往官方文档查看更多连接适配器,修改
MainActivity.kt
,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class MainActivity : AppCompatActivity() {
private val datas = ArrayList<Int>().apply {
add(R.drawable.tx1)
add(R.drawable.tx2)
add(R.drawable.tx3)
add(R.drawable.tx4)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val viewPage2 = findViewById<ViewPager2>(R.id.viewpager2)
val myViewPage2Adapter = MyViewPage2Adapter(datas)
viewPage2.adapter = myViewPage2Adapter
}
}代码非常简单,就是找到控件,加载适配器再载入数据.
- 效果图
给ViewPage2加上循环滚动
- 在上面的基础上修改
MyViewPage2Adapter.kt
,代码如下:\1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class MyViewPage2Adapter(private val imageList: ArrayList<Int>) : RecyclerView.Adapter<MyViewPage2Adapter.ViewHolder>(){
inner class ViewHolder(val view:View) : RecyclerView.ViewHolder(view) {
val imageView: ImageView = view.findViewById(R.id.image)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// 通过取余,一直循环
val i = position % imageList.size
holder.imageView.setImageResource(imageList[i])
}
// 设置一个超级大的数(2147483647),达成理论无限滚动
override fun getItemCount(): Int = Int.MAX_VALUE
} - 效果图
给ViewPage2加上自动滚动
前面的代码都只能手动滚动,为了实现自动滚动需要借助循环器Handler
来在后台自动切换下一张.不建议使用协程,因为协程不被允许修改主线程ui.
- 循环器,修改
MainActivity.kt
文件,代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40class MainActivity : AppCompatActivity() {
// 在主线程创建循环器
private var mHandler = Handler(Looper.getMainLooper())
private lateinit var viewPage2:ViewPager2
private val datas = ArrayList<Int>().apply {
add(R.drawable.tx1)
add(R.drawable.tx2)
add(R.drawable.tx3)
add(R.drawable.tx4)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewPage2 = findViewById<ViewPager2>(R.id.viewpager2)
val myViewPage2Adapter = MyViewPage2Adapter(datas)
viewPage2.adapter = myViewPage2Adapter
}
// 软件启动时回调
override fun onResume(){
super.onResume()
mHandler.postDelayed(runnable,500)
}
// 退出时移除循环器
override fun onPause() {
super.onPause()
mHandler.removeCallbacks(runnable)
}
private val runnable: java.lang.Runnable = object : java.lang.Runnable {
override fun run() {
//获得轮播图当前的位置
var currentPosition = viewPage2.currentItem
currentPosition++
viewPage2.setCurrentItem(currentPosition, true)
mHandler.postDelayed(this, 5000)
}
}
}
给轮播图加上指示器(小白点)
- 在
res/drawable/
文件夹下面新增文件shape_dot.xml
文件,代码如下1
2
3
4
5
6
7
8
9
10<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size
android:width="8dp"
android:height="8dp"/>
<corners
android:radius="8dp"/>
<solid
android:color="#00ccff"/>
</shape> - 在
res/drawable/
文件夹下面新增文件shape_dot_selected.xml
文件,代码如下1
2
3
4
5
6
7
8
9
10<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size
android:width="8dp"
android:height="8dp"/>
<corners
android:radius="8dp"/>
<solid
android:color="#ffffff"/>
</shape> - 在
activity_main.xml
新增放置指示器的布局,重写布局.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<?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="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- 为指示器准备的布局-->
<LinearLayout
android:gravity="center"
android:id="@+id/container_indicator"
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="20dp"
android:orientation="horizontal" />
</FrameLayout> - 修改
MainActivity.kt
,代码如下:在这里主要新建了选中和未选中两个指示器的xml,文件.然后在MainActivity中在onCreate生命周期时将指示器的初始图片赋值,然后注册了一个Page切换的回调函数,用于修改指示器的背景图片.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
private lateinit var initIndicatorDots: LinearLayout
// 在主线程创建循环器
private var mHandler = Handler(Looper.getMainLooper())
private lateinit var viewPage2: ViewPager2
private val datas = ArrayList<Int>().apply {
add(R.drawable.tx1)
add(R.drawable.tx2)
add(R.drawable.tx3)
add(R.drawable.tx4)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewPage2 = findViewById(R.id.viewpager2)
val myViewPage2Adapter = MyViewPage2Adapter(datas)
viewPage2.adapter = myViewPage2Adapter
// 初始化指示器父布局
initIndicatorDots = findViewById(R.id.container_indicator)
viewPage2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
// 上一个图片索引
private var lastPosition = 0
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
//轮播时,改变指示点
val current = position % 4
val last = lastPosition % 4
initIndicatorDots.getChildAt(current).setBackgroundResource(R.drawable.shape_dot_selected)
initIndicatorDots.getChildAt(last).setBackgroundResource(R.drawable.shape_dot)
// 将本次图片索引更新到上一个图片索引
lastPosition = position
}
})
initIndicatorDots()
}
// 软件启动时回调
override fun onResume() {
super.onResume()
mHandler.postDelayed(runnable, 500)
}
// 退出时移除循环器
override fun onPause() {
super.onPause()
mHandler.removeCallbacks(runnable)
}
private fun initIndicatorDots() {
Log.d(TAG, "初始化完成")
// 循环数据长度
for (i in datas.indices) {
// 实例化一个viewImage控件对象
val imageView = ImageView(this)
// 初始启动,除了第0个,其它都是未选择状态
if (i == 0) imageView.setBackgroundResource(R.drawable.shape_dot_selected)
else imageView.setBackgroundResource(R.drawable.shape_dot)
// 为指示器设置宽高
val layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
// 指示器间距
layoutParams.marginEnd = 20
imageView.layoutParams = layoutParams
initIndicatorDots.addView(imageView)
}
}
private val runnable: java.lang.Runnable = object : java.lang.Runnable {
override fun run() {
//获得轮播图当前的位置
var currentPosition = viewPage2.currentItem
currentPosition++
viewPage2.setCurrentItem(currentPosition, true)
mHandler.postDelayed(this, 5000)
}
}
} - 效果图
本篇代码
由潜入深使用viewPage2
https://007666.xyz/2022/10/17/由潜入深使用viewPage2/