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

在上一节讲完了登录界面的内容,现在随着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

posted @ 2022-03-21 20:18  虞美人体重90  阅读(204)  评论(0编辑  收藏  举报