在上一节讲完了登录界面的内容,现在随着Activity的跳转,来到MainActivity。

1.主界面activity_main.xml

由上图,activity_main.xml的内容很简单。

首先是定义了一个androidx.appcompat.widget.Toolbar。先来看看,什么是Toolbar。这是由AndroidX库提供的一个控件。

看Toolbar之前,先来看看ActionBar。ActionBar是什么?其实每个Activity最顶部的标题栏就是ActionBar,不过系统原生的ActionBar由于其设计的原因,被限定只能用于顶部,从而不能实现一些Material Design的效果,官方不再建议用ActionBar,更推荐使用Toolbar。

Toolbar不仅继承了ActionBar的所有功能,还可以配合控件完成一些Material Design的效果。

现在我们准备使用Toolbar来替代ActionBar,因此需要指定一个不带ActionBar的主题。在res\values\themes.xml下,将parent设置为"Theme.AppCompat.Light.NoActionBar"

然后就可以设置Toolbar了。此处是将搜索放在了toolbar里面。

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:textColor="#CCCCCC"
android:text="Memo"
android:textSize="22dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<SearchView
android:iconifiedByDefault="false"
android:id="@+id/search"
android:background="@drawable/corners_shade_2"
android:imeOptions="actionSearch"
android:layout_width="270dp"
android:layout_height="30dp"/>
</androidx.appcompat.widget.Toolbar>

由上,SearchView为android提供的搜索组件。来看看它的属性吧。

android:iconifiedByDefault="false" ---> 这个属性默认为true,设置为false时,直接展开显示左侧有放大镜,右侧无叉叉;有输入内容后,右侧叉叉显示出来。
android:imeOptions="actionSearch" --->键盘右下角的键设置。actionNone:没有动作;actionSearch:去搜索;actionSend:发送;actionGo:去往。

现在来看一下悬浮按钮FloatingActionButton.(也是下文中的FAB)

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btn_add"
android:src="@drawable/add"
app:fabSize="normal"
android:backgroundTint="#66CCCC"
android:elevation="5dp"
app:rippleColor="#66CCCC"
android:layout_gravity="bottom|right"
android:layout_margin="50dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
来看看它的属性。
app:fabSize="normal" --->设置FAB的大小,可选的值有三个;mini normal auto.
android:backgroundTint="#66CCCC" --->设置FAB的整体背景,如果没有设置,默认会取theme中的colorAccent作为背景色;
android:elevation="5dp" --->FAB在z轴方向的距离,也就是海拔深度,实际效果就是阴影效果;
app:rippleColor="#66CCCC" --->点击Fab时出现水波纹扩散的效果;
最后是RecyclerView.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycleView"
android:layout_marginTop="60dp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
由上,在activity_main.xml放了一个RecyclerView,对于它的item放在了recycler_item.xml里面。

由上图,为recycler_item.xml的效果,整个布局只有ShapeableImageView需要讲解一下。

可以看到,该组件只有最后的app:shapeAppearanceOverlay="@style/eggStyle"/>和android:scaleType="centerCrop"不同,前者与上一节中activity_login.xml中一样,具体不再阐述。

后者scaleType="centerCrop"的意思是:以原图填满ImageView为目的,如果原图size大于ImageView的size,则与center_inside一样,按比例缩小,居中显示在ImageView上。如果原图size小于ImageView的size,则按比例拉升原图的宽和高,填充ImageView居中显示。

该标签还有很多值,具体可百度。

剩下的三个TextView分别是标题,内容和时间。在内容这一块的TextView中,

<TextView
android:layout_marginTop="5dp"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:id="@+id/item_content"
android:ellipsize="end"
android:maxLines="3"
android:textColor="#CCCCCC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
由上,有两个标签需要解释下。
android:ellipsize="end" --->当文字过长时,省略号显示在结尾。有四个值:start end middle marquee(以跑马灯的方式显示)
 android:maxLines="3" --->显示的行数最大为3行,与ellipsize标签搭配使用。表示,最多显示三行的内容,剩下的内容用...表示。

2.主界面MainActivity

(1)ToolBar的实现 ----顶部菜单栏
这一步很简单,首先通过setSupportActionBar(findViewById(R.id.toolbar));将我们自定义的toolbar实例传入。这时的标题栏什么都没有,我们可以对它进行一些修改,
1.修改标题栏显示的文字。
直接在AndroidManifest.xml中指定,

由上图,通过android:label=" "进行指定。

2.为菜单栏增加一些action按钮。

由上图红色矩形框出来的部分,我们可以在MainActivity中实现这样的效果。

步骤:1):在res目录下创建menu文件夹。然后新建Menu resource file命名为main。名字自己取。

   2):编写代码。如上图编写<item /> 此处还有一个标签app:showAsAction。但是我没有在这个menu中写出来,我在添加的界面写了,应该是下几节的内容,但放在这块儿一起讲了。

新建一个Menu resource file命名为add。为它编写的代码如下。


我们为第一个item添加了app:showAsAction="ifRoom"和android:icon="@drawable/skin"标签。icon就不用解释了,来说说showAsAction。
这个标签主要有以下几种值可选:always :表示永远显示在Toolbar中。如果屏幕不够则不显示。
               ifRoom: 表示屏幕空间足够的情况下显示在Toolbar中,不够就显示在菜单当中。
               never: 表示永远显示在菜单当中。
注意:Toolbar中action按钮只会显示图标,菜单当中的action按钮只会显示文字。
3.创建菜单,加载main.xml文件。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}

4.设置这些action的点击事件
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
return super.onOptionsItemSelected(item);
}
此处的点击事件我没有写,但是在添加备忘录的Activity有写,是为了插入图片到备忘录。此处先略过,后面会讲。
(2)SQLite的实现 ----将备忘录内容存到数据库
SQLite这是Android内置的一个数据库。Android为了让我们能够更加方便的管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类可以非常简单地对数据进行创建和升级。
SQLiteOpenHelper是一个抽象类,所以需要创建一个自己的帮助类去继承它。它有两个抽象方法,onCreate()和onUpgrade()。
必须在自己的帮助类里重写这两个方法,然后分别在这两个方法里实现数据库的创建和升级的逻辑。
SQLiteOpenHelper还有两个非常重要的实例方法:getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则就创建一个新的数据库)
并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式打开数据库,而getWritableDatabase()将会抛出异常。

构造方法:接收4个参数。第一个参数是Context;第二个参数是数据库名;第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般传入null。
第四个参数表示当前的版本号,用于对数据库进行升级操作。

public class MyDbHelper extends SQLiteOpenHelper {
private static String DBNAME = "memodemo.db"; //数据库名称
private static int VERSION = 1; //版本号

public MyDbHelper(Context context) { //构造方法
super(context,DBNAME,null,VERSION);
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) { //创建数据库
sqLiteDatabase.execSQL("create table tb_memory(_id Integer primary key,titel String(200),content String,imgpath String,mtime String)");
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { //数据库升级,此处我没写。

}
}
在以上的代码中,创建了一个名叫"memodemo.db"的数据库,在该数据库中,新建了一张名为tb_memory的表,表里有_id,titel,content,imgpath,mtime五个字段。(title这个单词写错了,但是我后面才发现,就懒得改了。)
可以通过 MyDbHelper myDbHelper = new MyDbHelper(MainActivity.this);
     SQLiteDatabase database = myDbHelper.getWritableDatabase();
database.insert(“表名”,null,contentValues对象)。这是向表中插入数据的代码。只需将要插入的数据放在contentValues对象里即可。
        ContentValues contentValues = new ContentValues();
      contentValues.put("titel",title);
      contentValues.put("content",content);
      contentValues.put("imgpath",disp_path);
      contentValues.put("mtime",time.year + "/" + (time.month + 1) + "/" +time.monthDay);
  注意顺序,应该先创建contentValues对象放数据,再调用insert()方法插入。

更新数据时,先将要更新的数据放在contentValues对象中,然后通过database.update("tb_memory",contentValues,"_id = ?",new String[]{myid});的方式更新。
第一个参数是表名,第二个参数是contentValues对象,第三个参数是具体更新哪条数据,此处用了"_id = ?"的方式,表示更新所有_id=?的行,?在这里是占位符,可以通过第四个参数提供的一个字符串数组为第三个参数中的每个占位符指定相应的内容。

删除数据时,通过database.delete("tb_memory","_id=?",new String[]{arr.get(position).getId()});的方式进行删除。
第一个参数是表名,第二个,第三个参数同更新数据时的后两位参数同理。

查询数据库时,通过rawQuery()方法进行数据查询,还有query()方法。
rawQuery()方法:
Cursor cursor = database.rawQuery("select * from tb_memory",null); --->第一个参数是sql的select语句,第二个参数是select语句中占位符参数的值。如果没有占位符,可以设置为null。
我写的这条没有占位符,所有第二个参数用的null。有占位符的例子:
Cursor cursor = db.rawQuery("select * from person where name like ? and age=?", new String[]{"李华", "4"});

来看看此处是完整代码:

private void recyDisplay(){
MemoBean memoBean;
Cursor cursor = database.rawQuery("select * from tb_memory",null);
while (cursor.moveToNext()){
String myid = cursor.getString(cursor.getColumnIndex("_id"));
String mytitle = cursor.getString(cursor.getColumnIndex("titel"));
String mycontent = cursor.getString(cursor.getColumnIndex("content"));
String mytime = cursor.getString(cursor.getColumnIndex("mtime"));
String myimgpath = cursor.getString(cursor.getColumnIndex("imgpath"));
memoBean = new MemoBean(myid,mytitle,mycontent,myimgpath,mytime);
arr.add(memoBean);
}
cursor.close();
adapter = new MemoAdapter(MainActivity.this,arr);
StaggeredGridLayoutManager st = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(st);
recyclerView.setAdapter(adapter);
}
首先,MemoBean是什么?
这是我写的一个关于备忘录的类。先来看看这个类:

为了截图,我把空行删了,看着不太美观,但不影响。可以看到这里面的属性与表的字段一致,都是备忘录的属性。

回到上面的代码,我们创建了一个MemoBean的对象,memoBean,然后我们通过while循环,查询tb-memory这张表里的所有数据,将这些数据通过memoBean的构造方法,返回一个拥有这些信息的memoBean。好像说绕了,也就是说,表里的每条数据都是一个memoBean,每个memoBean都拥有自己的id,标题,内容,图片地址,时间。

arr是什么?List<MemoBean> arr = new ArrayList<>(); arr是一个用于存放MemoBean类型数据的集合。将所有的memoBean添加到arr中。

退出循环时,arr中已经添加完数据库中所有的数据。然后关闭游标。

下一行代码:adapter = new MemoAdapter(MainActivity.this,arr);

问题来啦,MemoAdapter(MainActivity.this,arr);是什么?

这段代码理解为:通过 MemoAdapter的构造方法新建了一个adapter对象。我们给这个构造方法传入两个参数。

第一个参数是上下文,第二个是添加了备忘录所有数据的arr。

MemoAdapter--备忘录适配器,是什么?干什么的?那么接下来的问题就涉及到第三点RecyclerView了。

-----------

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

RecyclerView + SQLite 简易备忘录-----中(1)的更多相关文章

  1. RecyclerView + SQLite 简易备忘录-----中(2)

    (3)RecyclerView的实现 ---中间的内容 RecyclerView是一个比ListView更加强大的滚动控件.要使用这个控件需要先在项目的build.gradle中添加RecyclerV ...

  2. RecyclerView + SQLite 简易备忘录-----下

    最后就是添加备忘录的界面了.同时也是显示备忘录内容的界面. 1.activity_add_info.xml 也是比较简陋的一个页面设计. 顶部是一个自定义的Toolbar,剩下的部分都是ScrollV ...

  3. RecyclerView + SQLite 简易备忘录-----上

    先看效果 图一只是做了简单的页面,没有连接数据库,刚写完页面才想起备忘录好像不需要登录------但用SharedPreferences写了个记住密码. 图二是主页面,实现了搜索,添加,删除,修改几个 ...

  4. C# 在SQLite数据库中存储图像 z

    C# 在SQLite数据库中存储图像 更多 0 C# SQLite   建表语句 CREATE TABLE [ImageStore]([ImageStore_Id] INTEGER NOT NULL ...

  5. 将 flask 中的 session 存储到 SQLite 数据库中

    将 flask 中的 session 存储到 SQLite 数据库中 使用 flask 构建服务器后端时,常需要在浏览器端存储 cookie 用于识别不同用户,根据不同的 cookie 判断出当前请求 ...

  6. 网络采集软件核心技术剖析系列(6)---将任意博主的全部博文下载到SQLite数据库中并通过Webbrower显示(将之前的内容综合到一起)

    一 本系列随笔目录及本节代码下载 自己开发的豆约翰博客备份专家软件工具问世3年多以来,深受广大博客写作和阅读爱好者的喜爱.同时也不乏一些技术爱好者咨询我,这个软件里面各种实用的功能是如何实现的. 该软 ...

  7. SQLite数据库中rowid使用

    SQLite数据库中rowid使用   SQLite中每个表都默认包含一个隐藏列rowid,使用WITHOUT ROWID定义的表除外.通常情况下,rowid可以唯一的标记表中的每个记录.表中插入的第 ...

  8. SQLite 3 中的数据类型

    SQLite使用动态类型系统,在SQLite中,值的数据类型和值本身,而不是和它的容器,关联在一起的.SQLite的动态类型系统和其他数据库引擎的静态类型系统是兼容的,这样在静态类型的数据库上执行的S ...

  9. Mysql(或者sqlite), Mongo中update Column + 1

    Mysql(或者sqlite), Mongo中update Column + 1 有类似以下需求,在数据库表里有一个字段,记录了一个count,然后又时候需要在count的基础上加上某个数字,比如1. ...

随机推荐

  1. ElasticSearch7.3 学习之定制动态映射(dynamic mapping)

    1.dynamic mapping ElasticSearch中有一个非常重要的特性--动态映射,即索引文档前不需要创建索引.类型等信息,在索引的同时会自动完成索引.类型.映射的创建. 当ES在文档中 ...

  2. 图解CompletableFuture源码

    前言 关于CompletableFuture源码解析部分,整体上感觉还是写比较难的,不过为了推广到团队还是要好好搞一下的,我还是希望大家看到这边文章能学到点什么,废话不多说开始吧. 属性部分 首先看属 ...

  3. 什么是 inode ?

    一般来说,面试不会问 inode .但是 inode 是一个重要概念,是理解 Unix/Linux 文件系统和硬盘储存的基础.理解inode,要从文件储存说起.文件储存在硬盘上,硬盘的最小存储单位叫做 ...

  4. leedCode

    https://blog.csdn.net/code_yilia/category_9851007.html https://blog.csdn.net/qq_17550379/article/det ...

  5. springcloud如何实现服务的注册?

    1.服务发布时,指定对应的服务名,将服务注册到 注册中心(eureka zookeeper)2.注册中心加@EnableEurekaServer,服务用@EnableDiscoveryClient,然 ...

  6. java程序如何确保多线程的运行安全?

    线程的安全问题体现在: 原子性:一个或多个操作在CPU执行过程中不被中断的特性 可见性:一个线程对共享变量的修改,另一个线程能立刻看到 有序性:程序执行的顺序按照代码的先后顺序执行 导致线程存在安全问 ...

  7. mybatis-01-基本流程

    mybatis执行流程   1. 加载配置文件并初始化(SqlSession) 配置文件来源于两个地方,一个是配置文件(主配置文件conf.xml,mapper文件*.xml), 一个是java代码中 ...

  8. 运筹学之"连通图"和"最小枝杈树"和"最短路线问题"

    一.连通图 必须每个点都有关系 图1 不算连通图 图2含有圈v1,v2,v5,可优化 图3就是所需的连通图 注意:图>连通图>树 二.最小枝杈树 获取是所有节点的最小值,只要是连通图就好, ...

  9. SQL语句之Column 'Status' in where clause is ambiguous错误

    问题: AND created_by IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) limit 0, 10]; Column 'created_by' in where cla ...

  10. 如何在Ubuntu 18.04 LTS上安装和配置MongoDB

    MongoDB是一款非关系型数据库,提供高性能,高可用性和自动扩展企业数据库. MongoDB是一个非关系型数据库,因此您不能使用SQL(结构化查询语言)插入和检索数据,也不会将数据存储在MySQL或 ...