效果如下:
步骤如下:
1)添加一个ListView控件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/lv"
style="@style/Widget.AppCompat.ListView"
android:layout_width="409dp"
android:layout_height="729dp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
2)再添加一个ListView每一行所使用的视图layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iconTv"
android:layout_width="106dp"
android:layout_height="98dp"
android:layout_weight="1"
tools:srcCompat="@tools:sample/avatars" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginLeft="150dp"
tools:layout_editor_absoluteX="100dp">
<TextView
android:id="@+id/nameTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:textColor="#898989"
android:textSize="16sp" />
<TextView
android:id="@+id/phoneTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:layout_marginTop="10dp"
android:layout_marginLeft="5dp"
android:textColor="#898989"
android:textSize="16sp" />
<CheckBox
android:id="@+id/shareTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="共享位置"
android:textColor="#898989"
android:textSize="16sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
3)我们定义一个模板类,实现Apapter:
package org.bird.testlistview
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
/**
* 自定义的通用适配器,作为公共的Adapter类,继承自BaseAdapter。以后如果是自定义ListView的adapter,继承它就行了
*/
abstract class ListViewAdapter<T>(context: Context, datas: List<T>, layoutId: Int) :
BaseAdapter() {
//为了让子类访问,于是将属性设置为protected
protected var mContext: Context
protected var mDatas: List<T>
protected var mInflater: LayoutInflater
private val layoutId: Int //不同的ListView的item布局肯能不同,所以要把布局单独提取出来
override fun getCount(): Int {
return mDatas.size
}
override fun getItem(position: Int): T {
return mDatas[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(
position: Int, //当前item的位置
convertView: View?, //用于复用旧视图
parent: ViewGroup?
): View { //此视图最终将附加到的父级,用于加载XML布局
//初始化ViewHolder,使用通用的ViewHolder,一行代码就搞定ViewHolder的初始化咯
val holder: CommonViewHolder =
CommonViewHolder.get(mContext, convertView, parent, layoutId, position) //layoutId就是单个item的布局
convert(holder, getItem(position))
return holder.getConvertView() //这一行的代码要注意了
}
//将convert方法公布出去
abstract fun convert(holder: CommonViewHolder?, t: T)
init {
mContext = context
mInflater = LayoutInflater.from(context)
mDatas = datas
this.layoutId = layoutId
}
}
4)对这个模板再写一个通用的Holder,用于将资源转换为自己需要的类引用,方便绑定数据:
package org.bird.testlistview
import android.util.SparseArray
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
/**
* 作为公共的类.对应ListView里面的item控件,提高控件的查询效率
*/
class CommonViewHolder(
context: Context?,
parent: ViewGroup?, //此视图最终将附加到的父级,用于加载XML布局
layoutId: Int, //单个item的布局
private var mPosition: Int
) {
private val mViews: SparseArray<View?>
private val mConvertView: View
init { //当前item的位置
mViews = SparseArray<View?>()
mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false)
mConvertView.setTag(this)
}
/*
通过viewId获取控件
*/
//使用的是泛型T,返回的是View的子类
fun <T : View?> getView(viewId: Int): T {
var view: View? = mViews[viewId]
if (view == null) {
view = mConvertView.findViewById(viewId)
mViews.put(viewId, view)
}
return view as T
}
fun getConvertView(): View
{
return mConvertView
}
companion object {
operator fun get(
context: Context?,
convertView: View?, //用于复用旧视图
parent: ViewGroup?, //此视图最终将附加到的父级,用于加载XML布局
layoutId: Int, //单个item的布局
position: Int
): CommonViewHolder { //当前item的位置
return if (convertView == null) {
CommonViewHolder(context, parent, layoutId, position)
} else {
val holder = convertView.getTag() as CommonViewHolder
holder.mPosition = position //即使ViewHolder是复用的,但是position记得更新一下
holder
}
}
}
}
5) 定义一下我们需要使用的数据类:
package org.bird.testlistview
data class Friend(val name: String, val icon:String, val phone:String, val isShare: Boolean) {
}
6) 将数据与layout绑定的定制adapter:
package org.bird.testlistview
import android.content.Context
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import android.view.View
import android.view.ViewGroup
import android.widget.*
//将Adapter和ViewHolder关联,加载到item布局,此处用于扩展
class FriendAdapter1 (context: Context?, datas: List<Friend?>?) :
ListViewAdapter<Friend?>(context!!, datas!!, R.layout.item_friend) {
override fun convert(holder: CommonViewHolder?, friend: Friend?) {
(holder!!.getView(R.id.nameTv) as TextView).setText(friend!!.name)
(holder.getView(R.id.iconTv) as ImageView).setImageResource(R.drawable.ic_launcher_background)
(holder.getView(R.id.phoneTv) as TextView).setText(friend.phone)
(holder.getView(R.id.shareTv) as CheckBox).isChecked = friend.isShare
//(holder.getView(R.id.shareTv) as CheckBox).bringToFront()
}
}
7) Activity中生成几组数据,并设置:
var data: kotlin.collections.List<Friend> = ArrayList<Friend>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var lv = findViewById<ListView>(R.id.lv);
data += Friend("robin", "icon1", "13810501000", true)
data += Friend("robin1", "icon2", "13810502000", false)
data += Friend("robin2", "icon3", "13810503000", true)
// 1)
//val adapter = FriendAdapter(this, data)
// 2)
val adapter = FriendAdapter1(this, data)
// 第三步:给listview设置适配器(view)
lv.setAdapter(adapter);
val actionBar: ActionBar? = supportActionBar
if (actionBar != null) {
actionBar.setHomeButtonEnabled(true)
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.setTitle("测试页面")
//actionBar.setBackgroundDrawable(resources.getDrawable(R.drawable.tab_menu_auto))
}
好了,完成!