RecyclerView + SQLite 简易备忘录-----中(2)
阅读原文时间:2023年07月08日阅读:7

(3)RecyclerView的实现 ---中间的内容

RecyclerView是一个比ListView更加强大的滚动控件。要使用这个控件需要先在项目的build.gradle中添加RecyclerView库的依赖。这个内容在第一节就讲过,此处按下不表。
然后在布局文件中加入RecyclerView的控件。---->然后新建一个布局文件recycler_item.xml,在这里写RecyclerView的子项布局。
以上布局步骤在前面的小节中已经讲过。现在看看他们的具体实现。

上一节代码讲到:

adapter = new MemoAdapter(MainActivity.this,arr);
StaggeredGridLayoutManager st = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(st);
recyclerView.setAdapter(adapter);

MemoAdapter是一个备忘录适配器,通过这个适配器将arr集合中的数据和RecyclerView联系起来。
怎么联系的呢?
先来看看MemoAdapter这个类。

该类有一个构造方法,三个重写方法,一个内部类,一条注解和一个自定义方法setFiler(List filterList)。

先看构造方法

//构造器,第一个参数是上下文,第二个参数是传入的带有备忘录所有数据的集合
public MemoAdapter(Context mcontext, List arr) {
this.mcontext = mcontext;
this.arr = arr;
}

来看内部类:

/*该内部类继承RecyclerView.ViewHolder。然后在ViewHolder的主构造方法中传入一个View参数,
这个参数通常就是RecyclerView子项的最外层布局。
通过这个最外层布局的参数,那么我们就可以通过findViewById()方法来获取布局中各组件的实例了。*/
public class ViewHolder extends RecyclerView.ViewHolder{
TextView item_title,item_content,item_time;
ImageView item_img;
LinearLayout item_layout;
public ViewHolder(@NonNull View itemView) {
super(itemView);
item_title = itemView.findViewById(R.id.item_title);
item_content = itemView.findViewById(R.id.item_content);
item_time = itemView.findViewById(R.id.item_time);
item_img = itemView.findViewById(R.id.item_image);
item_layout = itemView.findViewById(R.id.item_layout);
}
}

来看onCreateViewHolder()方法:第一个参数是要创建的View的父View,第二个参数是要创建的这个View类型。

@NonNull
@Override //该方法是用于创建ViewHolder的实例.
// 在这个布局中将子项布局recycler_item加载进来,然后创建一个ViewHolder的实例,并把加载出来的布局传入构造函数当中,最后将ViewHolder的实例返回。
public MemoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mcontext).inflate(R.layout.recycler_item,parent,false);
ViewHolder mholder = new ViewHolder(view);
return mholder;
}

使用LayoutInflater来将recycler_item这个子项加载进来。它的inflate()方法接收三个参数。
第一个参数是:要加载布局文件的id。
第二个参数是:给加载好的布局中添加一个父布局。
第三个参数指定为false,表示只让我们在父布局中声明的layout属性生效,但不会为这个View添加父布局。

来看onBindViewHolder()方法:第一个参数是一个ViewHolder,第二个是位置参数。

@Override //该方法用于对RecyclerView子项的数据复制,会在每个子项被滚动到屏幕内的时候执行
public void onBindViewHolder(@NonNull MemoAdapter.ViewHolder mholder, int position) {
final MemoBean memoBean = arr.get(position);
mholder.item_title.setText(memoBean.getTitle());
mholder.item_content.setText(memoBean.getContent());
mholder.item_time.setText(memoBean.getTime());
Glide.with(mcontext).load(memoBean.getImgpath()).into(mholder.item_img);
if(memoBean.getImgpath() ==null){ //如果图片地址为空,则不显示图片
// Toast.makeText(mcontext,"memoBean.getImgpath()"+memoBean.getImgpath(),Toast.LENGTH_LONG).show();
mholder.item_img.setVisibility(View.GONE);
}
/* 以上代码都是对子项的数据进行赋值,每个子项被滚动到屏幕的时候的时候执行。 */

//长按删除  
mholder.item\_layout.setOnLongClickListener(new View.OnLongClickListener() {  
    @Override  
    public boolean onLongClick(View view) {  
        AlertDialog.Builder dialog = new AlertDialog.Builder(mcontext); //弹出一个AlertDialog进行确认。  
        dialog.setMessage("确定删除吗?");  
        dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() { //如果点击确认,就从数据库里删除,并从arr集合中移出,然后刷新该页面。  
            @Override  
            public void onClick(DialogInterface dialogInterface, int i) {  
                myDbHelper = new MyDbHelper(mcontext);  
                database = myDbHelper.getWritableDatabase();  
                database.delete("tb\_memory","\_id=?",new String\[\]{arr.get(position).getId()}); //从数据库里删除  
                arr.remove(position); //从arr集合中移出  
                Toast.makeText(mcontext,"删除成功",Toast.LENGTH\_LONG).show();  
                notifyItemChanged(position); //然后刷新该页面,局部刷新,还有其他的刷新方法,这里不讲  
                dialogInterface.dismiss();   
            }  
        });  
        dialog.setNegativeButton("取消",null);  
        dialog.setCancelable(false);  
        dialog.create();  
        dialog.show();  
        return false;  
    }  
});  

//点击显示  
mholder.item\_layout.setOnClickListener(new View.OnClickListener() {  //如果对子项进行点击,就启动AddInfoActivity,这里我们将该子项的id一起传入AddInfoActivity,因为我们还要在AddInfoActivity中进行判断。  
    @Override                            //判断什么?在AddInfoActivity中,如果该id存在,那么我们就将该id的内容显示到页面中。如果不存在,那应当是从悬浮按钮点击进入的该Activity,则显示添加页面。  
    public void onClick(View view) {  
        Intent intent = new Intent(mcontext, AddInfoActivity.class);  
        intent.putExtra("\_id",arr.get(position).getId());  
        Toast.makeText(mcontext,"\_id"+arr.get(position).getId(),Toast.LENGTH\_LONG).show();  
        startActivity(intent);  
    }  
});  

}

来看getItemCount()方法:

public int getItemCount() {
return arr.size();
}
很简单,没啥好说的。

来看ViewHolder这个内部类:

/*该内部类继承RecyclerView.ViewHolder。然后在ViewHolder的主构造方法中传入一个View参数,
这个参数通常就是RecyclerView子项的最外层布局。
通过这个最外层布局的参数,那么我们就可以通过findViewById()方法来获取布局中各组件的实例了。*/
public class ViewHolder extends RecyclerView.ViewHolder{
TextView item_title,item_content,item_time;
ImageView item_img;
LinearLayout item_layout;
public ViewHolder(@NonNull View itemView) {
super(itemView);
item_title = itemView.findViewById(R.id.item_title);
item_content = itemView.findViewById(R.id.item_content);
item_time = itemView.findViewById(R.id.item_time);
item_img = itemView.findViewById(R.id.item_image);
item_layout = itemView.findViewById(R.id.item_layout);
}
}

来看setFiler(List filterList)方法:
接收一个MemoBean类型的集合,该集合为过滤后的数据,将该集合直接赋值给arr,再刷新界面。
就成功的将搜索的数据展示了出来。

//该方法用于搜索时过滤数据。
public void setFiler(List filterList){
arr = filterList;
notifyDataSetChanged();
}
以上就是MemoAdapter的全部内容。
好的,再回到MainActivity的那段代码:
adapter = new MemoAdapter(MainActivity.this,arr);
StaggeredGridLayoutManager st = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(st);
recyclerView.setAdapter(adapter);
在这里新建了一个MemoAdapter的适配器adapter。
下一句代码StaggeredGridLayoutManager是什么?
RecyclerView给我们内置了两种布局排列方式:GirdLayoutManager 网格布局
和 StaggeredGridLayoutManager 瀑布流布局

StaggeredGridLayoutManager(布局的列数,布局的排列方向)。

StaggeredGridLayoutManager.VERTICAL表示会让布局纵向排列。

所以recyclerView.setLayoutManager(st);的意思是:指定布局方式为:纵向排列的两行。

最后通过recyclerView.setAdapter(adapter);的方法完成适配器的设置。
(4)SearchView的实现 ---搜索功能
现在我们来看看搜索功能的完整实现。
SearchView是搜索框组件,它可以让用户在文本框内输入汉字,并允许通过监听器监控用户输入,当用户用户输入完成后提交搜索按钮时,也通过监听器执行实际的搜索。
有一个常用的方法setOnQueryTextListener(SearchView.OnQueryTextListener listener):为该搜索框设置事件监听器。我们只需通过该方法即可实现搜索功能。
1.首先,通过绑定控件msearch = findViewById(R.id.search);的方式获取到SearchView组件的对象。
2.继承OnQueryTextListener接口,并实现里面的两个方法。

onQueryTextSubmit(String s):单击搜索按钮时激发该方法。

onQueryTextChange(String s):用户输入字符时激发该方法。

在该方法中调用filter(s)方法。s为用户输入的字符串。

来看看filter(String text)方法:

private List filter(String text){
filterS = new ArrayList<>();
for(MemoBean memoBean:arr){
if(memoBean.getTitle().contains(text) || memoBean.getContent().contains(text) || memoBean.getTime().contains(text)){
filterS.add(memoBean);
}
}
return filterS;
}
很简单的逻辑,新建了一个MemoBean类型的集合,用于存符合搜索条件的数据,并将其返回。
用for循环遍历arr集合。这个集合里有备忘录的所有内容。如果用户输入的内容 是 集合里的标题,或者内容,或者时间的子字符串,就将该条数据添加给filterS。

回到@Override
public boolean onQueryTextChange(String s) {
filterS = filter(s);
adapter.setFiler(filterS);
return false;
}
现在我们的filterS里装满了符合搜索条件的数据,通过适配器里的setFiler(filterS)方法将页面刷新,将结果显示出来。

2.直接msearch.setOnQueryTextListener(this);

效果图:

(5)FAB的实现 ----悬浮按钮

这个组件已经在前面讲过了。
再看下布局代码:

然后在MainActivity中实现点击跳转就好了:

private void btnOnClicknext(){
btn_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,AddInfoActivity.class);
startActivity(intent);
finish();
}
});
}

跳转后,启动AddInfoActivity,进入添加备忘录的页面。

-------
源码:https://github.com/Xiang-MY/MemoDemo

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器