星期六,又是撸代码的一天
作为一个初级都算不上的小白,一步一个脚印的学吧,学一个记一个
今天记录的是RecyclerView
RecyclerView
简述
官方解释为:提供一个固定的View让有限的窗口显示一个大数据集。(抄的)
我的理解是,和ListView差不多的东西
ListView是什么,不知道
总之,它可以呈现一系列数据,呈现方式可以根据给的LayoutManager确定
瀑布流(StaggeredGridLayoutManager)
列表流 (LinearLayoutManager)
表格流(GridLayoutManager)
使用方式在下面的 绑定适配器
创建布局
添加 RecyclerView和每个list布局(偏新手向,选择性跳过)
第一步当然是在xml中添加,在Palette中找到RecyclerView,右键Add添加
又或者在布局中写入Recy选择
这时需要给RecyclerView添加id
android:id="@+id/recycler"
然后根据开发需求,创建一个xml文件,我这里命名为recy_list.xml
作为单个list的布局,我这里模仿聊天界面做了个xml
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#cccccc"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingRight="20dp"
android:paddingLeft="20dp">
<ImageView
android:id="@+id/head"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:src="@android:mipmap/sym_def_app_icon" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="小白"
android:textColor="@color/black"
android:textSize="16sp" />
<TextView
android:id="@+id/news"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="#666666"
android:text="今天搬了多少砖"/>
</LinearLayout>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="end"
android:textColor="#999999"
android:textSize="14sp"
android:text="2021年4月24日\n19:02:50"/>
</LinearLayout>
最后在Activity绑定等等一系列操作
public class MainActivity extends AppCompatActivity {
private RecyclerView recycler;//创建
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//初始化控件方法
}
private void initView() {
recycler = findViewById(R.id.recycler);//绑定RecyclerView
}
接下来进入重点,适配器
创建适配器
适配器Adapter,可以让开发者自定义recyclerview绑定的数据,通过上面创建的recy_list文件模板来创建一堆item
创建
- 创建一个Adapter类
- 继承RecyclerView的Adapte
- 泛型定义为Adapter的内部类MyHolder
具体是什么我也不知道,一堆复杂的词
大概就是这样
public class Adapter extends RecyclerView.Adapter<Adapter.MyHolder> {
@NonNull
@Override
public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(@NonNull Adapter.MyHolder holder, int position) {
}
@Override
public int getItemCount() {
return 0;
}
}
然后Alt+回车生成一堆Adapter的接口,同时MyHolder变红,这个不管它,先来看这三方法干啥的
onCreateViewHolder()
- 创建ViewHolder时的回调函数
- 传入 ViewGroup parent 和 int viewType
- 返回 MyHolder
MyHolder是list中每个item
这里使用LayoutInflater布局加载器来加载view,再将view传给内部类MyHolder用于实例化
private View view;//在外面定义一个view
@NonNull
@Override
public Adapter.MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
view = LayoutInflater.from(context)//实例化LayoutInflater
//传参 刚才创建的recy_list.xml
.inflate(R.layout.recy_list, parent, false);
Adapter.MyHolder myHolder= new Adapter.MyHolder(view);
return myHolder;
}
(要传contect,挖坑)
来说一下LayoutInflater,菜鸟教程的解释 LayoutInflater(布局服务)
然后创建一个内部类MyHolder,继承ViewHolder ,在里面加上刚才的xml中的控件并绑定
public class MyHolder extends RecyclerView.ViewHolder {
TextView name, news, time;
ImageView head;
public MyHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.name);
news = itemView.findViewById(R.id.news);
time = itemView.findViewById(R.id.time);
head = itemView.findViewById(R.id.head);
}
}
这时,第一个方法解决了!!
onBindViewHolder()
- 绑定ViewHolder时的回调函数
- 传入 自定义内部类的 holder 和 int position
激动人心的时候到了,终于绑定数据了
position
可以理解为list中item的下标,就像数组一样,每个item都有自己的标识
那数据怎么来,Adapter初始呗
新增构造方法,记得要传context,顺便加上成员变量
private Context context;
private ArrayList<String> nameList,newsList,timeList;
public Adapter(Context context, ArrayList nameList ,ArrayList newsList ,ArrayList timeList) {
this.context = context;
this.nameList = nameList;
this.newsList = newsList;
this.timeList = timeList;
}
然后在onBindViewHolder方法中写绑定,根据position来给各个控件设置
@Override
public void onBindViewHolder(@NonNull ButViewHolder holder, int position) {
//将数据和控件绑定
holder.name.setText(nameList.get(position));
holder.news.setText(newsList.get(position));
holder.time.setText(timeList.get(position));
}
就剩最后一个方法了
getItemCount()
没有传参,需要返回一个int
这个方法是控制创建item的条数,返回的就是条数
我这里直接给其中一个ArrayList的大小即可
@Override
public int getItemCount() {
return nameList.size();
}
三个方法搞定了,意味着这个简单的Adapter已经写完了
然后就是让RecyclerView绑定Adapter
绑定适配器
在Activity那边加一个方法,或者直接在onCreate里绑定
setRecyclerView();
创建假数据
ArrayList name = new ArrayList();
ArrayList news = new ArrayList();
ArrayList time = new ArrayList();
for (int i= 0;i<20;i++){
name.add("小白 " + i);
news.add("今天搬砖了?");
time.add("2021年4月24日\n19:17:04");
}
绑定适配器
//适配器
RecyclerAdapter adapter = new RecyclerAdapter(this,name,news,time);
//布局
LinearLayoutManager manager = new LinearLayoutManager(this);
//设置布局
recycler.setLayoutManager(manager);
//设置动画
recycler.setItemAnimator(new DefaultItemAnimator());
//设置适配器
recycler.setAdapter(adapter);
就这样搞定了,这时运行项目就可以了看见本文开头那个列表流的效果了
适配器调整
都写到这了,再写一点吧
区别显示的实现
假如要给某一条item换上不同的背景
这时就需要在onBindViewHolder中修改
通过position,拿到ArrayList的某个数据进行判断
然后设置这个holder的某个控件的属性即可
点击事件
都九点半了,六千字,好累,写目录时加了这个,想删又不想删,还是写完再回家吧
Adapter点击事件的实现,需要声明View.OnClickListener接口
修改Adapter类,声明View.OnClickListener接口,加上一个onClick方法
public class Adapter
extends RecyclerView.Adapter<Adapter.MyHolder>
implements View.OnClickListener{
@Override
public void onClick(View v) {}
}
想要点击不同的item时做一些不同的事,就又又又要修改onBindViewHolder
给itemView设置点击事件
@Override
public void onBindViewHolder(@NonNull ButViewHolder holder, int position) {
//将数据和控件绑定
holder.name.setText(nameList.get(position));
holder.news.setText(newsList.get(position));
holder.time.setText(timeList.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {}
});
}
就这样???
如果我想在Activity中设置点击事件呢,比如跳转页面这种情况
添加点击事件接口,传值嘛
你想要什么就传什么,比如我想要点击的item的name,就传个name
public interface OnItemClickListener {
void onItemClick(String name);
}
有接口,就要Activity那边实现,所以Adapter里新增一个方法
同时,接口里的方法需要传给成员变量
private OnItemClickListener mListener;
public void setOnItemClickListener(OnItemClickListener li) {
mListener = li;
}
最后在绑定中的点击事件中添加
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onItemClick(nameList.get(position));
}
});
这么说好像有些别扭
总结就是
- Adapter创建点击事件接口
- Activity实现接口
- 实现后的接口存入Adapter的成员变量
- 当点击item时,触发onBindViewHolder中设置的绑定事件
- 绑定事件执行的是 Activity中传给成员变量的方法
这时,点击事件已经完成,就这样吧,回家咯!
下次有时间写个加头或尾的文章类似于B站的独占一行方法
不要在意内容!!!
对本文有任何意见或疑问,或者认为其中说法有误,欢迎在评论区留言!!!
最后,转载请注明出处!!