简单用法
创建一个简单的ListView非常简单
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
这就可以创造一个简单的ListView。
输入数据源
这里先暂时用少量数据,listof一个集合
class MainActivity : AppCompatActivity() {
private val data= listOf(
"Apple","Banana","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)
val list1 = findViewById<ListView>(R.id.listView)
list1.adapter = adapter
}
}
数据需要通过设配器传输进ListView,最好用的设配器之一是ArrayAdapter,有多个构造函数。
这里由于数据源都是字符串,因此类型强制为String,依次传入参数。
android.R.layout.simple_list_item_1是ListView子项布局的一个id,data就是数据源。
然后将适配器传递进去即可。效果图如下
定制界面
自定义界面,我们首先需要ListView适配器的适配类型。
即需要定义一个实体类
这里我们定义了一个fruit类
class Fruit(val Name:String,val imageId:Int) {
}
欸,可以发现不需要构造方法,因为功能只是提供一个适配类型。
参数为水果的名字和图片id。
我们的ListViewlayout已经写好了,还需要一个fruit_item,用来显示图片和文字。
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:id="@+id/fruitImage"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fruitName"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
/>
这里定义了两个控件,都比较简单,位置都是垂直居中。
接下来是比较重要的一步:自定义适配器
自定义的适配器将继承ArrayAdapter,并且将泛型指定为fruit类。
class FruitAdapter(avtivity:Activity,val resourceId:int,data:List<Fruit>):ArratAdapter(activity,resourceId,data){
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = LayoutInflater.from(context).inflate(resourceId,parent,false)
val fruitImage = view.findViewById(R.layout.FruitImage)
val fruitName = view.findViewByid(R.layout.FruitName)
val fruit = getItem(position)
if(fruit!=null)
{
fruitImage.setImageResource(fruit.imageId)
fruitName.text = fruit.name
}
return view
}
}
getView方法会在每个子项被滚动到屏幕的时候会被调用。
首先还是调用LayoutInflater类中的from()方法生成一个实例对象,再调用inflate动态加载,这里有三个参数,目前暂时不需要知道为什么传这三个参数,只需要知道这是ListView的标准写法即可。
getItem会得到当前的Fruit实例,当Fruit不为空时,就可以设置图片和文字。
最后需要在MainActivity中调用适配器。
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
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))
}
}
}
首先创建一个fruitlist用来收集所有的水果图片和名字,用initFruit来初始化,将图片的名字与图片i导入。
后面就是我们熟悉的操作啦。
效果如下:
优化
目前的ListView的效率非常低,还有很多地方可以改进。
比如,每次滚动时都要调用getView方法,加载所有布局,这其实是不需要的。
只需要做一点小小的变动即可
class FruitAdapter(avtivity:Activity,val resourceId:int,data:List<Fruit>):ArratAdapter(activity,resourceId,data){
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
}
}
}
convertView是缓存参数,用于将之前加载好的布局缓存,如果已经缓存那就可以直接用啦。
还有比如每次都有重新用FindViewByid捕获控件,也是比较费时间,这里可以用ViewHolder提前捕获,需要用到时就可以直接调用。
class FruitAdapter(avtivity:Activity,val resourceId:int,data:List<Fruit>):ArratAdapter(activity,resourceId,data){
inner Class ViewHolder(fruitImage:Imageview,fruitName:TextView)
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view:View
val viewHolder:ViewHolder
if(convertView==null)
{
view = LaytoutInflater.from(context).inflate(resourceId,partent,false)
val fruitImage = view.FindViewByid(R.id.fruitImage)
val fruitName = view.FindViewById(R,id.fruitName)
viewHoler.ViewHolder(fruitName,fruitImage)
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
}
}
这里创建了一个inner类viewHolder用来缓存控件。
这样就可以使得效率更高!
点击事件
这里学习一个setOnItemClickListener方法
setOnItemClickListener会有4个参数,但是有时候实际用到的并没有全部,因此没有用到的参数可以用’_‘表示
代码如下
listView.setOnItemClickLister{_,_,position,_ ->
val fruit = fruitList[positon]
Toast.maketext(this,fruit.name,Toast.LENGTH_SHORT).show()
}
代码参考自《第一含代码第三版》——郭霖大神