Android RecyclerView

1、用法案例:在RecyclerView中展示水果图片以及水果名称

水果实体类:Fruit.kt

class Fruit(val fruitName: String, val fruitImage: Int)

RecyclerView中水果数据项布局:fruit_item.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="60dp">

    <ImageView
        android:id="@+id/fruitImage"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        android:layout_width="40dp"
        android:layout_height="40dp"/>

    <TextView
        android:id="@+id/fruitName"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

适配器Adapter实现:FruitAdapter.kt

class FruitAdapter(private val fruits: List<Fruit>): RecyclerView.Adapter<FruitAdapter.ViewHolder>() {
    
    inner class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
        var fruitImage: ImageView = view.findViewById(R.id.fruitImage)
        var fruitName: TextView = view.findViewById(R.id.fruitName)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        Log.d("FruitAdapter", "onCreateViewHolder ...")
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.fruit_item, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        Log.d("FruitAdapter", "onBindViewHolder ...$position")
        holder.fruitImage.setImageResource(fruits[position].fruitImage)
        holder.fruitName.text = fruits[position].fruitName
    }

    override fun getItemCount(): Int {
        return fruits.size
    }
}

这里我们首先定义了一个内部类ViewHolder,它要继承自RecyclerVIew.ViewHolder。然后ViewHolder的主构造函数中要传一个view参数,这个参数就是RecyclerView子项的最外层布局,这样我们就可以通过findViewById来获取布局的元素了

由于FruitAdapter继承RecyclerView.Adapter,那么就必须重写onCreateViewHolder()、onBindViewHolder()以及getItemCount()这三个方法。

onCreateViewHolder方法用来创建ViewHolder实例的,我们在这个方法中将fruit_item.xml布局加载进来,创建ViewHolder实例并返回该实例。

onBindViewHolder方法用于对RecyclerView子项数据进行赋值,会在每个子项被滚进到屏幕内的时候执行,这里通过position参数将对应的水果信息初始化到屏幕内的子项上。

getItemCount方法用于告诉RecyclerView一共有多少个子项,直接返回数据源的长度即可。

这里要说明一点:onCreateViewHolder中创建的组件会被RecyclerView内部机制缓存,当屏幕滚动产生新的子项时,onCreateViewHolder方法不会被执行,RecyclerView内部会使用缓存组件,大大提高了滚动效率。

展示页面逻辑:MainActivity.kt

class MainActivity : AppCompatActivity() {

    private var fruitList = ArrayList<Fruit>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val bind = ActivityMainBinding.inflate(layoutInflater)
        setContentView(bind.root)
        initFruits()
        Log.d("MainActivity", "fruitList: ${fruitList.size}")
        val manager = LinearLayoutManager(this)
        bind.recycleView.layoutManager = manager
        val fruitAdapter = FruitAdapter(fruitList)
        bind.recycleView.adapter = fruitAdapter
    }

    private fun initFruits() {
        repeat(2) {
            fruitList.add(Fruit("apple", R.drawable.fruit))
            fruitList.add(Fruit("pear", R.drawable.fruit))
            fruitList.add(Fruit("banana", R.drawable.fruit))
            fruitList.add(Fruit("orange", R.drawable.fruit))
            fruitList.add(Fruit("peach", R.drawable.fruit))
            fruitList.add(Fruit("nectarine", R.drawable.fruit))
            fruitList.add(Fruit("apricot", R.drawable.fruit))
            fruitList.add(Fruit("plum", R.drawable.fruit))
            fruitList.add(Fruit("prune", R.drawable.fruit))
            fruitList.add(Fruit("persimmon", R.drawable.fruit))
            fruitList.add(Fruit("lemon", R.drawable.fruit))
            fruitList.add(Fruit("grape", R.drawable.fruit))
            fruitList.add(Fruit("watermelon", R.drawable.fruit))
            fruitList.add(Fruit("pineapple", R.drawable.fruit))
            fruitList.add(Fruit("blueberry", R.drawable.fruit))
            fruitList.add(Fruit("strawberry", R.drawable.fruit))
            fruitList.add(Fruit("waxberry", R.drawable.fruit))
            fruitList.add(Fruit("mulberry", R.drawable.fruit))
            fruitList.add(Fruit("cherrytomato", R.drawable.fruit))
        }
    }
}

自定义一个水果数组用来提供FruitAdater数据。

LinearLayoutManager用于指定RecyclerView的布局方式,这里是线性布局。一定要设置布局方式,不然RecyclerView不起作用,无法显示。

接着初始化FruitAdapter并适配到RecyclerView。

实现横向布局

修改fruit_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" //① 改为垂直布局
    android:layout_width="80dp"  //②设置宽度
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/fruitImage"
        android:layout_gravity="center_horizontal" //③水平居中
        android:layout_marginTop="10dp" //④设置顶部间距
        android:layout_width="40dp"
        android:layout_height="40dp"/>

    <TextView
        android:id="@+id/fruitName"
        android:layout_gravity="center_horizontal" //⑤水平居中
        android:layout_marginTop="10dp" //⑥设置顶部间距
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

修改MainActivity.kt

manager.orientation = LinearLayoutManager.HORIZONTAL

只需要将布局的排列方式改为横向排列即可,默认为纵向排列。

实现瀑布流布局:StaggeredGridLayoutManager

修改fruit_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_margin="5dp" //①让子项之间有间距,不至于紧贴在一起,比较美观
    android:layout_width="match_parent" //②改为match_parent,因为瀑布流的宽度应该是根据布局的列数来自动适配的,而不是一个固定值
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/fruitImage"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:layout_width="40dp"
        android:layout_height="40dp"/>

    <TextView
        android:id="@+id/fruitName"
        android:layout_gravity="left"  //③为了美观展示
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

修改MainActivity.kt

使用瀑布流布局,StaggeredGridLayoutManager的构造函数接收两个参数,第一个参数用于指定布局展示的列数,第二个参数用于指定布局的排列方向。

val manager = StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL)

创建了一个函数getRandomLengthString,就是为了随机增加水果名称的字数,尽可能展示瀑布流的布局效果。

    private fun initFruits() {
        repeat(2) {
            fruitList.add(Fruit(getRandomLengthString("apple"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("pear"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("banana"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("orange"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("peach"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("nectarine"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("apricot"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("plum"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("prune"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("persimmon"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("lemon"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("grape"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("watermelon"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("pineapple"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("blueberry"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("strawberry"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("waxberry"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("mulberry"), R.drawable.fruit))
            fruitList.add(Fruit(getRandomLengthString("cherrytomato"), R.drawable.fruit))
        }
    }

    private fun getRandomLengthString (str: String): String {
        val n = (1..20).random()
        var name = StringBuilder()
        repeat(n) {
            name.append(str)
        }
        return name.toString()
    }

 网格布局:GridLayoutManager

修改MainActivity.kt

 val manager = GridLayoutManager

posted on 2023-06-29 16:32  Devil'soul  阅读(34)  评论(0编辑  收藏  举报

导航