Android MVVM框架使用(十二)记事本功能增强:视图类型、批量删除、搜索笔记

42 阅读8分钟

在activity_notebook.xml中增加data中的变量数据,因为需要通过xml去改变布局的图标,文字,文字颜色。

在这里插入图片描述

当触发批量删除时,首先修改标题:

在这里插入图片描述

其次隐藏掉浮动按钮:

在这里插入图片描述

最后在页面底部增加一个布局,这个布局里面是删除和多选:

<LinearLayout

android:layout_width="match_parent"

android:layout_height="?attr/actionBarSize"

android:layout_alignParentBottom="true"

android:background="@color/white"

android:gravity="center_vertical"

android:visibility="@{isBatchDeletion ? View.VISIBLE : View.GONE}">

<TextView

android:id="@+id/tv_delete"

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@mipmap/ic_delete"

android:gravity="center"

android:text="删除"

android:textColor="@color/black" />

<TextView

android:id="@+id/tv_all_selected"

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:drawableTop="@{isAllSelected ? ContextCompat.getDrawable(tvAllSelected.getContext(),R.mipmap.ic_all_selected) : ContextCompat.getDrawable(tvAllSelected.getContext(),R.mipmap.ic_all_select)}"

android:gravity="center"

android:text="@{isAllSelected ? 取消全选 : 全选}"

android:textColor="@{isAllSelected ? @color/purple_500 : @color/black}" />

图标去我的源码中拿,添加位置如下图所示:

在这里插入图片描述

现在是页面修改完了,还有item的布局中也需要改动,打开item_notebook.xml,增加变量数据代码:

在这里插入图片描述

这里你会看到我把这个item的点击事件去掉了,这部分代码我将会挪到NoteActivity中,因此这里要修改一下item_notebook.xml中的代码:

<variable

name="notebook"

type="com.llw.mvvm.db.bean.Notebook" />

<variable

name="isBatchDeletion"

type="Boolean" />

<RelativeLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_margin="@dimen/dp_4"

android:background="@drawable/shape_bg_white_radius_12"

android:foreground="?attr/selectableItemBackground"

android:padding="12dp">

<TextView

android:id="@+id/tv_title"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_toStartOf="@+id/iv_check"

android:ellipsize="end"

android:singleLine="true"

android:text="@{notebook.title}"

android:textColor="@color/black"

android:textSize="16sp" />

<TextView

android:id="@+id/tv_content"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@+id/tv_title"

android:layout_marginTop="4dp"

android:layout_toStartOf="@+id/iv_check"

android:ellipsize="end"

android:maxLines="3"

android:text="@{notebook.content}"

android:textSize="14sp" />

<ImageView

android:id="@+id/iv_check"

android:layout_width="24dp"

android:layout_height="24dp"

android:layout_alignParentEnd="true"

android:layout_centerVertical="true"

android:layout_marginStart="6dp"

android:src="@{notebook.select ? ContextCompat.getDrawable(ivCheck.getContext(),R.mipmap.ic_selected) : ContextCompat.getDrawable(ivCheck.getContext(),R.mipmap.ic_select)}"

android:visibility="@{isBatchDeletion ? View.VISIBLE : View.GONE}" />

还是老样子,图标去我源码里面拿。

③ 适配器修改

item布局改完了,下面是NotebookAdapter适配器。在这里插入图片描述

这里我去掉了之前写的点击事件内部类。

④ 修改删除方法

之前写的NotebookDao中的删除方法是删除单个笔记的,那如果要删除多个呢?这里我们改成动态参数就行了。

在这里插入图片描述

就在后面加三个点就行了,这个表示你一个笔记可以,多个笔记也行。下面修改NotebookRepository中的deleteNotebook方法的参数,

在这里插入图片描述

然后再修改NotebookViewModel中的deleteNotebook方法中的参数。

在这里插入图片描述

⑤ 列表处理

现在就只剩下NotebookActivity中的代码没写了,首先在NotebookActivity增加变量,代码如下:

//笔记适配器

private NotebookAdapter notebookAdapter;

//笔记列表

private final List mList = new ArrayList<>();

//是否为批量删除

private boolean isBatchDeletion = false;

//是否全选

private boolean isAllSelected;

实现页面的点击监听。

在这里插入图片描述

控件监听

在这里插入图片描述

重写onClick方法。

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.tv_delete:

break;

case R.id.tv_all_selected:

break;

default:

break;

}

}

这里针对页面中底部布局中的两个TextView的点击,一个用于删除,一个用于全选和取消全选。这两个按钮的处理事件先不管它,先弄别的,这里我们先修改一下onResume中的代码:

在这里插入图片描述

这里之前的代码,我写到一个方法里面去了,新建一个initList方法。

/**

  • 初始化列表

*/

private void initList() {

//适配器

notebookAdapter = new NotebookAdapter(mList);

//设置适配器

binding.rvNotebook.setAdapter(notebookAdapter);

binding.rvNotebook.setLayoutManager(mvUtils.getInt(Constant.NOTEBOOK_VIEW_TYPE) == 1 ?

new GridLayoutManager(context, 2) : new LinearLayoutManager(context));

//item点击事件

notebookAdapter.setOnItemClickListener((adapter, view, position) -> {

if (isBatchDeletion) {

//选中设备

mList.get(position).setSelect(!mList.get(position).isSelect());

notebookAdapter.notifyDataSetChanged();

//修改页面标题

changeTitle();

} else {

Intent intent = new Intent(NotebookActivity.this, EditActivity.class);

intent.putExtra("uid", mList.get(position).getUid());

startActivity(intent);

}

});

}

这里还有一个修改页面标题的方法,也就是说当你选择了笔记时会记录选择个数。

/**

  • 修改标题

*/

private void changeTitle() {

int selectedNum = 0;

for (Notebook notebook : mList) {

if (notebook.isSelect()) {

selectedNum++;

}

}

Log.e(TAG, "changeTitle: " + selectedNum);

binding.tvTitle.setText("已选择 "+ selectedNum +" 项");

binding.setIsAllSelected(selectedNum == mList.size());

}

刚才的initList方法,在onCreate中调用。

在这里插入图片描述

下面就是通过点击菜单的批量删除item时调用的方法,新增方法如下:

/**

  • 设置批量删除模式

*/

private void setBatchDeletionMode() {

//进入批量删除模式

isBatchDeletion = !isBatchDeletion;

//设置当前页面

binding.setIsBatchDeletion(isBatchDeletion);

if (!isBatchDeletion) {

//取消所有选中

for (Notebook notebook : mList) {

notebook.setSelect(false);

}

}

//设置适配器

notebookAdapter.setBatchDeletion(isBatchDeletion);

notebookAdapter.notifyDataSetChanged();

}

这个方法首先是改变当前的是否批量删除变量,然后设置到xml中,如果是false,则说明你退出了批量删除模式,则之前有过选中的笔记也要取消选中。最后设置适配器中的变化,再刷新适配器。方法调用的地方如下图所示:

在这里插入图片描述

因为页面会进入到批量删除模式,如果这个时候页面返回了则也调用一下这个方法。

在这里插入图片描述

下面就是删除和全选/取消全选的方法要写一下了,首先是删除吧。

⑥ 删除笔记

因为是删除多个笔记,因此我们需要弹窗提示一下用户,新增代码如下:

/**

  • 显示确认删除弹窗

*/

private void showConfirmDelete() {

AlertDialog.Builder builder = new AlertDialog.Builder(this).setMessage("确定要删除所选的笔记吗?")

.setPositiveButton("确定", (dialog, which) -> {

dialog.dismiss();

List notebookList = new ArrayList<>();

//删除所选中的笔记

for (Notebook notebook : mList) {

if (notebook.isSelect()) {

notebookList.add(notebook);

}

}

Notebook[] notebooks = notebookList.toArray(new Notebook[0]);

viewModel.deleteNotebook(notebooks);

//设置批量删除模式

setBatchDeletionMode();

//请求数据

viewModel.getNotebooks();

})

.setNegativeButton("取消", (dialog, which) -> dialog.dismiss());

builder.create().show();

}

这里的方法主要就是将选择的笔记添加到列表中,然后列表再转笔记数组,数组可以作为动态参数传入到方法中。删除之后当然就要关闭这个批量删除模式,最后我们再查询一下数据库中的笔记。

⑦ 全选

/**

  • 全选/取消全选

*/

private void allSelected() {

isAllSelected = !isAllSelected;

//设置适配器

for (Notebook notebook : mList) {

notebook.setSelect(isAllSelected);

}

//修改页面标题

changeTitle();

//设置当前页面

binding.setIsAllSelected(isAllSelected);

//刷新适配器

notebookAdapter.notifyDataSetChanged();

}

最后就是方法调用的地方:

在这里插入图片描述

代码基本上就写完了,你写的时候最后自己捋一捋这个逻辑,下面运行一下。

在这里插入图片描述

这个批量删除就OK了,相对来说麻烦一些。

三、搜索笔记


当笔记很多的时候,搜索就有必要了,你让我一条一条的去找,那是不存在的。那么事已至此,就开始写吧,写之前理一下思路啊,首先我们需要一个输入框,当输入内容之后显示删除按钮,点击按钮需要清除输入框内容,然后就是通过内容进行模糊搜索,目标字段是标题和内容,也就是说当你的输入内容和搜索的数据中标题和内容只要有一个可以匹配就可以。Emm…

① 输入布局

开始吧。首先在activity_notebook.xml中的data标签中增加变量,如下所示:

<variable

name="showSearchLay"

type="Boolean" />

<variable

name="isSearch"

type="Boolean" />

然后增加一个搜索布局,代码如下:

<LinearLayout

android:id="@+id/lay_search"

android:layout_width="match_parent"

android:layout_height="46dp"

android:background="@color/white"

android:gravity="center_vertical"

android:paddingStart="8dp"

android:paddingEnd="8dp"

android:visibility="@{showSearchLay ? View.VISIBLE : View.GONE}">

<RelativeLayout

android:layout_width="match_parent"

android:layout_height="36dp"

android:background="@drawable/shape_search_bg"

android:paddingStart="12dp"

android:paddingEnd="12dp">

<ImageView

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_centerVertical="true"

android:src="@mipmap/ic_search" />

<EditText

android:id="@+id/et_search"

android:layout_width="match_parent"

android:layout_height="36dp"

android:layout_centerVertical="true"

android:layout_marginStart="32dp"

android:layout_marginEnd="32dp"

android:background="@null"

android:hint="搜索笔记"

android:textColor="@color/black"

android:textCursorDrawable="@drawable/custom_cursor"

android:textSize="@dimen/sp_14" />

<ImageView

android:id="@+id/iv_clear"

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_alignParentEnd="true"

android:layout_centerVertical="true"

android:src="@mipmap/ic_clear"

android:visibility="@{isSearch ? View.VISIBLE : View.GONE}" />

图标在我的源码里,这个布局的位置我需要说明一下:

在这里插入图片描述

这里注意一点就是这个搜索布局是在列表的上方,而不再没有数据布局的上方。

② 模糊搜索

Room中的模糊搜索和常规的SQL语句有一点区别,首先打开NotebookDao,在里面增加如下代码:

// ||相当于+号

@Query("SELECT * FROM notebook WHERE title LIKE '%' || :input || '%' OR content LIKE '%' || :input || '%' ")

Flowable<List> searchNotebook(String input);

这里你看到where后面就是要搜索的字段条件,这里的|| 就等于 + ,or用来匹配另一个字段,这里有标题和内容两个字段。因为模糊搜索返回的数据也会是多条,因此用List包裹起来。下面就是调用的地方了,打开NotebookRepository,在里面增加如下代码:

/**

  • 搜索笔记

*/

public MutableLiveData<List> searchNotebook(String input) {

Flowable<List> listFlowable = BaseApplication.getDb().notebookDao().searchNotebook(input);

CustomDisposable.addDisposable(listFlowable, notebooks -> {

if (notebooks.size() > 0) {

notebooksMutableLiveData.postValue(notebooks);

} else {

notebooksMutableLiveData.postValue(emptyList);

failed.postValue("暂无数据");

}

});

return notebooksMutableLiveData;

}

这里的代码就没啥好说的,和之前的获取全部笔记方法类似。然后就是在NotebookViewModel中调用了,在NotibookViewModel中增加如下方法:

/**

  • 搜索笔记

  • @param input 输入内容

*/

public void searchNotebook(String input) {

notebooks = notebookRepository.searchNotebook(input);

failed = notebookRepository.failed;

}

③ 逻辑处理

首先是处理搜索布局是否显示,没有数据并且搜索输入框没有内容的时候不显示。

在这里插入图片描述

处理页面的输入框监听:

//输入框监听

binding.etSearch.addTextChangedListener(new TextWatcher() {

写在最后

由于本文罗列的知识点是根据我自身总结出来的,并且由于本人水平有限,无法全部提及,欢迎大神们能补充~

将来我会对上面的知识点一个一个深入学习,也希望有童鞋跟我一起学习,一起进阶。

提升架构认知不是一蹴而就的,它离不开刻意学习和思考。

**这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家,**梳理了多年的架构经验,筹备近1个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

领取方式:点击这里获取免费架构视频资料

最近还在整理并复习一些Android基础知识点,有问题希望大家够指出,谢谢。

希望读到这的您能转发分享和关注一下我,以后还会更新技术干货,谢谢您的支持!

转发+点赞+关注,第一时间获取最新知识点

Android架构师之路很漫长,一起共勉吧!