簡(jiǎn)述:
記事本的第一個(gè)版本,需要完善的還有很多,完成了基本的增刪改查的功能,以及在正文中插入圖片,對(duì)內(nèi)容進(jìn)行分類,根據(jù)內(nèi)容查找等基本功能,對(duì)于刪除添加了回收站機(jī)制,可在回收站中對(duì)已刪除的內(nèi)容進(jìn)行恢復(fù)或者永久刪除
暫時(shí)只支持Android5.0以上的設(shè)備運(yùn)行,后續(xù)版本將會(huì)對(duì)4.4版本進(jìn)行兼容,對(duì)4.4以下的設(shè)備未做兼容打算
主界面
編輯界面
功能點(diǎn):
基礎(chǔ)功能
- 對(duì)記事的增刪改
- 添加時(shí)間戳
- 查詢內(nèi)容
拓展功能
- 對(duì)記事進(jìn)行分類
- 在記事中添加圖片
- 一些界面美化以及人性化細(xì)節(jié)設(shè)置
基礎(chǔ)功能
對(duì)記事的增刪改
使用了數(shù)據(jù)庫(kù)輔助類SQLiteOpenHelper來(lái)創(chuàng)建數(shù)據(jù)庫(kù)
數(shù)據(jù)的插入
使用dbHelper封裝insert方法
插入數(shù)據(jù) ContentValues values = new ContentValues(); values.put(COLUMN_NAME_NOTE_TITLE ,title); values.put(COLUMN_NAME_NOTE_CONTENT ,content); values.put(COLUMN_NAME_NOTE_DATE ,dateNum); dbread.insert(TABLE_NAME_NOTES ,null,values);
原先使用的是execSQL()方法來(lái)插入數(shù)據(jù),但是有一個(gè)問(wèn)題就是輸入 ' 這個(gè)符號(hào)使,執(zhí)行語(yǔ)句就會(huì)出錯(cuò),
原先的插入方法 sql = "insert into " +NotesDB.TABLE_NAME_NOTES +"(" +COLUMN_NAME_ID + " ," +COLUMN_NAME_NOTE_TITLE +"," +COLUMN_NAME_NOTE_CONTENT + " ," +COLUMN_NAME_NOTE_DATE + ")" +" values("+count+","+"'"+ title +"'"+","+"'"+ content +"'"+","+"'"+ dateNum + "')"; Log.d("LOG",sql); dbread.execSQL(sql);
數(shù)據(jù)的修改
使用dbHelper封裝update方法 ContentValues values = new ContentValues();; values.put(COLUMN_NAME_NOTE_TITLE ,title); values.put(COLUMN_NAME_NOTE_CONTENT ,content); values.put(COLUMN_NAME_NOTE_DATE,dateNum); String where = "_id="+id; dbread.update(TABLE_NAME_NOTES ,values ,where, null);
同上,使用數(shù)據(jù)庫(kù)語(yǔ)句的execSQL()方法會(huì)因?yàn)檩斎?' 而出錯(cuò),此處不再列出
數(shù)據(jù)的刪除
本應(yīng)用的刪除分兩步進(jìn)行,第一步只是先把記事的屬性改為已刪除,并在回收站顯示,第二部才是進(jìn)行在數(shù)據(jù)庫(kù)的刪除
第一步
更改屬性為刪除 Cursor content = c1; String id = c1.getString(content.getColumnIndex("_id")); String setCategory = "update note set category ='" + CATEGORY_DELETED + "' where _id=" + id; Log.d("DELETE",setCategory); dbread.execSQL(setCategory);
第二步
在數(shù)據(jù)庫(kù)中刪除 Cursor content = (Cursor) deletedview.getItemAtPosition(n); String id = content.getString(content.getColumnIndex("_id")); String recovery = "delete from note where _id=" + id; dbread.execSQL(recovery);
至此,本應(yīng)用的核心功能增刪改已經(jīng)完成
下面是徹底刪除一條記事的流程:
主界面長(zhǎng)按選擇刪除
在彈出的提示中確認(rèn)刪除,此時(shí),主界面列表已經(jīng)不顯示這條記錄
而在回收站中可以看到先前被刪除的記錄,長(zhǎng)按則可以選擇回復(fù)或者徹底刪除
選擇刪除則彈出提示,這條記錄"徹底刪除"已在數(shù)據(jù)庫(kù)中刪除
邏輯的判斷
進(jìn)入編輯界面有兩個(gè)途徑,第一是點(diǎn)擊新建按鈕,第二是從記事列表進(jìn)入,所以我們加入了一個(gè)屬性,若是新建按鈕則為0(調(diào)用插入函數(shù)),若是從記事列表則為1(調(diào)用修改函數(shù)).
if(ENTER_STATE == 0){ noteInsert(); else{ noteUpdate(); }
添加時(shí)間戳
首先要在顯示的listview中加入一個(gè)TextView組件來(lái)顯示這個(gè)時(shí)間,
使用SimpleDateFormat 可以把當(dāng)前時(shí)間格式化成指定格式
Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm"); String dateNum = sdf.format(date);
然后在數(shù)據(jù)庫(kù)相對(duì)應(yīng)的列中加入這個(gè)字符串即可
查詢內(nèi)容
查詢的方法在工具欄點(diǎn)擊查詢按鈕即可調(diào)出searchview,然后輸入所需查詢的文字然后點(diǎn)擊鍵盤的搜索即可查詢內(nèi)容包含關(guān)鍵詞的記錄
查詢"在"的結(jié)果
實(shí)現(xiàn)
具體搜索的實(shí)現(xiàn)代碼不難,執(zhí)行一下代碼就可以將查詢到的內(nèi)容放到Cursor里,然后用適配器進(jìn)行適配就可以在列表中顯示了
String sql = "select * from note where category !='"+CATEGORY_DELETED+"' and content like ?"; Cursor cursor = dbread.rawQuery(sql, new String[]{"%"+word+"%"});
但是為了實(shí)現(xiàn)搜索欄,我們需要用到一個(gè)新的組件
SearchView
首先要在AndroidManifest的顯示搜索欄的活動(dòng)中加入
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" /> <meta-data android:name="android.app.default_searchable" android:value="edu.fjnu.birdie.notemd.MainActivity" />
并在顯示搜索結(jié)果的活動(dòng)中加入
<intent-filter> <action android:name="android.intent.action.SEARCH" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
在 onCreateOptionsMenu(Menu menu)函數(shù)中加入
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView(); searchView.setSearchableInfo( searchManager.getSearchableInfo(getComponentName())); String SearchContent = getIntent().getStringExtra(SearchManager.QUERY); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { Intent intent = new Intent(MainActivity.this,SearchActivity.class); intent.putExtra("word",query); startActivity(intent); return true; } @Override public boolean onQueryTextChange(String newText) { return true; } });
即可讓搜索欄中輸入的文字傳到顯示搜索結(jié)果的活動(dòng)中,并在顯示結(jié)果的搜索欄中進(jìn)行dbread.rawQuery()并裝配到listview就可以得到搜索結(jié)果
拓展功能
對(duì)記事進(jìn)行分類
此處的分類有"默認(rèn)", "重要", "備忘", "筆記", "日程" ,用戶不可自定義
此處一是作為分類,二也是為后續(xù)添加的功能留下接口(備忘接口添加鬧鐘提醒等,但這個(gè)版本只單純的作為分類功能)
同時(shí)還有一個(gè)隱藏分類 刪除
刪除也是通過(guò)分類到刪除分類并在select的時(shí)候去掉這個(gè)分類的記錄
修改分類可以從主界面長(zhǎng)按或者編輯界面的右上角分類按鈕進(jìn)行
實(shí)現(xiàn)
public void addCategory(){ //Toast.makeText(this,"add_catagory",Toast.LENGTH_SHORT).show(); //{ "默認(rèn)", "重要", "備忘", "筆記", "日程" }; if(ENTER_STATE == 1) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("設(shè)置分組"); builder.setSingleChoiceItems(category, 0, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { int choose = which; switch (which) { case 0: { setCategory = "update note set category ='" + CATEGORY_NORMAL + "' where _id=" + id; Log.d("EXE", setCategory); break; } .... builder.setPositiveButton("確定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dbread.execSQL(setCategory); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); builder.create(); builder.show();
使用一個(gè)AlertDialog彈出單選框,并根據(jù)選項(xiàng)的不同來(lái)加載不同的sql語(yǔ)句,并在確定后執(zhí)行sql語(yǔ)句.
在記事中添加圖片
在編輯界面 點(diǎn)擊右下角的按鈕,就會(huì)打開相冊(cè),選擇相冊(cè)中的圖片即可將圖片加入到文本中
實(shí)現(xiàn):
首先要在AndroidManifest中加入權(quán)限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
首先
對(duì)點(diǎn)擊按鈕的事件創(chuàng)建監(jiān)聽
一些界面美化以及人性化細(xì)節(jié)設(shè)置
本應(yīng)用參照了Material Design,雖然并未完全規(guī)范,不過(guò)在界面上還是達(dá)到了相對(duì)應(yīng)的簡(jiǎn)潔,在操作邏輯上也符合用戶的使用
界面美化
界面的演變
4.12 --雛形
內(nèi)容:
- 通過(guò)ListView,Button,EditText等控件做出初始的界面
- 并通過(guò)內(nèi)嵌數(shù)據(jù)庫(kù)SQLite 完成對(duì)內(nèi)容的增刪改
4.13 --重新設(shè)計(jì)界面
內(nèi)容:
- 對(duì)界面進(jìn)行重新設(shè)計(jì)
為了使輸入界面更加簡(jiǎn)潔,可以通過(guò) 在<EditText>中,加入
android:background="@null"
去掉輸入框下的橫線
4.13 --Material Design
內(nèi)容:
- 基于對(duì)界面的重新設(shè)計(jì),加入了Material Design
雖然并不是很規(guī)范,但會(huì)在后續(xù)慢慢完善 - 完成了搜索的基本邏輯,記事本的增刪改查功能基本完善
- 同時(shí)對(duì)設(shè)置菜單,關(guān)于界面進(jìn)行了初步的設(shè)計(jì),但大部分功能都未實(shí)現(xiàn)
后續(xù)的版本都是在第三次界面修改后基本沒(méi)有太大的變化,主要實(shí)在功能上的變化
當(dāng)前版本
人性化細(xì)節(jié)設(shè)置
- 虛擬鍵盤設(shè)置
- 自動(dòng)補(bǔ)充標(biāo)題
- 提醒設(shè)置
- 空界面提示
虛擬鍵盤設(shè)置
新建記事會(huì)自動(dòng)彈出虛擬鍵盤,而二次編輯不彈出虛擬鍵盤,需要點(diǎn)擊才會(huì)彈出鍵盤,因?yàn)樽鳛橛浭骂愜浖罄m(xù)修改的頻率遠(yuǎn)低于查看的頻率,自動(dòng)彈出鍵盤反而會(huì)降低用戶體驗(yàn)
此外,光標(biāo)自動(dòng)聚焦在內(nèi)容編輯處,標(biāo)題在記事類軟件中的存在性并不重要,若要編輯標(biāo)題則需要點(diǎn)擊標(biāo)題欄
實(shí)現(xiàn)
//使焦點(diǎn)默認(rèn)在編輯內(nèi)容上,點(diǎn)擊標(biāo)題欄才能編輯標(biāo)題 et_title.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { et_title.setFocusableInTouchMode(true); return false; } }); //新建文本時(shí)調(diào)用軟鍵盤,如果是打開原來(lái)存在的文本默認(rèn)不打開軟鍵盤 //在Manifest中添加android:windowSoftInputMode="stateHidden"使得虛擬鍵盤不會(huì)自動(dòng)彈出 if(ENTER_STATE == 0){ Log.d("KeyBoard","VISIBLE"); Log.d("ENTER_STATE",ENTER_STATE+""); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); }
自動(dòng)補(bǔ)充標(biāo)題
若用戶覺(jué)得標(biāo)題不重要大可不填,將會(huì)自動(dòng)生成標(biāo)題
if(title.equals("")){ SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy/MM/dd-HH-mm"); String dateNum1 = sdf.format(date); //title = "新建記事"+ dateNum1;//自動(dòng)添加為時(shí)間 title = "新建記事";//添加為新建記事 }
提醒設(shè)置
在刪除,編輯了內(nèi)容未保存的情況下,空內(nèi)容保存記錄,都會(huì)彈出提示框來(lái)提示用戶確保不會(huì)產(chǎn)生誤操作
(在回收站中的刪除沒(méi)有提示,邏輯上如果你已經(jīng)進(jìn)到回收站并確認(rèn)要?jiǎng)h除那條被刪除過(guò)的記錄,應(yīng)該不會(huì)是誤操作)
未保存提示
刪除提示
空界面提示
在沒(méi)有記錄的首頁(yè),搜索不到結(jié)果的搜索頁(yè)面,沒(méi)有回收記錄的回收站,不會(huì)因?yàn)闆](méi)有記錄而空在那里,而是會(huì)有一定的文字提醒
沒(méi)有記錄會(huì)提示點(diǎn)擊右下角添加
無(wú)搜索結(jié)果
無(wú)回收文件
實(shí)現(xiàn)
在Layout中同時(shí)放兩個(gè)Item都是matchparents
然后通過(guò)判斷select結(jié)果來(lái)判斷是要顯示Listview還是顯示提示性文字
以MainActivity為例
//如果列表項(xiàng)為空,則顯示背景和文字 public boolean isNoteNull(){ String sql = "select * from note where category !='"+CATEGORY_DELETED+"'"; Log.d("sql",sql); Cursor c = dbManager.executeSql(sql, null); int number = c.getCount(); Log.d("Note number",number+""); if(number == 0){ ListView listView = (ListView)findViewById(R.id.notelist); TextView textView = (TextView)findViewById(R.id.main_text); listView.setVisibility(View.GONE); textView.setVisibility(View.VISIBLE); return true; }else{ ListView listView = (ListView)findViewById(R.id.notelist); TextView textView = (TextView)findViewById(R.id.main_text); textView.setVisibility(View.GONE); listView.setVisibility(View.VISIBLE); return false; } }