RecyclerView,一个强大的控件,既支持纵向滚动,又支持横向滚动。 应用场景非常广泛,简单说ListView可以做的它可以做,ListView不支持的横向它也可以做。

Recyclerview使用

对于其不仅可以实现和ListView同样的效果

本文主要是一个RecyclerView的开篇,主要针对RecyclerView空间的使用。至于RecyclerView的观察者模式和缓冲机制,后续会在源码分析持续更新。

RecyclerView的使用说明

笔者对于RecyclerView的记忆主要是一个口诀,一类继承,四个方法。

对于口诀使用的类就是Adapter

1)一类继承

里面MyViewHolder继承 RecyclerView.ViewHolder,并实现RecyclerView.ViewHolder的构造,一般用于findviewbyid绑定控件

而MyAdapter继承RecyclerView.Adpter<MyAdapter.MyViewHolder>

2)四个方法

一个构造

一般为有参构造,用于传递参数进来,初始化控件信息

举例MyAdapter(List< SettingItem > list)

三个继承

1)通过viewType来实现加载不同的布局

public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)

2)将数据和控件绑定,会在每个子项被滚动到屏幕内时执行,position从0开始

public void onBindViewHolder(ViewHolder holder, int position)

3)多少个item数

public int getItemCount()

3)外部使用

设置完成之后,在Activity的使用也很简单,如下所示外部设置

1)RecyclerView获取他的对象 RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);

2)LayoutManager用于指定RecyclerView的布局方式,设置layoutManager 的展示方式设置为竖直方向 LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager .setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager);

3)设置适配器 MyAdapter adapter = new MyAdapter(fruitList); recyclerView.setAdapter(adapter);

RecyclerView的demo

1)settings

效果图如下

settings效果图 settings效果图

拆解demo

首先是Adapter

 1//构造内部类,并使用kotlin的构造函数,继承内部Holder类
 2private inner class SimpleAdapter constructor(list :List<SettingItem>) : RecyclerView.Adapter<SimpleAdapter.Holder>() {
 3        private var mSettingItem: List<SettingItem>? = null
 4        //*一个继承* Holder继承RecyclerView.ViewHolder,并且初始化构造
 5        inner class Holder(itemView: View) : RecyclerView.ViewHolder(itemView){
 6            var textView : TextView? = null
 7            var imageView : ImageView? = null
 8
 9            //Hoder构造器初始化
10            init {
11                textView = itemView.findViewById(R.id.settingname)
12                imageView = itemView.findViewById(R.id.settinginfo)
13                imageView?.setOnClickListener(View.OnClickListener {
14                    Log.d(TAG, "->onclicked imageview")
15                    //可以直接通过getposition获取到postion的值
16                    Toast.makeText(context!!, "onclicked imageview pos = $position", Toast.LENGTH_LONG).show()
17                })
18                itemView?.setOnClickListener(View.OnClickListener {
19                    Log.d(TAG, "->onclicked item")
20                    Toast.makeText(context!!, "onclicked item pos = $position", Toast.LENGTH_LONG).show()
21                })
22            }
23
24        }
25        //*一个构造*SimpleAdapter构造器初始化,将list传递进来
26        init {
27            mSettingItem = list
28        }
29        //*三个方法*加载唯一布局
30        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
31            var view: View = LayoutInflater.from(parent.context).inflate(R.layout.item_settings, parent, false)
32            var viewHolder: Holder = Holder(view)
33            return viewHolder
34        }
35        //*三个方法*将数据和控件绑定,数据来源于SimpleAdapter构造器
36        override fun onBindViewHolder(holder: Holder, position: Int) {
37            var settingItem = mSettingItem?.get(position)
38            holder.textView?.text = settingItem?.getName()
39            settingItem?.getInfo()?.let { holder.imageView?.setImageResource(it) }
40
41        }
42        //*三个方法*设置多少个item数为list长度
43        override fun getItemCount(): Int {
44            return mSettingItem?.let { it.size } ?: run { 0 }
45        }
46    }

接着拆解外部使用

1//1)RecyclerView获取他的对象
2recyclerView = findViewById(R.id.moresettings)
3//2)LayoutManager用于指定RecyclerView的布局方式,展示方式设置为竖直方向
4var ll: LinearLayoutManager = LinearLayoutManager(this)
5ll.orientation = LinearLayoutManager.VERTICAL
6recyclerView?.layoutManager = ll
7//3)设置适配器
8recyclerView?.adapter = SimpleAdapter(mList)

拆解之后就感觉使用会很简单

2)wifiSettings

效果图如下

wifiSettings效果图 wifiSettings效果图

拆解demo

首先是Adapter

 1//构造内部类,并使用kotlin的构造函数,具体的逻辑代码省略部分,因为此demo有多个viewholder,所以不继承使用父类即可
 2private inner class WifiAdapter internal constructor(context: Context) :
 3        RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 4        private val inflater: LayoutInflater = LayoutInflater.from(context)
 5        //*三个方法*增加一个方法来判断viewholder类型,总共有itemCount个item
 6        //范围从0---itemCount-1,其中下标为0,表示为viewType为2
 7        //下标为1---itemCount-2表示viewType为1
 8        //下标为其他itemCount-1表示viewType为0
 9        override fun getItemViewType(position: Int): Int {
10            return when (position) {
11                0 -> 2
12                itemCount - 1 -> 1
13                else -> 0
14            }
15        }
16        //*三个方法*加载布局,这里默认有三个布局,根据上面的getItemViewType的返回值viewtype来判断
17        //viewType为0 ,布局就是数据布局,这里代表wifi
18        //viewType为1 ,布局就是数据布局的下面布局,这里代表手动添加wifi
19        //viewType为2 ,布局就是数据布局的上面布局,这里代表关闭/打开wifi
20        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
21            return when (viewType) {
22                0 ->
23                    ItemViewHolder(inflater.inflate(R.layout.item_access_point_2, parent, false))
24                1 ->
25                    ManualViewHolder(
26                        inflater.inflate(
27                            R.layout.item_access_point_manual,
28                            parent,
29                            false
30                        )
31                    )
32                2 -> {
33                    val holder = WifiSwitchViewHolder(
34                        inflater.inflate(
35                            R.layout.item_wifi_switch,
36                            parent,
37                            false
38                        )
39                    )
40                    ...
41                }
42                else ->
43                    ItemViewHolder(inflater.inflate(R.layout.item_access_point_2, parent, false))
44            }
45        }
46        //*三个方法*将数据和控件绑定,数据来源于scans
47        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
48            if (holder is ItemViewHolder) {
49                scans?.get(position - 1)?.let { scan ->
50                    holder.bind(scan)
51                }
52            }
53        }
54        //*三个方法*设置多少个item数,wifi打开为scans.size + 2,wifi关闭为1
55        override fun getItemCount(): Int {
56            val isWifiEnabled = wifiSwitch?.isChecked == true
57            return if (isWifiEnabled) (scans?.size ?: 0) + 2 else 1
58        }
59        //*一个继承* ManualViewHolder继承RecyclerView.ViewHolder,并且初始化构造
60        internal inner class ManualViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
61            init {
62                itemView.setOnClickListener {
63                    handleAddManual()
64                }
65            }
66        }
67        //*一个继承* WifiSwitchViewHolder继承RecyclerView.ViewHolder
68        internal inner class WifiSwitchViewHolder(itemView: View) :
69            RecyclerView.ViewHolder(itemView)
70        //*一个继承* ItemViewHolder继承RecyclerView.ViewHolder,并且初始化构造
71        internal inner class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
72            private val icon: ImageView = itemView.findViewById(R.id.icon)
73            private val ssid: TextView = itemView.findViewById(R.id.ssid)
74            private val status: TextView = itemView.findViewById(R.id.status)
75            private val info: ImageView = itemView.findViewById(R.id.info)
76
77            init {
78                itemView.setOnClickListener { handleOnItemClick(scans!![this@ItemViewHolder.layoutPosition - 1]) }
79                info.setOnClickListener { handleOpenWifiInfo(scans!![this@ItemViewHolder.layoutPosition - 1]) }
80            }
81        }
82    }

接着拆解外部使用

 1private var adapter: WifiAdapter? = nul 
 2adapter = context?.let { WifiAdapter(it) }
 3//1)RecyclerView获取他的对象
 4val list =findViewById<RecyclerView>(R.id.wifi_list)
 5//2)设置展示方式,这里将item之间添加横线,默认方向为竖向
 6list.addItemDecoration(
 7    DividerItemDecoration.Builder(list.context)
 8    .setPadding(resources.getDimensionPixelSize(R.dimen.dp_40))
 9    .setDividerColor(ContextCompat.getColor(list.context, R.color.dividerLight))
10    .setDividerWidth(resources.getDimensionPixelSize(R.dimen.dp_1))
11    .build()
12)
13//4)设置适配器
14list.adapter = adapter

整理wifisettings.kt

主要流程如下

1.布局加载

2.数据加载

3.notify更新

总结

RecyclerView的使用已经完结,主要针对具体demo分析如何去快速的上手使用,由于RecyclerView的功能非常强大,其他功能各位宝宝可以自行探索。

本文所有实例代码下载

猜你喜欢

recyclerview观察者模式

recyclerview缓存机制

参考

[1] Frank-Zhu, RecyclerView使用详解(二), 2015.

[2] Mr.杨__一个刚入行的码农, RecyclerView的基本使用, 2020.

[3]sean_depp, Android RecyclerView从入门到玩坏, 2018.