安卓开发高级控件学习之ListView与RecyclerView(Java与Kotlin)

一直以来都认为不必分散太多精力在UI控件上,但是逆向的过程中看到有许多控件都没有实践过,所以趁着这个机会学习一下几个UI。

1.Adapter

在学习UI之前首先学习下适配器Adapter,它的作用类似于MVC模式下的C,用来控制数据以怎样的方式显示到V上:
网上找到的一张Adapter的继承结构图
在这里插入图片描述
常用的有BaseAdapter(经常重写来使用)、ArrayAdapter(最简单的适配器,只显示一行文字)、SimpleAdapter(比ArrayAdapter效果好一点,可以自定义多种效果)。

2.ListView

多说无益,首先来学习ListView,虽然ListView逐渐被RecyclerView所取代,但是还是有学习的必要,之后学习RecyclerView的时候会看到两者的区别。适配器首先选择简单的ArrayAdapter和SimpleAdapter,当然重写BaseAdapter也可以。
首先定义activity_main布局:布局里放了一个listview作为MVC里面的V
在这里插入图片描述
然后要准备M然后定义C:
这里通过数组的方式准备数据源,适配器选择最简单的ArrayAdapter,静态或动态添加数据都可以:
在这里插入图片描述
在这里插入图片描述
这样看起来太单调,考虑在此基础上添加水果的图片:
item布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/fruit_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/fruit_name"
            android:textSize="20sp"
            android:textColor="#000000"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

        <TextView
            android:id="@+id/fruit_says"
            android:textSize="15sp"
            android:textColor="#000000"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>

</LinearLayout>

首先新建水果类:定义了三个变量,并设置相应的setter与getter
在这里插入图片描述
使用自定义适配器,新建FruitAdapter继承自BaseAdapter,并重写其getView方法:
在这里插入图片描述
然后在MainActivity中动态添加:
在这里插入图片描述
效果如下:
在这里插入图片描述
Kotlin Fruit类:

class Fruit(var icon:Int,var name:String,var says:String)

FruitAdapter继承ArrayAdapter,与Java逻辑相同:

class FruitAdapter(activity: Activity,resourceid:Int,fruits:List<Fruit>):ArrayAdapter<Fruit>(activity,resourceid,fruits) {
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
       val viewHolder:ViewHolder
       val view:View
       if(convertView == null){
           view = LayoutInflater.from(context).inflate(R.layout.fruit_item,parent,false)
           viewHolder = ViewHolder(view.findViewById(R.id.fruit_icon),view.findViewById(R.id.fruit_name),view.findViewById(R.id.fruit_says))
           view.tag = viewHolder
       }else{
           view = convertView
           viewHolder = view.tag as ViewHolder
       }

        val fruit = getItem(position)
        if(fruit!=null){
            viewHolder.icon.setImageResource(fruit.icon)
            viewHolder.name.text = fruit.name
            viewHolder.says.text = fruit.says
        }
        return view;
    }
    inner class ViewHolder(val icon:ImageView,val name:TextView,val says:TextView)
}

MainActivity中添加了点击事件:

class MainActivity : AppCompatActivity() {
    private val fruits = ArrayList<Fruit>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        fruits.add(Fruit(R.drawable.apple_pic,"苹果","我是苹果"))
        fruits.add(Fruit(R.drawable.cherry_pic,"樱桃","我是樱桃"))
        fruits.add(Fruit(R.drawable.mango_pic,"芒果","我是芒果"))
        val adapter = FruitAdapter(this,R.layout.fruit_item,fruits)
        listview.adapter = adapter
        listview.setOnItemClickListener { parent, view, position, id ->
            val fruit = fruits[position]
            Toast.makeText(this,"点击了${fruit.name}",Toast.LENGTH_SHORT).show()
        }
    }
}

效果如下:
在这里插入图片描述

之后要完成对listview的数据更新操作,这里添加功能是靠按钮来实现的,依次添加苹果,当然也可以选择位置插入添加,删除操作使用长按item子项弹出菜单实现的:
(1)添加功能
自定义适配器中添加了add功能:
在这里插入图片描述
Mainactivity中的调用:
在这里插入图片描述
效果如下:
在这里插入图片描述
Kotlin版本:
FruitAdapter:

class FruitAdapter(activity: Activity,resourceid:Int,val fruits:ArrayList<Fruit>):ArrayAdapter<Fruit>(activity,resourceid,fruits) {

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
       val viewHolder:ViewHolder
       val view:View
       if(convertView == null){
           view = LayoutInflater.from(context).inflate(R.layout.fruit_item,parent,false)
           viewHolder = ViewHolder(view.findViewById(R.id.fruit_icon),view.findViewById(R.id.fruit_name),view.findViewById(R.id.fruit_says))
           view.tag = viewHolder
       }else{
           view = convertView
           viewHolder = view.tag as ViewHolder
       }

        val fruit = getItem(position)
        if(fruit!=null){
            viewHolder.icon.setImageResource(fruit.icon)
            viewHolder.name.text = fruit.name
            viewHolder.says.text = fruit.says
        }
        return view;
    }

    **fun add(fruit:Fruit){
        //添加功能
        fruits?.add(fruit)
        notifyDataSetChanged()
    }**

    inner class ViewHolder(val icon:ImageView,val name:TextView,val says:TextView)
}

MainActivity,增加按钮点击监听:

class MainActivity : AppCompatActivity() {
    private var fruits = ArrayList<Fruit>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        fruits.add(Fruit(R.drawable.apple_pic,"苹果","我是苹果"))
        fruits.add(Fruit(R.drawable.cherry_pic,"樱桃","我是樱桃"))
        fruits.add(Fruit(R.drawable.mango_pic,"芒果","我是芒果"))
        val adapter = FruitAdapter(this,R.layout.fruit_item,fruits)
        listview.adapter = adapter
        add.setOnClickListener{
            adapter.add(Fruit(R.drawable.apple_pic,"苹果","我是苹果"))
        }
        listview.setOnItemClickListener { parent, view, position, id ->
            val fruit = fruits[position]
            Toast.makeText(this,"点击了${fruit.name}",Toast.LENGTH_SHORT).show()
        }
    }

}

点击增加苹果,效果如下:
在这里插入图片描述
(2)删除功能

首先为listview添加注册:
在这里插入图片描述
之后重写onCreateContextMenu方法和点击事件onContextItemSelected方法:
在这里插入图片描述
效果如下:
长按芒果:
在这里插入图片描述
点击删除:
在这里插入图片描述
Kotlin版本,修改MainActivity即可,逻辑和Java 相同:

   class MainActivity : AppCompatActivity() {
    private var fruits = ArrayList<Fruit>()
    private var item_position:Int = 0
    private var adapter : FruitAdapter ? = null

    override fun onContextItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            R.id.remove -> {
                fruits.removeAt(item_position)
                adapter?.notifyDataSetChanged()
                listview.invalidate()
            }
        }
        return true
    }

    override fun onCreateContextMenu(
        menu: ContextMenu?,
        v: View?,
        menuInfo: ContextMenu.ContextMenuInfo?
    ) {
       val info = menuInfo as AdapterView.AdapterContextMenuInfo
        item_position = info.position
        var inflator = MenuInflater(this)
        inflator.inflate(R.menu.menu,menu)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        fruits.add(Fruit(R.drawable.apple_pic,"苹果","我是苹果"))
        fruits.add(Fruit(R.drawable.cherry_pic,"樱桃","我是樱桃"))
        fruits.add(Fruit(R.drawable.mango_pic,"芒果","我是芒果"))
        adapter = FruitAdapter(this,R.layout.fruit_item,fruits)
        listview.adapter = adapter
        add.setOnClickListener{
            adapter?.add(Fruit(R.drawable.apple_pic,"苹果","我是苹果"))
        }
        listview.setOnItemClickListener { parent, view, position, id ->
            val fruit = fruits[position]
            Toast.makeText(this,"点击了${fruit.name}",Toast.LENGTH_SHORT).show()
        }
        registerForContextMenu(listview)
    }

}

长按子项,效果如下:
在这里插入图片描述
点击删除:
在这里插入图片描述

3.RecyclerView

需要引入依赖包:
在这里插入图片描述
RecyclerView相对ListView来说在性能方面进行了优化,例如子项中控件的点击事件比ListView简洁;也可以实现ListView不能实现的横向滚动。
首先先利用RecyclerView实现上面ListView中实现的布局,activity_main.xml添加RecyclerView控件作为V
在这里插入图片描述
与ListView一样也要有C来控制数据的显示方式:
在这里插入图片描述
ViewHolder类通过onCreateViewHolder方法中LayoutInflater.from(parent.getContext()).inflate方法将item布局加载并传给ViewHolder类的构造函数,并在构造函数里通过findViewbyId绑定实例。onBindViewHolder方法中利用ViewHolder实例进行赋值。
MainActivity与ListView类似,完成数据的动态加载:
在这里插入图片描述
与ListView不同的是增加了设置LinearLayoutManager实例,以用来指定RecyclerView的布局方式,LinearLayoutManager是线性布局的意思,因此效果与ListView类似:指定不同的布局方式显示的效果也不尽相同
在这里插入图片描述

Kotlin:逻辑与Java相同
子项布局文件:
在这里插入图片描述
FruitAdapter:首先定义了一个内部类ViewHolder,ViewHolder的主构造函数中需要传入一个View参数,这个参数就是Recycler子项的最外层布局,有了这个最外层布局,就可以通过findViewById获取子项布局中的各个控件实例

 class FruitAdapter(val fruits:List<Fruit>): RecyclerView.Adapter<FruitAdapter.ViewHolder>() {

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
         val fruit_icon:ImageView = itemView.findViewById(R.id.fruit_icon)
         val fruit_name:TextView = itemView.findViewById(R.id.fruit_name)
         val fruit_says:TextView = itemView.findViewById(R.id.fruit_says)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
         //继承RecyclerView.Adapter必须要重写的方法 
          val view = LayoutInflater.from(parent.context).inflate(R.layout.fruit_item,parent,false)
          return  ViewHolder(view)
    }
    //继承RecyclerView.Adapter必须要重写的方法
    override fun getItemCount(): Int = fruits.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        //继承RecyclerView.Adapter必须要重写的方法 对子项控件实例进行赋值
        val fruit = fruits[position]
        holder.fruit_icon.setImageResource(fruit.icon)
        holder.fruit_name.text = fruit.name
        holder.fruit_says.text = fruit.says
    }

}

MainActivity:layoutManager用于指定Recyclerview的布局方式,这里使用LinearLayoutManager就是现形布局的意思,可以实现和listview相同的效果

class MainActivity : AppCompatActivity() {

    private val fruits = ArrayList<Fruit>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        fruits.add(Fruit(R.drawable.apple_pic,"苹果","我是苹果"))
        fruits.add(Fruit(R.drawable.cherry_pic,"樱桃","我是樱桃"))
        fruits.add(Fruit(R.drawable.mango_pic,"芒果","我是芒果"))
        val adapter = FruitAdapter(fruits)
        val layoutManager = LinearLayoutManager(this)
        recyclerview.layoutManager = layoutManager
        recyclerview.adapter = adapter
    }
}

效果如下:在这里插入图片描述

接着看下上面说的与listview不同的横向滚动和子项控件点击事件优化。
横向滚动:
在这里插入图片描述
改动的地方有2:
1是item布局的宽度,当然这里没有设置图片与文字的对齐方式
在这里插入图片描述
2是通过 linearLayoutManager设置布局的排列方式
在这里插入图片描述
Kotlin:
在这里插入图片描述

再看点击事件,这里设置了子项view的点击事件以及子项中三个字控件的点击事件,在onCreateViewHolder中实现:
在这里插入图片描述
效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Kotlin:
同样在FruitAdapter的onCreateViewHolder方法中实现,逻辑与Java相同
在这里插入图片描述
效果如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42011443/article/details/106567849