ListView 的简单用法

在布局中加入 ListView 控件还算简单,先为 ListView 指定一个 id,然后将宽度和高度都设置为 match_parent,这样 ListView 就占满了整个布局的空间

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent">    <ListView        android:id="@+id/listView"        android:layout_width="match_parent"        android:layout_height="match_parent" />LinearLayout>

接下来修改 MainActivity 中的代码

class MainActivity : AppCompatActivity() {         private val data = listOf("Apple", "Banana", "Orange", "Watermelon",        "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango",        "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape",        "Pineapple", "Strawberry", "Cherry", "Mango")    override fun onCreate(savedInstanceState: Bundle?) {             super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data)        listView.adapter = adapter    }}

先将数据准备好,然后借助适配器将数据传递给 ListView。ArrayAdapter 是 Android 提供的一种适配器的实现类,可以通过泛型来指定要适配的数据类型,然后在构造函数中把要适配的数据传入。在 ArrayAdapter 的构造函数中依次传入 Activity 的实例、ListView 子项布局的 id、数据源,这里我们使用了 android.R.layout.simple_list_item_1 作为 ListView 子项布局的 id,这是一个 Android 内置的布局文件,里面只有一个 TextView,可用于简单地显式一段文本。最后,调用 ListView 的 setAdapter() 方法,将构建好的适配器对象传递进去,这样 ListView 和数据之间的关联就建立完成了


定制 ListView 的界面

只能显示一段文本的 ListView 实在太单调了,我们现在希望定制 ListView 的界面,让它能显示文本和图片

在需要 ListView 的子项指定一个我们自定义的布局,在 layout 目录下新建 fruit_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="60dp">    <ImageView        android:id="@+id/fruitImage"        android:layout_width="40dp"        android:layout_height="40dp"        android:layout_gravity="center_vertical"        android:layout_marginLeft="10dp"        tools:ignore="ContentDescription,RtlHardcoded" />    <TextView        android:id="@+id/fruitName"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center_vertical"        android:layout_marginLeft="10dp"        tools:ignore="RtlHardcoded" />LinearLayout>

定义一个实体类,作为 ListView 适配器的适配类型

class FruitAdapter(activity: Activity, val resourceId: Int, data: List<Fruit>) :    ArrayAdapter<Fruit>(activity, resourceId, data) {         @SuppressLint("ViewHolder")    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {             val view = LayoutInflater.from(context).inflate(resourceId, parent, false)        val fruitImage: ImageView = view.findViewById(R.id.fruitImage)        val fruitName: TextView = view.findViewById(R.id.fruitName)        val fruit = getItem(position)        if (fruit != null) {                 fruitImage.setImageResource(fruit.imageId)            fruitName.text = fruit.name        }        return view    }}

FruitAdapter 类继承自 ArrayAdapter,并泛型指定为 Fruit 类,重写 getView() 方法。在 getView() 方法中,首先使用 LayoutInflater 来为这个子项加载我们传入的布局,再调用 View 的 findViewById() 方法分别获取 ImageView 和 TextView,然后通过 getItem() 方法得到当前项的 Fruit 实例,设置显示的图片和文字,最后将布局返回

最后修改 MainActivity 中的代码

class MainActivity : AppCompatActivity() {         private val fruitList = ArrayList<Fruit>()    private val data = listOf("Apple", "Banana", "Orange", "Watermelon",        "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango",        "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape",        "Pineapple", "Strawberry", "Cherry", "Mango")    override fun onCreate(savedInstanceState: Bundle?) {             super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        initFruits()        val adapter = FruitAdapter(this, R.layout.fruit_item, fruitList)        listView.adapter = adapter    }    private fun initFruits() {             repeat(2) {                 fruitList.add(Fruit("Apple", R.drawable.apple_pic))            fruitList.add(Fruit("Banana", R.drawable.banana_pic))            fruitList.add(Fruit("Orange", R.drawable.orange_pic))            fruitList.add(Fruit("Watermelon", R.drawable.watermelon_pic))            fruitList.add(Fruit("Pear", R.drawable.pear_pic))            fruitList.add(Fruit("Grape", R.drawable.grape_pic))            fruitList.add(Fruit("Pineapple", R.drawable.pineapple_pic))            fruitList.add(Fruit("Strawberry", R.drawable.strawberry_pic))            fruitList.add(Fruit("Cherry", R.drawable.cherry_pic))            fruitList.add(Fruit("Mango", R.drawable.mango_pic))        }    }}


提升 ListView 的运行效率

getView() 方法中还有一个 convertView 参数,这个参数用于将之前加载好的布局进行缓存,以便之后进行重用,我们可以借助这个参数进行性能优化

class FruitAdapter(activity: Activity, val resourceId: Int, data: List<Fruit>) :    ArrayAdapter<Fruit>(activity, resourceId, data) {         @SuppressLint("ViewHolder")    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {             val view: View        if (convertView == null) {                 view = LayoutInflater.from(context).inflate(resourceId, parent, false)        } else {                 view = convertView        }        val fruitImage: ImageView = view.findViewById(R.id.fruitImage)        val fruitName: TextView = view.findViewById(R.id.fruitName)        val fruit = getItem(position)        if (fruit != null) {                 fruitImage.setImageResource(fruit.imageId)            fruitName.text = fruit.name        }        return view    }}

我们在 getView() 方法中进行了判断:如果 convertView 为 null,则使用 LayoutInflater 去加载布局;如果不为 null,则直接对 convertView 进行重用

目前代码还可以继续优化,每次在 getView() 方法中仍然会调用 View 的 findViewById 方法去获取一次控件的实例,我们可以借助一个 ViewHolder 来对这部分性能进行优化,修改 FruitAdapter 中的代码

class FruitAdapter(activity: Activity, val resourceId: Int, data: List<Fruit>) :    ArrayAdapter<Fruit>(activity, resourceId, data) {         inner class ViewHolder(val fruitImage: ImageView, val fruitName: TextView)    @SuppressLint("ViewHolder")    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {             val view: View        val viewHolder: ViewHolder        if (convertView == null) {                 view = LayoutInflater.from(context).inflate(resourceId, parent, false)            val fruitImage: ImageView = view.findViewById(R.id.fruitImage)            val fruitName: TextView = view.findViewById(R.id.fruitName)            viewHolder = ViewHolder(fruitImage, fruitName)            view.tag = viewHolder        } else {                 view = convertView            viewHolder = view.tag as ViewHolder        }        val fruit = getItem(position)        if (fruit != null) {                 viewHolder.fruitImage.setImageResource(fruit.imageId)            viewHolder.fruitName.text = fruit.name        }        return view    }}

我们新增一个内部类 ViewHolder,用于对 ImageView 和 TextView 的控件实例进行缓存。当 convertView 为 null 时,创建一个 ViewHolder 对象,并将控件的实例存放在 ViewHolder 里,然后调用 View 的 setTag() 方法,将 ViewHolder 对象存储在 View 中


ListView 的点击事件

ListView 的滚动毕竟只是满足我们视觉上的效果,因此本节学习 ListView 如何才能响应用户的点击事件

class MainActivity : AppCompatActivity() {         private val fruitList = ArrayList<Fruit>()    ...    override fun onCreate(savedInstanceState: Bundle?) {             super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        initFruits()        val adapter = FruitAdapter(this, R.layout.fruit_item, fruitList)        listView.adapter = adapter        /*val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, data)*/        /*listView.adapter = adapter*/        listView.setOnItemClickListener {     parent, view, position, id ->            val fruit = fruitList[position]            Toast.makeText(this, fruit.name, Toast.LENGTH_SHORT).show()        }    }}

更多相关文章

  1. 【移动开发】Android中Fragment+ViewPager的配合使用
  2. Android的线程使用来更新UI----Thread、Handler、Looper、TimerT
  3. android中引用javascript和在javascript中引用java的简单例子
  4. Android(安卓)webView与js 交互以及jsbridge框架源码分析
  5. [Android]解决failed to get the required ADT version from sdk
  6. Android中Handler Runnable与Thread的区别详解
  7. Android打开第三方地图使用方法
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android 开发者从0到1发布一个微信小程序
  2. Android搜索控件的基本使用方法
  3. 开博第一日
  4. Android结合Retrofit实现统一加解密处理(G
  5. 深入探索Android稳定性优化
  6. Android自定义视图
  7. Android与WebView的同步和异步访问机制
  8. Android消息循环的同步屏障机制及UI渲染
  9. android中的下载问题
  10. Activity生命周期详解