RecyclerView无论在性能还是灵活性上均优于ListView和GridView,因此,刚刚打算进阶就来学习了。
在开始使用之前,首先,在build.gradle中设置依赖导入:
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha05'
然后,Sync Now。
- 首先,废话不多说,先看一个例子,横向的RecyclerView实现:
- 适配器的实现。
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class HomeAdapter(val mList:ArrayList<String>, val mContext:Context) : RecyclerView.Adapter<HomeAdapter.MyViewHolder>(){
public fun removeData(position:Int) :Unit {
mList.removeAt(position)
notifyItemRemoved(position)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeAdapter.MyViewHolder {
val contentView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false)
val holder:MyViewHolder = MyViewHolder(contentView)
return holder
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.tv.setText(mList.get(position))
}
override fun getItemCount(): Int {
return mList.size
}
class MyViewHolder(val view: View) : RecyclerView.ViewHolder(view){
val tv:TextView = view.findViewById(R.id.text_id)
}
}
- 我们主要的列表所在页面的xml代码:
<?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"
android:orientation="horizontal"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
- 子项的xml代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_id"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="233"
android:gravity="center"
/>
</LinearLayout>
- 主函数代码:
import android.app.Activity
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.util.*
import kotlin.collections.ArrayList
class MainActivity : Activity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val data = ArrayList<String>()
data.add("测试")
data.add("再测")
data.add("春绮美空")
//设置列表
val list:RecyclerView = findViewById(R.id.recyclerview)
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
val linearLayoutManager = LinearLayoutManager(this)
linearLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
list.layoutManager = linearLayoutManager
list.layoutParams = params
list.itemAnimator = DefaultItemAnimator()
val adapter:HomeAdapter = HomeAdapter(data, this)
list.adapter = adapter
}
}
- 我们适配器不用变,看一下纵向的列表实现:
- 主活动:
import android.app.Activity
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.util.*
import kotlin.collections.ArrayList
class MainActivity : Activity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val data = ArrayList<String>()
data.add("测试")
data.add("再测")
data.add("春绮美空")
//设置列表
val list:RecyclerView = findViewById(R.id.recyclerview)
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
list.layoutManager = LinearLayoutManager(this)
list.layoutParams = params
list.itemAnimator = DefaultItemAnimator()
val adapter:HomeAdapter = HomeAdapter(data, this)
list.adapter = adapter
}
}
- 主列表:
<?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"
android:orientation="vertical"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
- 子项:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/text_id"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="233"
android:gravity="center"
/>
</LinearLayout>
注意:子项的最外层布局需要根据是横向还是纵向而设置wrap_content。
总结,RecyclerView更相当与一个容器,里面每一项都作为一个子布局,被适配器放入这个容器中,因此,子项的最外层布局,会直接影响到它在列表中的展示布局,所以,才会出现一个子项占满容器的情况,你可以试试将子项的布局线性布局宽高全部设置为match_parent,列表就只会显示一项。
3. 结果
横向:
纵向:
4. 你应该也注意到了,这个列表没有分割线,RecyclerView并没有自带分割线,需要自己定义,虽然比较麻烦,但是可以私人定制啊。下面介绍一下分割线的实现。
- 首先,需要继承实现RecyclerView.Decoration,如果你有一点Canvas的基础,应该不难理解,
import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.DrawFilter
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.text.AttributedString
class DividerItemDecoration : RecyclerView.ItemDecoration() {
companion object {
fun get():IntArray{
val res = IntArray(1)
res[0] = android.R.attr.listDivider
return res
}
var ATTRS = get()
val HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL
val VERTICAL_LIST = LinearLayoutManager.VERTICAL
}
private var mDivider: Drawable? = null
private var mOrientation:Int = 0
/**
* 初始化
*/
public fun DividerItemDecoration(context: Context, orientation:Int){
val a:TypedArray = context.obtainStyledAttributes(ATTRS)
mDivider = a.getDrawable(0)
a.recycle()
setOrientation(orientation)
}
/**
* 设置布局
*/
public fun setOrientation(orientation:Int){
if(orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST){
throw IllegalArgumentException("无效布局")
}
mOrientation = orientation
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if(mOrientation == VERTICAL_LIST){
drawVertical(c, parent)
}else{
}
}
/**
* 绘制纵向分割线
*/
fun drawVertical(c:Canvas, parent:RecyclerView){
val left:Int = parent.paddingLeft
val right:Int = parent.width - parent.paddingRight
val childCount:Int = parent.childCount
for(i in 0 until childCount){
val child: View = parent.getChildAt(i)
val params:RecyclerView.LayoutParams = RecyclerView.LayoutParams(child.layoutParams)
val top:Int = child.bottom + params.bottomMargin
val bootom:Int = top + mDivider!!.intrinsicHeight
mDivider!!.setBounds(left, top, right, bootom)
mDivider!!.draw(c)
}
}
/**
* 绘制横向分割线
*/
fun drawHorizontal(c:Canvas, parent: RecyclerView){
val top:Int = parent.paddingTop
val bottom:Int = parent.height - parent.paddingBottom
val childCount:Int = parent.childCount
for(i in 0 until childCount){
val child:View = parent.getChildAt(i)
val params:RecyclerView.LayoutParams = RecyclerView.LayoutParams(child.layoutParams)
val left:Int = child.right + params.rightMargin
val right:Int = left + mDivider!!.intrinsicWidth
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(c)
}
}
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
if(mOrientation == VERTICAL_LIST){
outRect.set(0, 0, 0, mDivider!!.intrinsicHeight)
}else{
outRect.set(0 , 0 , mDivider!!.intrinsicWidth, 0)
}
}
}
- 然后,在设置adapter之前,设置分割线。
val decoration:DividerItemDecoration = DividerItemDecoration()
decoration.DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)
list.addItemDecoration(decoration)
list.adapter = adapter
效果:
- 那么,我们想要设置单击事件,可以直接设置吗?那肯定不行。233,高级的组件灵活性就是高,啥都得自己搞,开搞。我们给每一项设置单击事件。
- 修改适配器
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class HomeAdapter(val mList:ArrayList<String>, val mContext:Context) : RecyclerView.Adapter<HomeAdapter.MyViewHolder>(){
private var mOnItemClickListener:OnItemClickListener? = null
public fun removeData(position:Int) :Unit {
mList.removeAt(position)
notifyItemRemoved(position)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeAdapter.MyViewHolder {
val contentView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false)
val holder:MyViewHolder = MyViewHolder(contentView)
//设置单击事件,和我们的接口挂钩
contentView.setOnClickListener(object :View.OnClickListener{
override fun onClick(v: View?) {
mOnItemClickListener!!.onItemClick(v!!, v.tag as Int)// as真好用
}
})
return holder
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.tv.setText(mList.get(position))
holder.itemView.tag = position
}
override fun getItemCount(): Int {
return mList.size
}
class MyViewHolder(val view: View) : RecyclerView.ViewHolder(view){
val tv:TextView = view.findViewById(R.id.text_id)
}
//我们的事件接口,可以在这里扩充
public interface OnItemClickListener{
//单击
fun onItemClick(view: View, position: Int)
}
//设置点击属性
public fun setOnItemClickListener(mOnItemClickListener: OnItemClickListener){
this.mOnItemClickListener = mOnItemClickListener
}
}
- 搞好之后,在主活动中定义单击事件:
import android.app.Activity
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.Toast
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.util.*
import kotlin.collections.ArrayList
class MainActivity : Activity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val data = ArrayList<String>()
data.add("测试")
data.add("再测")
data.add("春绮美空")
//设置列表
val list:RecyclerView = findViewById(R.id.recyclerview)
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
list.layoutManager = LinearLayoutManager(this)
list.layoutParams = params
list.itemAnimator = DefaultItemAnimator()
val adapter:HomeAdapter = HomeAdapter(data, this)
val decoration:DividerItemDecoration = DividerItemDecoration()
decoration.DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)
list.addItemDecoration(decoration)
//设置单击事件
adapter.setOnItemClickListener(object :HomeAdapter.OnItemClickListener{
override fun onItemClick(view: View, position: Int) {
Toast.makeText(this@MainActivity, "单击第${position+1}条", Toast.LENGTH_LONG).show()
}
})
list.adapter = adapter
}
}
- 效果如下
还有,下一篇,有帮助点个赞吧,拜托了,这对我真的很重要!!!
下一篇,Android初步进阶之RecyclerView使用(二)