Android常见结构控件(四)
https://i-blog.csdnimg.cn/direct/1e33417ce4e94c03a200926baf506ccf.gif目次
前言
RecyclerView控件
数据适配器
结构管理器
使用RecyclerView
创建XML结构文件
创建ReActivity类
创建数据适配器
onCreateViewHolder
onBindViewHolder
完整代码
补充知识
ItemDecoration
前言
在前一篇中,我们讲解了ListView控件,那么本篇我们就来讲解RecyclerView控件
RecyclerView控件
与ListView类似,RecyclerView控件同样也是以列表的形式将数据进行展示,都是为了维护少量的View来进行显示大量的数据。是在android5.0之后新添的控件,用来替代传统的ListView和GridView控件的。
与传统的ListView不同,RecyclerView能通过LayoutManager类来实现横向或者竖向的列表效果、瀑布流效果和GridView效果,而ListView只能实现竖直的列表效果。
格式如下:
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"/> 我们 可以通过在Patale中找到RecylcerView,将其拉到XML文件中
https://i-blog.csdnimg.cn/direct/1e606cbad5b644f09e2e145dc5143794.png
当然,我们也可以手动添加:
https://i-blog.csdnimg.cn/direct/f5a0ec90294f44d4ba937ac1fbabfabd.png
数据适配器
RecyclerView控件使用的是RecyclerView.Adapter,该数据适配器将BaseAdapter中的getView()方法拆解为onCreateViewHolder()方法和onBindViewHolder()方法,强制使用ViewHolder类,使代码更加规范化。
结构管理器
LayoutManager结构管理器用来设置每一项view在RecyclerView中的位置结构,以及控件item view的显示或隐藏。当View重用或者回收的时候,LayoutManager都会向Adapter来请求新的数据进行替换原来的数据的内容。这种回收复用机制可以提供性能,克制创建许多的view或者是频仍的调用findViewById()方法。
RcyclerView提供了三种内置的LayoutManager:
[*]LinearLayoutManager:线性结构,横向或者纵向滑动列表
[*]GridLayoutManager:网格结构
[*]StaggerdGridLayoutManager:流式结构,如瀑布流效果。
当然,我们也可以通过继续RecyclerView.LayoutManager来实现一个自界说的LayoutManager。
Animations(动画)效果:
[*]RecyclerView对于Item的添加和删除是默认开启动画的,我们也可以通过RecyclerView.ItemAnimator类来定制动画,再通过RecyclerView.setItemAnimator()方法来使用
以下是RecyclerView的一些相关类:
类名阐明RecyclerView.Adapter可以托管数据集合,为每一项Item创建视图并且绑定数据RecyclerView.ViewHolder承载Item视图的子结构RecyclerView.LayoutManager负责Item视图的结构的显示管理RecyclerView.ItemDecoration给每一项Item视图添加子View,例如进行画分割线等RecyclerView.ItemAnimator负责处理数据添加或者删除时候的动画效果 使用RecyclerView
创建XML结构文件
这里我选择创建一个名为recycle_list.xml的结构文件。
这里我们选择模仿聊天的界面,那么起首我们需要实现一个聊天的界面,就在上面创建的结构中实现。效果图如下:
https://i-blog.csdnimg.cn/direct/d1aa0b6260f74ba3a92888241a2cfb70.png
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp">
<ImageView
android:id="@+id/tv"
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_name"
android:text="李四"
android:textStyle="bold"
android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/news"
android:text="李四,你今天在干嘛呢?"
android:textSize="15sp"
android:layout_marginTop="15sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:id="@+id/tv_time"
android:gravity="end"
android:text="24/8/25\n12:00"
android:textColor="#999999"
android:textSize="15sp"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="match_parent"/>
</LinearLayout> 同时,我们可以创建一个recycle_main.xml结构用来显示聊天界面,在其中放入RecyclerView控件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout> 创建ReActivity类
我们既然已经把结构文件做好,那么现在就是有关java的代码了,我们需要创建一个ReActivity类,在里面来进行绑定结构文件等操作。
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
public class ReActivity extends AppCompatActivity {
private RecyclerView recyclerView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycle_main);
Init();
}
private void Init() {
recyclerView = findViewById(R.id.recyclerView);//初始化recyclerView
}
}
创建数据适配器
在上面,我们已经把聊天的界面以及RecyclerView控件创建出来了,那么接下来我们就来自界说一个适配器继续RecyclerView.Adapter来创建item view以及绑定数据.
onCreateViewHolder
步调:
[*]创建适配器类继续RecyclerView.Adapter,传入泛型
[*]创建内部类即RecyclerView.ViewHolder的子类,并初始化item控件。
[*]重写RecyclerView.Adapter类的相关方法。
这里我们使用View.inflate来加载v,并将v传给内部类MyAdapter(本身实现)继续实例化。
private View v;
private MyAdapter myAdapter;
@NonNull
@Override
public MyAdapter onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
v = View.inflate(ReActivity.this,R.layout.recycle_list,null);
myAdapter = new MyAdapter(v);
return myAdapter;
}
这里创建一个内部类MyAdapter继续ViewHolder,绑定传进来的v的控件。
class MyAdapter extends RecyclerView.ViewHolder {
TextView name, news, time;
ImageView image;
public MyAdapter(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.tv_name);
news = itemView.findViewById(R.id.news);
time = itemView.findViewById(R.id.tv_time);
}
} onBindViewHolder
[*]将获取到的数据设置到对应的控件上。
[*]传入类的holder和position
position相当于下标,既然需要获取类的数据,那么我们需要一个构造方法来初始化类的数据
private final Context context;
private final ArrayList nameList,timeList,newsList;
public Adapter(Context context, ArrayList nameList, ArrayList newsList, ArrayList timeList){
this.context = context;
this.nameList = nameList;
this.newsList = newsList;
this.timeList = timeList;
}
到这,我们已经把自界说的适配器Adapter实现完成,完整代码:
/**
* RecyclerView的适配器类
*/
class Adapter extends RecyclerView.Adapter<Adapter.MyAdapter> {
private Context context;
private ArrayList nameList, newsList, timeList;
/**
* Adapter构造方法
* @param context 上下文环境,此处为ReActivity实例
* @param nameList 名称数据列表
* @param newsList 消息数据列表
* @param timeList 时间数据列表
*/
public Adapter(Context context, ArrayList nameList, ArrayList newsList, ArrayList timeList){
this.context = context;
this.nameList = nameList;
this.newsList = newsList;
this.timeList = timeList;
}
/**
* 创建ViewHolder
* @param parent 父容器,用于容纳RecyclerView项视图
* @param viewType 视图类型,此处未使用
* @return 创建的ViewHolder实例
*/
@NonNull
@Override
public MyAdapter onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = View.inflate(ReActivity.this,R.layout.recycle_list,null); // 加载RecyclerView项布局文件
MyAdapter myAdapter = new MyAdapter(v); // 创建ViewHolder
return myAdapter;
}
/**
* 绑定ViewHolder数据
* @param holder ViewHolder实例,用于展示数据
* @param position 数据源中的位置
*/
@Override
public void onBindViewHolder(@NonNull MyAdapter holder, int position) {
holder.name.setText(nameList.get(position).toString()); // 设置名称文本
holder.news.setText(newsList.get(position).toString()); // 设置消息文本
holder.time.setText(timeList.get(position).toString()); // 设置时间文本
}
/**
* 返回数据源中项的数量
* @return 数据源大小
*/
@Override
public int getItemCount() {
return nameList.size();
}
/**
* RecyclerView ViewHolder子类
*/
class MyAdapter extends RecyclerView.ViewHolder {
TextView name, news, time;
ImageView image;
/**
* MyAdapter构造方法,用于初始化ViewHolder中的视图组件
* @param itemView RecyclerView项的根视图
*/
public MyAdapter(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.tv_name); // 初始化名称文本视图
news = itemView.findViewById(R.id.news); // 初始化消息文本视图
time = itemView.findViewById(R.id.tv_time); // 初始化时间文本视图
}
}
} 接下来,我们就在我们界说的Init()方法中来实例化这些类以及调用相关的方法。
[*]起首实例化存储数据的三个ArrayList,分别存储用户名,信息,时间。并模仿天生一些数据。
[*]创建Adapter对象并将上面三个ArratList传入
[*]创建线性结构管理器,并给前面的rercyclerView设置结构为线性结构。
[*]给rercyclerView设置每一项的动画,并且设置分割线和适配器
/**
* 初始化方法,用于初始化RecyclerView组件及适配器
*/
private void Init() {
recyclerView = findViewById(R.id.recyclerView); // 初始化RecyclerView组件
// 初始化存储数据的ArrayList
ArrayList names = new ArrayList();
ArrayList newsList = new ArrayList();
ArrayList timeList = new ArrayList();
// 循环生成模拟数据
for(int i=0;i<50;i++){
names.add("00"+i);
newsList.add("你今天在干嘛呢?");
timeList.add("2020-01-01 \n15:"+i);
}
// 创建Adapter实例并传入数据源
Adapter adapter = new Adapter(this ,names,newsList,timeList);
// 创建LinearLayoutManager实例,用于管理RecyclerView的布局
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager); // 设置RecyclerView的布局管理器
recyclerView.setItemAnimator(new DefaultItemAnimator()); // 设置RecyclerView的项动画
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL)); // 添加分割线装饰
recyclerView.setAdapter(adapter); // 设置RecyclerView的适配器
} 完整代码
ReActivity.java
import android.content.Context;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.TextView;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import androidx.appcompat.app.AppCompatActivity;import androidx.recyclerview.widget.DefaultItemAnimator;import androidx.recyclerview.widget.DividerItemDecoration;import androidx.recyclerview.widget.LinearLayoutManager;import androidx.recyclerview.widget.RecyclerView;import java.util.ArrayList;// ReActivity类继续自AppCompatActivity,用于展示RecyclerView实现的列表界面public class ReActivity extends AppCompatActivity { // 声明RecyclerView对象 private RecyclerView recyclerView; /** * onCreate方法,在活动创建时调用 * @param savedInstanceState 大概存在的保存实例状态Bundle,此处为可空 */ @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.recycle_main); // 设置活动的结构文件 Init(); // 初始化组件和数据 } /**
* 初始化方法,用于初始化RecyclerView组件及适配器
*/
private void Init() {
recyclerView = findViewById(R.id.recyclerView); // 初始化RecyclerView组件
// 初始化存储数据的ArrayList
ArrayList names = new ArrayList();
ArrayList newsList = new ArrayList();
ArrayList timeList = new ArrayList();
// 循环生成模拟数据
for(int i=0;i<50;i++){
names.add("00"+i);
newsList.add("你今天在干嘛呢?");
timeList.add("2020-01-01 \n15:"+i);
}
// 创建Adapter实例并传入数据源
Adapter adapter = new Adapter(this ,names,newsList,timeList);
// 创建LinearLayoutManager实例,用于管理RecyclerView的布局
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager); // 设置RecyclerView的布局管理器
recyclerView.setItemAnimator(new DefaultItemAnimator()); // 设置RecyclerView的项动画
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL)); // 添加分割线装饰
recyclerView.setAdapter(adapter); // 设置RecyclerView的适配器
} /**
* RecyclerView的适配器类
*/
class Adapter extends RecyclerView.Adapter<Adapter.MyAdapter> {
private Context context;
private ArrayList nameList, newsList, timeList;
/**
* Adapter构造方法
* @param context 上下文环境,此处为ReActivity实例
* @param nameList 名称数据列表
* @param newsList 消息数据列表
* @param timeList 时间数据列表
*/
public Adapter(Context context, ArrayList nameList, ArrayList newsList, ArrayList timeList){
this.context = context;
this.nameList = nameList;
this.newsList = newsList;
this.timeList = timeList;
}
/**
* 创建ViewHolder
* @param parent 父容器,用于容纳RecyclerView项视图
* @param viewType 视图类型,此处未使用
* @return 创建的ViewHolder实例
*/
@NonNull
@Override
public MyAdapter onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = View.inflate(ReActivity.this,R.layout.recycle_list,null); // 加载RecyclerView项布局文件
MyAdapter myAdapter = new MyAdapter(v); // 创建ViewHolder
return myAdapter;
}
/**
* 绑定ViewHolder数据
* @param holder ViewHolder实例,用于展示数据
* @param position 数据源中的位置
*/
@Override
public void onBindViewHolder(@NonNull MyAdapter holder, int position) {
holder.name.setText(nameList.get(position).toString()); // 设置名称文本
holder.news.setText(newsList.get(position).toString()); // 设置消息文本
holder.time.setText(timeList.get(position).toString()); // 设置时间文本
}
/**
* 返回数据源中项的数量
* @return 数据源大小
*/
@Override
public int getItemCount() {
return nameList.size();
}
/**
* RecyclerView ViewHolder子类
*/
class MyAdapter extends RecyclerView.ViewHolder {
TextView name, news, time;
ImageView image;
/**
* MyAdapter构造方法,用于初始化ViewHolder中的视图组件
* @param itemView RecyclerView项的根视图
*/
public MyAdapter(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.tv_name); // 初始化名称文本视图
news = itemView.findViewById(R.id.news); // 初始化消息文本视图
time = itemView.findViewById(R.id.tv_time); // 初始化时间文本视图
}
}
}} 结合前面的两个XML结构,运行即可得到:
https://i-blog.csdnimg.cn/direct/3081e4b3b2b84b8bb30cc02a8ed7a4dd.gif
补充知识
ItemDecoration
在使用RecyclerView的时候,如果我们想要设置分割线,那么我们可以通过ItemDecoration。例如:
DividerItemDecoration decoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);分割线
recyclerView.addItemDecoration(decoration); // 添加分割线装饰 https://i-blog.csdnimg.cn/direct/d4a6032583eb427d9502fe378b7e28dc.png
Item动画
在RecyclerView中提供了默认的IntemAnimator实现类: DefaulttemAnimator。我们可以借助该类帮我们实现一些动画。
DefaultItemAnimator animator = new DefaultItemAnimator();
animator.setAddDuration(1000);
animator.setRemoveDuration(1000);
recyclerView.setItemAnimator(animator); // 设置RecyclerView的项动画 在前面的基础上,在recycle_main.xml聊天界面的上部添加两个按钮(添加和删除)
<LinearLayout
android:layout_marginLeft="80dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/add"
android:text="添加Item"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/del"
android:text="删除Item"
android:layout_marginLeft="60dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout> 同时在ReActivity类中添加对应点击变乱(由于代码有改动,以是这里直接放全部代码):
package com.example.newapptext1;import android.content.Context;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.TextView;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import androidx.appcompat.app.AppCompatActivity;import androidx.recyclerview.widget.DefaultItemAnimator;import androidx.recyclerview.widget.DividerItemDecoration;import androidx.recyclerview.widget.LinearLayoutManager;import androidx.recyclerview.widget.RecyclerView;import java.util.ArrayList;// ReActivity类继续自AppCompatActivity,用于展示RecyclerView实现的列表界面public class ReActivity extends AppCompatActivity implements View.OnClickListener { // 声明RecyclerView对象 private RecyclerView recyclerView; private Adapter adapter; private ArrayList names; private ArrayList newsList; private ArrayList timeList; /** * onCreate方法,在活动创建时调用 * @param savedInstanceState 大概存在的保存实例状态Bundle,此处为可空 */ @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.recycle_main); // 设置活动的结构文件 Init(); // 初始化组件和数据 } /** * 初始化方法,用于初始化RecyclerView组件及适配器 */ private void Init() { recyclerView = findViewById(R.id.recyclerView); // 初始化RecyclerView组件 // 初始化存储数据的ArrayList names = new ArrayList(); newsList = new ArrayList(); timeList = new ArrayList(); // 循环天生模仿数据 for(int i=0;i<5;i++){ names.add("00"+i); newsList.add("你今天在干嘛呢?"); timeList.add("2020-01-01 \n15:"+i); } // 创建Adapter实例并传入数据源 adapter = new Adapter(this , names, newsList, timeList); // 创建LinearLayoutManager实例,用于管理RecyclerView的结构 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); // 设置垂直方向 recyclerView.setLayoutManager(linearLayoutManager); // 设置RecyclerView的结构管理器 DefaultItemAnimator animator = new DefaultItemAnimator();
animator.setAddDuration(1000);
animator.setRemoveDuration(1000);
recyclerView.setItemAnimator(animator); // 设置RecyclerView的项动画 DividerItemDecoration decoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);分割线
recyclerView.addItemDecoration(decoration); // 添加分割线装饰 recyclerView.setAdapter(adapter); // 设置RecyclerView的适配器 //添加点击变乱 findViewById(R.id.add).setOnClickListener(this); findViewById(R.id.del).setOnClickListener(this); } @Override public void onClick(View view) { // 判断点击的视图是否为添加按钮 if(view.getId()==R.id.add){ // 向列表中添加新的名字和消息,用于模仿新消息的到来 names.add(1,"新添"); newsList.add(1,"你在干嘛呢?"); timeList.add(1,"2020-01-01 \n15:00"); // 通知适配器插入新项,以便更新UI adapter.notifyItemInserted(1); } else if(view.getId()==R.id.del){ // 判断点击的视图是否为删除按钮 // 从名字、消息和时间列表中移除指定位置的元素,以模仿数据删除操作 names.remove(1); newsList.remove(1); timeList.remove(1); // 通知适配器移除项,以便更新UI adapter.notifyItemRemoved(1); } } /**
* RecyclerView的适配器类
*/
class Adapter extends RecyclerView.Adapter<Adapter.MyAdapter> {
private Context context;
private ArrayList nameList, newsList, timeList;
/**
* Adapter构造方法
* @param context 上下文环境,此处为ReActivity实例
* @param nameList 名称数据列表
* @param newsList 消息数据列表
* @param timeList 时间数据列表
*/
public Adapter(Context context, ArrayList nameList, ArrayList newsList, ArrayList timeList){
this.context = context;
this.nameList = nameList;
this.newsList = newsList;
this.timeList = timeList;
}
/**
* 创建ViewHolder
* @param parent 父容器,用于容纳RecyclerView项视图
* @param viewType 视图类型,此处未使用
* @return 创建的ViewHolder实例
*/
@NonNull
@Override
public MyAdapter onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = View.inflate(ReActivity.this,R.layout.recycle_list,null); // 加载RecyclerView项布局文件
MyAdapter myAdapter = new MyAdapter(v); // 创建ViewHolder
return myAdapter;
}
/**
* 绑定ViewHolder数据
* @param holder ViewHolder实例,用于展示数据
* @param position 数据源中的位置
*/
@Override
public void onBindViewHolder(@NonNull MyAdapter holder, int position) {
holder.name.setText(nameList.get(position).toString()); // 设置名称文本
holder.news.setText(newsList.get(position).toString()); // 设置消息文本
holder.time.setText(timeList.get(position).toString()); // 设置时间文本
}
/**
* 返回数据源中项的数量
* @return 数据源大小
*/
@Override
public int getItemCount() {
return nameList.size();
}
/**
* RecyclerView ViewHolder子类
*/
class MyAdapter extends RecyclerView.ViewHolder {
TextView name, news, time;
ImageView image;
/**
* MyAdapter构造方法,用于初始化ViewHolder中的视图组件
* @param itemView RecyclerView项的根视图
*/
public MyAdapter(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.tv_name); // 初始化名称文本视图
news = itemView.findViewById(R.id.news); // 初始化消息文本视图
time = itemView.findViewById(R.id.tv_time); // 初始化时间文本视图
}
}
}} 运行之后可以得到:
https://i-blog.csdnimg.cn/direct/607a3a42e7b240f38fcacac73401b5ce.gif
当然,尚有个革新功能,后面再跟各人讲。
以上就是本篇所有内容,如有不敷,欢迎指正~ https://i-blog.csdnimg.cn/direct/1a5fa8546f094609a75148e3dc6212fe.gif
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]