安卓 recycler view
recycler view
recycler view通常用于展示一组数据。比如音乐播放列表里,这个页面需要展示一组歌曲的信息。每一行展示一首歌,里面可能有一张图片放专辑海报,有歌曲名,有歌手姓名。由于歌曲很多,手机屏幕装不下,就需要使用户能够向下滑动。
通常对于固定长度的信息(比如注册页面用户需要填写很多信息)设计允许滑动的用户界面,我们可以用scrollview. 但是如果信息内容过多且变动频繁,那我们可以选择RecyclerView来展示。
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="false">
</ScrollView>
scrollview 解决固定屏幕大小不够展示所有信息的问题,而RecyclerView除了具备这个功能,还可以对需展示的数据内容的变更动态处理,它是有几个组件协作来完成的数据展示。首先,RecyclerView使用一个适配器,从数据源中提取内容,并将其输入到列表中。然后我们需要知道,它通过一个布局管理器(比如LinearLayoutManager或GridLayoutManager)来填充自身试图。这个布局管理器会负责把数据源中的对象们放置在RecyclerView中,并决定RecyclerView中哪些对象的view被显示,哪些不可见。这个布局管理器与你RecyclerView放置于哪个布局文件没有关系(底层布局文件可能是任意的layout),它只管理RecyclerView内部的信息展示。
数据源中集合里的每一个对象,需要被一个ViewHolder对象表示,我们可以把它理解为一个容器。我们需要定义一个类,来继承RecyclerView.ViewHolder. 每一个ViewHolder对象展示数据源集合里的一个view。view holder对象被适配器管理。我们需要编写一个适配器的类,继承RecyclerView.Adapter. 适配器会为数据源中每一个对象,生成一个容器view holder,我们可以想象成一个小卡片。针对列表里的歌曲(数据源list),适配器会给每首歌(数据源中的单个对象object)一张小卡片(view holder)在上面画上一个专辑海报,写出歌曲名和歌手名,然后把小卡片放在可滑动查看的容器内(RecyclerView)。适配器有一个功能(也就是方法)叫onBindViewHolder(RecyclerViewAdapter.ViewHolder viewHolder, int position),会根据卡片(viewHolder)的在排列中的位置来决定是否展示该卡片信息。除夕之外,RecyclerView还有notifyItemChanged,notifyItemInserted等方法对展示内容进行修改。
使用方法
使用RecyclerView,首先我们要添加对应的依赖,然后在布局文件中放置一个RecyclerView对象。
标题添加依赖
implementation 'androidx.recyclerview:recyclerview:1.1.0'
底层布局文件
放置recycler view的xml文件。
<?xml version="1.0" encoding="utf-8"?>
<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
view
recycler view 里通常是把很多对象的信息以某种共同的形式展现出来,所以我们使用的时候新创建一个view的xml文件,用于定义每个对象相关信息的展现格式。以下是一个简单的例子,每个学生对象有姓名和年龄两个属性,用以下view(这里我的文件命名为card.xml)展示出学生的信息。除了学生的两个属性,最后还有个叉号用来删除其对应的对象。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/singer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView
android:id="@+id/iv_item_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="8dp"
android:src="@android:drawable/ic_menu_close_clear_cancel"
android:tint="@android:color/holo_red_dark" />
</LinearLayout>
自定义适配器
为每一个数据对象创建一个view(根据我们刚刚定义的view模板card.xml)
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Song> mDataset;
// Provide a reference to the views for each data item
// you provide access to all the views for a data item in a view holder
public static class MyViewHolder extends RecyclerView.ViewHolder {
public TextView nameTextView;
public TextView singerTextView;
public ImageView imageView;
public MyViewHolder(TextView v) {
super(v);
nameTextView = v.findViewById(R.id.name);
singerTextView = v.findViewById(R.id.singer);
imageView = v.findViewById(R.id.my_recycler_view);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(List<Song> myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
@Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the view from an XML layout file
View songView = inflater.inflate(R.layout.card, parent, false); // construct the viewholder with the new view
ViewHolder viewHolder = new ViewHolder(songView);
return viewHolder;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final Song song = mDataset.get(position);
TextView tvName = holder.nameTextView;
TextView tvSinger = holder.singerTextView;
ImageView ivDelete = holder.imageView;
tvName.setText(song.getName());
tvSinger.setText(song.getSinger());
ivDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
songs.remove(song);
notifyDataSetChanged();
}
});
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return mDataset.length;
}
}
activity
public class MyActivity extends Activity {
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
private List<Song> myDataset;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true);
// use a linear layout manager
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
// 这里大家自定义下数据集合
// specify an adapter (see also next example)
mAdapter = new MyAdapter(myDataset);
recyclerView.setAdapter(mAdapter);
}
// ...
}
(详情请参考安卓官网开发手册)