android自定义ListView与Adapter

效果如下:

 步骤如下:

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))
        }

好了,完成!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值