# sticky-note **Repository Path**: sudormrf/sticky-note ## Basic Information - **Project Name**: sticky-note - **Description**: Android 便签软件 - **Primary Language**: Unknown - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 5 - **Created**: 2022-06-07 - **Last Updated**: 2022-06-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Sticky Note - Android 便签软件 | 项目 | 信息 | | ---- | ---- | | 项目地址 | https://gitee.com/wshzard/sticky-note | | 软件包名 | com.team6.stickynote | | minSDK / targetSDK | 21 (Android 5.0) / 32 (Android 12L) | ## 开发人员 | 用户名 | 姓名 | | ---- |--| | wshzard | 吴世昊 | | Swchun | 孙万春 | | EEEEEE | 鲍云达 | # 软件功能 实现添加有标题和文本的便签,同时实现编辑、删除和修改功能。 # 系统的功能表 查看 Git 提交记录。 # 软件架构设计 软件在多个界面使用 MVVM 架构,使用了 ViewModel ,由用户向 ViewModel 发起操作,ViewModel 向数据库请求数据返回赋值给 ViewModel 内数据,UI 负责监听数据显示给用户。 ## 基类 BaseActivity 设计 定义了 abstract 类,方便 initViewBinding 在实体类定义。按照 Android 官方推荐使用 ViewBinding 减少大量 findViewById 方法。 #### MainActivity 数据显示 ```java // Sticky Note 适配器 stickyNoteAdapter = new StickyNoteAdapter(new StickyNoteDiffCallback()); ``` # 数据库设计 # 布局设计 ## RecyclerView 该 App 采用 RecyclerView的形式建立界面布局,通过修改自定义Adapter的布局管理器,实现ListView布局、GridView 布局和 StaggerView 布局。 ### 自定义的 Adapter 适配器 使用了 RecyclerView 的 ListAdapter ,对于列表的数据显示更加友好,同时通过实现 Diff 进行数据变更判断进行局部数据更新,也自带了动画效果。 ```java public class StickyNoteAdapter extends ListAdapter { // ... } ``` StickyNoteAdapter 用于对从数据库中读出的数据进行一系列预处理并显示到 UI 。 #### ViewHolder ```java class ViewHolder extends RecyclerView.ViewHolder { /*...代码段...*/ } ``` ViewHolder为一个自定义的帮助类,用于封装数据,即其包含每个Item的View样式以及数据等。 #### onCreateViewHolder ```java public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { // 获取自定义的 Sticky 的 View View view = View.inflate(parent.getContext(), R.layout.sticky_layout, null); // 把 View 发给 holder return new ViewHolder(view); } ``` 该方法用于创建Item的样式view,并new一个ViewHoder实例,将view传给它。 #### onBindViewHolder ```java public void onBindViewHolder(@NonNull ViewHolder holder, int position) { StickyNoteBean stickyNoteBean = getItem(position); holder.selectedStickyNoteBean = stickyNoteBean; holder.tvSticky.setText(stickyNoteBean.getText()); } ``` 该方法用于将数据绑定到该holder的view上去,position代表数据的位置。 ### 实现ListView布局效果 ```java //用于实现ListView布局 void showList(boolean isVertical) { //创建布局管理器 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); //设置方向定位 if (isVertical) { linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); } else { linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); } //设置布局管理器 binding.rvStickyNote.setLayoutManager(linearLayoutManager); } ``` 调用showList方法即可实现ListView布局的效果,参数isvertical用于控制垂直布局还是水平布局,可由用户自行选择。 其实现逻辑是:通过创建线性布局管理器并设置好布局方向,最后赋给适配器StickyNoteAdapter的对象rvStickyNote即可。 ### 实现GridView布局效果 ```java // 用于实现 Grid 布局 void showGrid(boolean isvertival) { //创建布局管理器 GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2); //设置方向定位 if (isvertival) { gridLayoutManager.setOrientation(GridLayoutManager.VERTICAL); } else { gridLayoutManager.setOrientation(GridLayoutManager.HORIZONTAL); } //设置布局管理器 binding.rvStickyNote.setLayoutManager(gridLayoutManager); } ``` 调用showGrid方法即可实现GridView布局的效果,参数isvertical用于控制垂直布局还是水平布局,可由用户自行选择。 其实现逻辑是:通过创建网格布局管理器并设置好布局方向,最后赋给适配器StickyNoteAdapter的对象rvStickyNote即可。 ### 实现StaggerView布局效果 ```java // 用于实现瀑布流布局 private void showStagger(boolean isVertical) { //创建布局管理器 int ORIENTATION = isVertical ? StaggeredGridLayoutManager.VERTICAL : StaggeredGridLayoutManager.HORIZONTAL; StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, ORIENTATION); //设置布局管理器 binding.rvStickyNote.setLayoutManager(staggeredGridLayoutManager); } ``` 调用showStagger方法即可实现StaggerView布局的效果,参数isvertical用于控制垂直布局还是水平布局 其实现逻辑是:通过创建瀑布流布局管理器并设置好布局方向,最后赋给适配器StickyNoteAdapter的对象rvStickyNote即可。 ## 图标与 UI 图标与界面布局使用figma绘制,通过矢量图导入为xml文件。 # 数据操作 ## 添加便签 ## 删除便签 实现思路为:为每一个便签Item添加长按点击事件,当用户长按某一个Item时将弹出一个删除窗口,点击即可从数据库中删除该Item,并更新UI显示界面 ### 在适配器StickyNoteAdapter中定义接口 ```java // 定义长按事件接口 public interface onItemLongClickListener { void onItemLongClick(View view, long id); } public void setOnItemLongClickListener(onItemLongClickListener onItemLongClickListener) { this.onItemLongClickLitener = onItemLongClickListener; } ``` 用户可直接在外部调用适配器的setOnItemLongClickListener方法并重写接口里方法即可自定义长按事件,接着在Item的长按事件中 调用该接口里的方法即可。如下: ```java //为当前View设置长按事件 itemView.setOnLongClickListener(v -> { if (onItemLongClickLitener != null) { // 获取当前选中的 long id = selectedStickyNoteBean.getId(); onItemLongClickLitener.onItemLongClick(v, id); // 调用定义的接口的事件函数 } return true; }); ``` ### 利用PopupMenu实现弹出窗口并删除数据 ```java // Sticky Note 适配器 stickyNoteAdapter = new StickyNoteAdapter(new StickyNoteDiffCallback()); stickyNoteAdapter.setOnItemLongClickListener((view, id) -> { //长按事件 //为该View设置弹出框 PopupMenu popupMenu = new PopupMenu(MainActivity.this, view); popupMenu.getMenuInflater().inflate(R.menu.delete_menu, popupMenu.getMenu()); // 设置样式 popupMenu.show(); // 显示 //设置点击事件 popupMenu.setOnMenuItemClickListener(item -> { switch (item.getItemId()){ case R.id.delete_it: // 删除该item ToastUtil.toast("删除成功!"); App.database.deleteOneData(id); // 更新显示数据 mainViewModel.updateStickyNoteBeans(); break; } return true; }); }); ``` 在外部调用适配器的setOnItemLongClickListener方法重写接口方法时,实例化一个PopupMenu对象,并将自定义的view样式赋给该对象。 接着为该对象设置点击事件,在点击事件中实现删除Item的功能并更新UI显示界面。 ## 修改编辑便签 通过调用数据库中的更新数据函数,更改便签相关内容,并进行保存。 ```java //save函数保存数据 private void save() { if (stickyNoteBean != null) { String title = binding.etTitle.getText().toString(); String content = binding.etContent.getText().toString(); if (TextUtils.isEmpty(title)) { ToastUtil.toast( "标题不能为空!"); return; } ``` ```java //调用数据库中updata函数 stickyNoteBean.setTitle(title); stickyNoteBean.setText(content); long id=stickyNoteBean.getId(); long rowId = App.database.updateOneData(id,stickyNoteBean); if (rowId != -1) { ToastUtil.toast("修改成功!"); this.finish(); } else { ToastUtil.toast("修改失败!"); } ``` ## 搜索便签