栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android ListView和RecyclerView

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android ListView和RecyclerView

1.ListView 1.1ListView的简单使用

listView在开发中经常用到,首先看一下listView的实现效果

  1. 新建activity_main.xml和list_item.xml布局文件


    




    


在activity_main中添加ListView控件,list_item就是列表中每一项的布局(只添加了一个Textview,可以通过修改list_item来定制不同的ListView界面)
2. 新建一个JavaBean类,作为适配器的适配类型

public class Bean {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

在Bean类中只有一个属性name,用于设置textView的文本
3. 新建一个MyAdapter继承自baseAdapter

public class MyAdapter extends baseAdapter {

    private List data;
    private Context mContext;

    public MyAdapter(List data, Context mContext) {
        this.data = data;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        convertView= LayoutInflater.from(mContext).inflate(R.layout.list_item,parent,false);
        TextView textView=convertView.findViewById(R.id.tv);
        textView.setText(data.get(position).getName());
        return convertView;
    }
}

在MyAdapter中重写了父类的构造方法,用于将context(上下文)和ListView子项的数据传递进来;然后又重写了getView()方法,这个方法是在listView中每个子项滚动到屏幕中时就会调用,在这个方法中通过LayoutInflater.from()方法加载listView子项的布局,并且设置textView需要显示的文本内容。
4. 最后在MainActivity中修改代码,通过setAdapter()方法将创建好的适配器对象传递进去,建立ListView和数据之间的关联。

public class MainActivity extends AppCompatActivity {

    private List data=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Bean bean=new Bean();
            bean.setName("hello world"+i);
            data.add(bean);
        }
        ListView listView=findViewById(R.id.listView);
        listView.setAdapter(new MyAdapter(data,this));
    }
}

当然这个只显示一个TextView的ListView比较简单,可以更为简单的实现(直接使用ArrayAdapter)
修改MainActivity中的代码:

public class MainActivity extends AppCompatActivity {

    private List data=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Bean bean=new Bean();
            bean.setName("hello world"+i);
            data.add(bean);
        }
        ArrayAdapter adapter=new ArrayAdapter(this,android.R.layout.simple_list_item_1,data);
        ListView listView=findViewById(R.id.listView);
        listView.setAdapter(adapter);
    }
}

这里的android.R.layout.simple_list_item_1是Android内置的一个布局文件,里面只有一个Textview,当然也可以使用我们创建的list_item.xml,最后实现的效果是相同的。

1.2 ListView的优化

我们可以分析一下baseAdapter中的getView()方法,每次都要重新绘制子项view和通过findViewById()方法来获取控件。

  1. 通过对getView()方法的观察,convertView这个参数我们只是粗略的使用,并没有发挥它的效果,convertView这个参数时用于将之前加载好的布局进行缓存,这样我们就可以通过判断convertView是否为null,如果为null,在调用LayoutInflater来进行绘制View,如果不为null,就可以直接复用。
public class MyAdapter extends baseAdapter {

    private List data;
    private Context mContext;

    public MyAdapter(List data, Context mContext) {
        this.data = data;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        MyViewHolder viewHolder;
        if(convertView ==null){
            convertView=LayoutInflater.from(mContext).inflate(R.layout.list_item,parent,false);
            viewHolder=new MyViewHolder();
            viewHolder.textView=convertView.findViewById(R.id.tv);
            convertView.setTag(viewHolder);
        }else{
            viewHolder= (MyViewHolder) convertView.getTag();
        }
        viewHolder.textView.setText(data.get(position).getName());
        return convertView;
    }

   class MyViewHolder{
        TextView textView;
   }
}

2.在MyAdapter中我们新建了一个MyViewHolder类(见名思意,就是view的持有者),用于对控件的实例进行缓存,当convertView 为null时,创建一个viewHolder对象,并将控件的实例都存放在该对象中,然后通过view.setTag()方法,将viewHolder对象存储在convertView 中,当convertView 不为null时,通过view的getTag()方法取出viewHolder对象,这样就不用每次都通过findViewById来获取控件的实例了,同时也大大提高的ListView的运行效率。

1.3 ListView的点击事件

ListView的点击事件主要通过setOnItemClickListener方法实现

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Bean bean=new Bean();
            bean.setName("hello world"+i);
            data.add(bean);
        }
        ListView listView=findViewById(R.id.listView);
        listView.setAdapter(new MyAdapter(data,this));
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                Toast.makeText(MainActivity.this,data.get(position).getName(),Toast.LENGTH_LONG)
                .show();
            }
        });
    }

当我们进行点击的时候通过position判断出我们点击的是哪一项,这里用Toast进行显示。

2.RecyclerView

上面介绍了ListView的简单使用和性能优化,接下来介绍一下一个更为强大的控件RecyclerView,并且Android官方也更加推荐使用RecyclerView。

2.1 RecyclerView的简单使用
  1. 将上方activity_main中的listView替换为RecyclerView。



    


  1. 修改MyAdapter继承自RecyclerView.Adapter,并且新建一个内部类ViewHolder继承自RecyclerView.ViewHolder
public class MyAdapter extends RecyclerView.Adapter {

    private List data;
    private Context mContext;

    public MyAdapter(List data, Context mContext) {
        this.data = data;
        this.mContext = mContext;
    }

    @NonNull
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(mContext).inflate(R.layout.recycler_item,parent,false);
        ViewHolder holder=new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
        holder.textView.setText(data.get(position).getName());
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            textView=itemView.findViewById(R.id.recycler_text);
        }
    }
}

重写的三个方法:

  1. onCreateViewHolder:这个方法是用于创建ViewHolder实例的,在这个方法中通过LayoutInflater绘制recycler_item(recyclerview的item布局),然后创建viewHolder实例并且将绘制的view加载到viewholder中去。
  2. onBindViewHolder:这个方法就类似于ListView中的getView()方法,会在每个item滚动到屏幕中时执行,通过position得到当前项的数据,然后在设置到viewHolder保存的控件实例中
  3. getItemCount:返回recyclerView子项的个数
  1. 修改MainActivity中的代码
public class MainActivity extends AppCompatActivity {

    private List data=new ArrayList<>();
    private RecyclerView mRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Bean bean=new Bean();
            bean.setName("hello world"+i);
            data.add(bean);
        }
        mRecyclerView=(RecyclerView) findViewById(R.id.recyclerView);
        LinearLayoutManager manager=new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(manager);
        mRecyclerView.setAdapter(new MyAdapter(data,this));
    }
}

LayoutManager用于指定RecyclerView的布局,我们在这里使用的是LinearLayoutManager (线性布局管理器),所以实现效果和ListView相同。

2.2 实现网格布局和瀑布流布局
  1. 网格布局其实非常简单,只要改变我们所使用的布局管理器就行了,这里使用GridLayoutManager
    修改MainActivity中的代码:
 mRecyclerView=(RecyclerView) findViewById(R.id.recyclerView);
 		//第二个参数代表网格布局用几列进行显示
        GridLayoutManager manager=new GridLayoutManager(this,4);
        mRecyclerView.setLayoutManager(manager);
        mRecyclerView.setAdapter(new MyAdapter(data,this));


2. 瀑布流布局也是如此

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=1;i<=50;i++){
            Random random=new Random();
            int length=random.nextInt(20)+1;
            StringBuilder builder=new StringBuilder();
            for(int j=0;j 

在这里使用了StaggeredGridLayoutManager ,两个参数分别是:列数;排列方向。
为了更直观的可以看出瀑布流和网格布局的差别(需要每个子项的高度不一样才能看出来),在这里使用了random函数,随机的将参数中传入的字符串重复N遍。

2.3 点击事件

RecyclerView和ListView不同,RecyclerView没有提供Item的点击事件,所以需要我们自己进行设置。

  1. 在onBindViewHolder方法中通过setOnClickListener实现
    @Override
    public void onBindViewHolder(@NonNull @org.jetbrains.annotations.NotNull MyAdapter.MyViewHolder holder, int position) {
        holder.textView.setText(data.get(position).getName());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context,"你点击了第"+position+"项",Toast.LENGTH_SHORT).show();
            }
        });
        holder.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context,"你点击了第"+position+"项",Toast.LENGTH_SHORT).show();
            }
        });
    }

通过 holder.itemView设置的点击事件是RecyclerView单个子项整体的点击事件,而通过holder.textView设置的点击事件是Item子项的点击事件;比如list_item中有button和textView时,可以通过这个方法分别设置button和textView的点击事件。
2. 通过接口回调的方式进行实现
(1)在MyAdapter中定义一个接口,专门用于设置点击事件

public interface OnItemListener{
        void onItemClick(View view,int position);
    }

(2)定义这个接口的set方法并且声明变量,便于调用

private OnItemListener mListener;

    public void setOnItemClickListener(OnItemListener listener){
        this.mListener=listener;
    }

(3)在onBindViewHolder中设置点击事件

    @Override
    public void onBindViewHolder(@NonNull @org.jetbrains.annotations.NotNull MyAdapter.MyViewHolder holder, int position) {
        holder.textView.setText(data.get(position).getName());
        holder.imageView.setImageResource(data.get(position).getImageId());
        //根布局的点击事件
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mListener!=null){//判断是否设置了监听
                    //通过holder.getAdapterPosition()获取当前item的位置
                    mListener.onItemClick(holder.itemView, holder.getAdapterPosition());
                    
                }

            }
        });
        //item子view的点击事件
        holder.textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mListener!=null){//判断是否设置了监听
                    //通过holder.getAdapterPosition()获取当前item的位置
                    mListener.onItemClick(holder.textView, holder.getAdapterPosition());

                }
            }
        });
    }

(4)在MainActivity中设置点击事件的具体效果(通过调用adapter中的setOnItemClickListener)

 myAdapter.setOnItemClickListener(new MyAdapter.OnItemListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this,"点击了第"+position+"项",Toast.LENGTH_SHORT).show();
            }
        });

这样就可以实现RecyclerView的点击事件了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/353592.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号