Android初步进阶之RecyclerView使用(一)

RecyclerView无论在性能还是灵活性上均优于ListView和GridView,因此,刚刚打算进阶就来学习了。

在开始使用之前,首先,在build.gradle中设置依赖导入:

implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha05'

然后,Sync Now。

  1. 首先,废话不多说,先看一个例子,横向的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
    }
}
  1. 我们适配器不用变,看一下纵向的列表实现:
  • 主活动:
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

效果:
在这里插入图片描述

  1. 那么,我们想要设置单击事件,可以直接设置吗?那肯定不行。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
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值