Android开发(1):ListView和RecyclerView以及Adapter的基本使用

本文主要讲ListView和RecycleView的基本使用,以及如何自定义Adapter,设计自己喜欢的Item样式,但具体原理不涉及,等以后有时间在记录。

ListView和RecycleView均为Android控件,是布局中特别重要的控件,用来显示一列一列的数据,Adapter是适配器,用于填充数据和设计Item样式,ListView有自带的Adapter,RecycleView需自定义Adapter。

一、ListView

1. 基本使用

(1)创建一个空的Listview

<ListView
    android:id="@+id/listView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

(2)使用自带Adapter填充数据

在.java文件中获得这个ListView后,使用Adapter为这个ListView填充数据,常用的Adapter有ArrayAdapter、SimpleAdapter。随着ListView中内容的丰富,这两种Adapter很难满足要求,因此现在一般使用自定义的Adapter来填充数据。现在使用ArrayAdapter演示填充数据,其他自带Adapter原理一样,只是参数不同,样式也有点不同,如果需求简单,可以直接使用自带的Adapter。

listview = (ListView) findViewById(R.id.listview);
String[] datas= {"第一行", "第二行", "第三行",};
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, R.layout.activity_main, datas);
listview .setAdapter(arrayAdapter);

如上,通过ID获取Listview控件,datas为数据,声明定义arrayAdapter的函数的三个参数分别为:

①this: 代表了访问整个Android应用的接口,即context。几乎创建所有组件都需要传入Context对象。

②activity_main: 一个布局页面,即ListView所在布局文件。

③datas:数组或List ,负责提供数据

(3)为自带Adapter修改字体和颜色

ListView是无法像其他控件一样直接在控件布局设置字体等属性,一般都是默认使用其字体、颜色等。但此时你又不想自定义Adap,只是想修改个颜色字体间距等等,可以新建一个布局文件,如detail.xml,该布局只含有一个TextView,其他组件均不可存在,包括ConstraintLayout等布局组件。如下,你可以在里面自由设计字体边距等等。

<?xml version="1.0" encoding="utf-8"?>
<TextView 
    xmlns:android="http://schemas.android.com/apk/res/android"    
    android:id="@+id/operation"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="#D5000000"
    android:textSize="20sp"/>

之后,需修改刚刚声明适配器的语句,将第二个参数activity_main(即listview所在页面)改为TextView所在页面,即detail。

ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, R.layout.detail, datas);

(3)数据更新

当你datas发生改变时,需要对数据进行更新,用notifyDataSetChanged更新,如下,datas修改,再更新,注意,不能改变数据datas指向的内存地址,即重新声明定义,只能调用它的remove(), add()等方法来改变数据。

datas.remove(0);
arrayAdapter.notifyDataSetChanged();
 

2. 自定义Adapter

有时候ListView无法满足你对Item的需求,比如你想在Item里插入图片或者多个TextView,可以选择自定义Adapter。

扫描二维码关注公众号,回复: 4215694 查看本文章

(1)重写布局文件

在activity_main.xml创建一个ListView,注意观察最后一个属性,item_layout是一个xml文件。根据意思大概也能只能item_layout.xml是ListView控件中的item的详细布局,即你自定义的内容,放在layout文件夹中。

<ListView
    android:id="@+id/listview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:listitem="@layout/item_layout"/>

item_layout.xml,里面有两个TextView控件,TextView属性自己设置,其实也可以添加其他控件,只要在自定义的适配器中传进数据即可。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >


    <TextView
        android:id="@+id/food_name"
         />


    <TextView
        android:id="@+id/food_type"
        />
</FrameLayout>

(2)自定义Adapter类

重写Adapter类,继承BaseAdapter,注意,需要在类中提供一个数据列表以填充数据。这里用ArrayList类型,food是我自己声明的一个类。两个TextView先声明,分别是我们刚刚在item_layout里的两个。

public class MyListAdapter extends BaseAdapter{
    private ArrayList<food> datas;
    Context context;
    TextView food_name;
    TextView food_type;
    MyListAdapter(ArrayList<food> data, Context context){
        this.datas = data;
        this.context = context;
    }

    @Override
    public food getItem(int position);

    @Override
    public long getItemId(int position);

    @Override
    public int getCount();
    
    @Override
    View getView(int i, View view, ViewGroup viewGroup);
}

以下列出的四个方法是必须重写的四个方法,下面介绍这四个方法。position是列表的第几项。

int getCount();获得数据项列表的长度,也就是一共有多少个数据项。

Object getItem(int position); //获得一个数据项。

long getItemId(int position); //获得数据项的位置。

View getView(int position, View convertView, ViewGroup parent); //获得数据项的布局样式,最重要的一个方法。

除此之外,你还得写更新datas数据的函数,比如删除或者增添,之后再用notifyDataSetChanged更新。

View getView()函数如下,当convertView 为空时才加载布局,否则,直接修改内容,这样可以减少重复的加载布局,提高效率。注意item_layout。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if(convertView == null){
        convertView = LayoutInflater.from(context).inflate(R.layout.item_layout, null);
    }
    food_name = (TextView) convertView.findViewById(R.id.food_name);
    food_type = (TextView) convertView.findViewById(R.id.food_type);
    food_name.setText(datas.get(position).getFood_name());
    food_type.setText(datas.get(position).getFood_type());
    return convertView;
}

(3)使用自定义MyListAdapter 

listview = (ListView) findViewById(R.id.listview);
myListAdapter = new MyListAdapter(collect_datas, this);
listview.setAdapter(myListAdapter);

(4)更新数据

和前面一样,只不过需要自己在MyListAdapter 内写更新的函数,然后myListAdapter对象调用该函数,再用notifyDataSetChanged()更新。

3. Listview点击事件

长按事件有返回值,注意返回false会同时触发点击事件和长按事件,所以需要返回true。position是点击item的位置。

listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
        // 处理单击事件
    }
});

listview.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
    @Override
    public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long l) {
        // 处理长按事件
        return true; 
    }
});

二、RecycleView

在RecyclerView中自定义实现RecyclerView.Adapter并为其提供数据集合,实现时遵循设计ViewHolder模式。

1. 添加依赖

在app的build.gradle(module)文件中添加依赖:版本号根据自己的build.gradle前面的数据自己改

implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'

2. 布局

activity.xml

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:listitem="@layout/item_layout" />

注意上面最后一行代码,和Listview一样,这里不多讲

3. 自定义Adapter

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHoder>{
    private ArrayList<food> datas;
    Context context;
    public MyAdapter(ArrayList<food> datas, Context context){
        this.datas = datas;
        this.context = context;
    }
}

实现上面自定义的MyAdapter必须重写以下三个函数,以及一个继承类MyViewHoder 。

①public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType), ViewHolder模式

②public void onBindViewHolder(ViewHolder holder, int position),最为重要的函数,类似于上面ListView的View getView()函数

③public int getItemCount(),这个不讲。

④public class MyViewHoder extends RecyclerView.ViewHolder{} ,这个不是必须写,但遵循设计ViewHolder模式时自定义RecyclerView.ViewHolder

(1)重写onCreateViewHolder()

注意inflate内第一个参数为item的样式所在布局。

@NonNull
@Override
public MyViewHoder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    MyViewHoder hoder = 
    new MyViewHoder(LayoutInflater.from(context).inflate(R.layout.item_layout,viewGroup, false));
    return hoder;
}

(2)自定义RecyclerView.ViewHolder

public class MyViewHoder extends RecyclerView.ViewHolder{
    TextView food_name;
    TextView food_type;
    public MyViewHoder(View view){
        super(view);
        food_name = view.findViewById(R.id.food_name);
        food_type = view.findViewById(R.id.food_type);
    }
}

(3)onBindViewHolder() 绑定数据

i为item的position,此处绑定了两个TextView的数据,而且是通过我们自定义的MyViewHoder ,同时在里面设置了item的点击事件,长按事件有返回值,这里具体前面已经说清楚了。

public void onBindViewHolder(@NonNull MyViewHoder myViewHoder, final int i) {
    myViewHoder.food_name.setText(datas.get(i).getFood_name());
    myViewHoder.food_type.setText(datas.get(i).getFood_type());
    myViewHoder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            //长按事件处理
            return true;  //设置false会引发点击事件
        }
    });
    myViewHoder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //点击事件处理
        }
    });
}

4. 设置布局管理器以及实例化

完成了RecycleView的布局以及Adapter的自定义,接下来一步是使用它,setLayoutManager()是item的显示方式,有以下几种方式,区别如下:

recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 类似ListView
recyclerView.setLayoutManager(new GridLayoutManager(this, 2)); // 类似GridView
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL)); // 线性宫格,类似瀑布流 ​

使用线性显示,其中all_datas是传入数据

recycleview = (RecyclerView)findViewById(R.id.recyclerView);
recycleview.setLayoutManager(new LinearLayoutManager(this));
myAdapter = new MyAdapter(all_datas, this);
recycleview.setAdapter(myAdapter);

5. 更新数据

想一想刚刚Listview是怎么样更新数据的,是在adapter里定义一个更新的函数,然后再调用notifyDataSetChanged实现更新,这里也使用notifyDataSetChanged,但因为我们点击事件是在Adapter里使用的,所以可以直接在自定义的Adapter里配合i(就是点击事件的一个参数)进行更新操作如add,remove等等,以长按事件代码为例

myViewHoder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        //长按事件处理
        datas.remove(datas.get(i)); //datas是Adapyer内声明的数据,可以直接使用
        myAdapter.notifyDataSetChanged(); //myAdapter是全局变量,是一开始声明的实例
        return true;  //设置false会引发点击事件
    }
});

猜你喜欢

转载自blog.csdn.net/chenxz_/article/details/83413658