Android 個(gè)人理財(cái)工具三:添加賬單頁面 上
ColaBox 登記收支記錄終于進(jìn)入了復(fù)雜階段了。這個(gè)界面我也是查找了很多資料以及打開android的源代碼看了后才完成了,現(xiàn)在想來Google的開源真是明智的啊。
從前面的登錄頁面跳轉(zhuǎn)進(jìn)入添加賬單頁面。這個(gè)頁面主要是用來登記收支記錄的。說白了就是往數(shù)據(jù)庫錄入明細(xì)。
表結(jié)構(gòu)如下:
db.execSQL("CREATE TABLE bills ("
+ "_ID INTEGER PRIMARY KEY," //id
+ "fee integer," //費(fèi)用
+"acctitemid integer," //賬目類型
+ "userid integer," //使用者
+ "sdate TEXT," //日期
+ "stime TEXT," //時(shí)間
+ "desc TEXT" //備注
+ ");");
可以看到主要是錄入這些數(shù)據(jù)。首先是布置界面,我目前想到的用個(gè)tablelayout來布局。
最后布局就是如下圖(圖1)這樣:

在這兒我首先需要設(shè)置賬目,前面我們已經(jīng)初始化過賬目的數(shù)據(jù)。
賬目應(yīng)該是一個(gè)ExpandableListActivity 2層的結(jié)構(gòu)。需要從數(shù)據(jù)庫里面讀取。我在賬目后面放了一個(gè)editview 只讀沒有光標(biāo)的,也就是在這兒不可錄入,在該editview的onclick事件里面我們打開賬目選擇界面。如下圖:
圖2 賬目選擇:

在這個(gè)界面中點(diǎn)擊子節(jié)點(diǎn)就返回前面界面,把選擇的賬目傳遞過去。在這有個(gè)問題,如果用戶需要錄入的賬目沒有怎么辦?
所以我這沒有用dialog方式而是用了ExpandableListActivity。在這個(gè)界面中如果長點(diǎn)某個(gè)子節(jié)點(diǎn)就彈出管理賬目菜單,來維護(hù)賬目,如下圖所示:
圖3 賬目選擇菜單:

圖4 編輯賬目:

上面這些流程說起來很簡單,可是當(dāng)我用andriod編寫時(shí),遇到了很多問題,不過一個(gè)個(gè)都被我解決了,這正是編程的快樂所在。
關(guān)于ExpandableListActivity 大家可以參考android 里面apidemos 里面ExpandableList1、ExpandableList2、ExpandableList3。
這里面對熟悉這個(gè)ui還是很有幫助的。在ExpandableList2 里面就是從數(shù)據(jù)庫進(jìn)行讀取的例子。當(dāng)然android里面那個(gè)我是沒太看明白因?yàn)樗昧薸mport android.provider.Contacts.People; 聯(lián)系人部分的框架,而我目前對數(shù)據(jù)庫的操作和他不一樣,我都是直接sql訪問。
但是你只要搞定2個(gè)cursor就ok了,Cursor groupCursor childCursor ,其他都由SimpleCursorTreeAdapter幫你實(shí)現(xiàn)了。
下面我們來看看如何使用SimpleCursorTreeAdapter。
Java代碼
//首先要實(shí)現(xiàn)groupcursor就是父節(jié)點(diǎn)游標(biāo),這個(gè)其實(shí)就是我的acctitem表的
//select * from accitem where pid is null 的結(jié)果
Cursor groupCursor = billdb.getParentNode();
// Cache the ID column index
mGroupIdColumnIndex = groupCursor.getColumnIndexOrThrow("_ID");
// Set up our adapter
mAdapter = new MyExpandableListAdapter(groupCursor, this, android.R.layout.simple_expandable_list_item_1,
android.R.layout.simple_expandable_list_item_1,
new String[] { "NAME" }, // Name for group layouts
new int[] { android.R.id.text1 },
new String[] { "NAME" }, //
new int[] { android.R.id.text1 });
setListAdapter(mAdapter);
//然后我要實(shí)現(xiàn)childCursor
//其實(shí)就是select * from acctitem where id=pid 的結(jié)果
public class MyExpandableListAdapter extends SimpleCursorTreeAdapter {
public MyExpandableListAdapter(Cursor cursor, Context context,
int groupLayout, int childLayout, String[] groupFrom,
int[] groupTo, String[] childrenFrom, int[] childrenTo)
{
super(context, cursor, groupLayout, groupFrom, groupTo,
childLayout, childrenFrom, childrenTo);
}
protected Cursor getChildrenCursor(Cursor groupCursor) {
String pid = groupCursor.getLong(mGroupIdColumnIndex) + "";
// Log.v("cola","pid="+pid);
return billdb.getChildenNode(pid);
}
}
//我們看看Billdbhelper里面的cursor
public Cursor getParentNode(){
return db.query("acctitem", new String[]{"_id", "name" }, "pid is null", null, null, null, "pid,_id");
}
public Cursor getChildenNode(String pid){
Log.v("cola","run getchildenNode");
return db.query("acctitem", new String[]{"_id", "name" }, "pid="+pid, null, null, null, "_id");
}
//只要這幾步一個(gè)2級的tree list就可以出現(xiàn)了.
上面其實(shí)才是剛開始,后面我們需要使用一個(gè)自定義的Dialog 類似于一個(gè)inputBox,因?yàn)槲覀冃略鲑~目是需要輸入賬目的名稱。就是上面圖4表現(xiàn)的。
雖然alertDialog提供了很多方法,可以選擇list、treelist、radio,可惜就是不能錄入text。
這里我參考了api demos 里面的 DateWidgets1.java 和源代碼里面DatePickerDialog.java 。
我們可以從alertdialog 繼承,然后添加一個(gè)Editview 最后把數(shù)據(jù)返回出來。只要把上面我說的2個(gè)java看清楚了后處理起來就簡單了。
主要是一個(gè)回調(diào)函數(shù)的用法。下面看代碼:
Java代碼
//
public class Dialog_edit extends AlertDialog implements OnClickListener {
private String text = "";
private EditText edit;
private OnDateSetListener mCallback; //定義回調(diào)函數(shù)
private LinearLayout layout;
public interface OnDateSetListener { //回調(diào)接口
void onDateSet(String text);
}
protected Dialog_edit(Context context, String title, String value,
OnDateSetListener Callback) {
super(context);
mCallback = Callback;
TextView label = new TextView(context);
label.setText("hint");
// setView(label);
edit = new EditText(context);
edit.setText(value);
layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.VERTICAL);
// LinearLayout.LayoutParams param =
// new LinearLayout.LayoutParams(100, 40);
// layout.addView(label, param);
LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(200,
50);
layout.addView(edit, param2);
//添加edit
setView(layout);
setTitle(title);
setButton("確定", this);
setButton2("取消", (OnClickListener) null);
}
public void onClick(DialogInterface dialog, int which) {
// Log.v("cola","U click which="+which);
text = edit.getText().toString();
Log.v("cola", "U click text=" + text);
if (mCallback != null)
mCallback.onDateSet(text); //使用回調(diào)返回錄入的數(shù)據(jù)
}
}
這樣我們就完成了自定義的dialog 我們可以使用它來新增和編輯賬目。對于賬目的增刪改就是sql的事情了。
在這我又遇到一個(gè)問題就是我新增一個(gè)賬目后如何來刷新界面,從而反映賬目修改后的變化。
在這我開始以為只要使用getExpandableListView().invalidate(); 就可以了。
因?yàn)槲抑霸贓xpandableList1.java例子里面,使用它可以刷新界面。
在那個(gè)例子里面我修改了數(shù)組后調(diào)用該方法,界面就刷新了,而在這SimpleCursorTreeAdapter就行不通了,我想
應(yīng)該只要刷新cursor應(yīng)該就可以了,后來找到了notifyDataSetChanged,呵呵,果然可以了。 這樣賬目的錄入和管理就搞定了。
下面給出目前最新的代碼。
首先是賬目管理:
Java代碼
package com.cola.ui;
import android.app.AlertDialog;
import android.app.ExpandableListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.util.Log;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.SimpleCursorTreeAdapter;
import android.widget.TextView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
/**
* Demonstrates expandable lists backed by Cursors
*/
public class Frm_Editacctitem extends ExpandableListActivity {
private int mGroupIdColumnIndex;
private String mPhoneNumberProjection[] = new String[] { People.Phones._ID,
People.Phones.NUMBER };
private ExpandableListAdapter mAdapter;
BilldbHelper billdb;
Dialog_edit newdialog;
private ExpandableListContextMenuInfo info;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("ColaBox-選擇賬目");
billdb = new BilldbHelper(this);
// Query for people
Cursor groupCursor = billdb.getParentNode();
// Cache the ID column index
mGroupIdColumnIndex = groupCursor.getColumnIndexOrThrow("_ID");
// Set up our adapter
mAdapter = new MyExpandableListAdapter(groupCursor, this,
android.R.layout.simple_expandable_list_item_1,
android.R.layout.simple_expandable_list_item_1,
new String[] { "NAME" }, // Name for group layouts
new int[] { android.R.id.text1 }, new String[] { "NAME" }, //
new int[] { android.R.id.text1 });
setListAdapter(mAdapter);
registerForContextMenu(getExpandableListView());
}
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)
{
Bundle bundle = new Bundle();
bundle.putString("DataKey", ((TextView)v).getText().toString());//給bundle 寫入數(shù)據(jù)
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
billdb.close();
finish();
return true;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateOptionsMenu(menu);
if (ExpandableListView
.getPackedPositionType(((ExpandableListContextMenuInfo) menuInfo).packedPosition) == 1) {
Log.v("cola", "run menu");
menu.setHeaderTitle("菜單");
menu.add(0, 1, 0, "新 增");
menu.add(0, 2, 0, "刪 除");
menu.add(0, 3, 0, "編 輯");
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
info = (ExpandableListContextMenuInfo) item.getMenuInfo();
if (item.getItemId() == 1) {
// Log.v("cola","id"+info.id);
newdialog = new Dialog_edit(this, "請輸入新增賬目的名稱", "",
mDialogClick_new);
newdialog.show();
} else if (item.getItemId() == 2) {
new AlertDialog.Builder(this).setTitle("提示").setMessage("確定要?jiǎng)h除'"+((TextView)info.targetView).getText().toString()+"'這個(gè)賬目嗎?")
.setIcon(R.drawable.quit).setPositiveButton("確定",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
billdb.Acctitem_delitem((int)info.id);
updatedisplay();
}
}).setNegativeButton("取消",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
// 取消按鈕事件
}
}).show();
} else if (item.getItemId() == 3) {
newdialog = new Dialog_edit(this, "請修改賬目名稱",
((TextView) info.targetView).getText().toString(),
mDialogClick_edit);
newdialog.show();
}
return false;
}
private Dialog_edit.OnDateSetListener mDialogClick_new = new Dialog_edit.OnDateSetListener() {
public void onDateSet(String text) {
Log.v("cola", "new acctitem");
billdb.Acctitem_newitem(text,ExpandableListView.getPackedPositionGroup(info.packedPosition));
updatedisplay();
}
};
private Dialog_edit.OnDateSetListener mDialogClick_edit = new Dialog_edit.OnDateSetListener() {
public void onDateSet(String text) {
billdb.Acctitem_edititem(text,(int)info.id);
updatedisplay();
}
};
private void updatedisplay(){
Log.v("cola", "update display");
((MyExpandableListAdapter)mAdapter).notifyDataSetChanged();
}
public class MyExpandableListAdapter extends SimpleCursorTreeAdapter {
public MyExpandableListAdapter(Cursor cursor, Context context,
int groupLayout, int childLayout, String[] groupFrom,
int[] groupTo, String[] childrenFrom, int[] childrenTo) {
super(context, cursor, groupLayout, groupFrom, groupTo,
childLayout, childrenFrom, childrenTo);
}
@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
String pid = groupCursor.getLong(mGroupIdColumnIndex) + "";
// Log.v("cola","pid="+pid);
return billdb.getChildenNode(pid);
}
@Override
public long getGroupId(int groupPosition) {
// Log.v("cola", "getGroupId " + groupPosition);
Cursor groupCursor = (Cursor) getGroup(groupPosition);
return groupCursor.getLong(mGroupIdColumnIndex);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
// Log.v("cola", "getChildId " + groupPosition + "," +
// childPosition);
Cursor childCursor = (Cursor) getChild(groupPosition, childPosition);
return childCursor.getLong(0);
}
}
}
自定義對話框:
Java代碼
package com.cola.ui;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.util.Log;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
public class Dialog_edit extends AlertDialog implements OnClickListener {
private String text = "";
private EditText edit;
private OnDateSetListener mCallback;
private LinearLayout layout;
public interface OnDateSetListener {
void onDateSet(String text);
}
protected Dialog_edit(Context context, String title, String value,
OnDateSetListener Callback) {
super(context);
mCallback = Callback;
TextView label = new TextView(context);
label.setText("hint");
// setView(label);
edit = new EditText(context);
edit.setText(value);
layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.VERTICAL);
// LinearLayout.LayoutParams param =
// new LinearLayout.LayoutParams(100, 40);
// layout.addView(label, param);
LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(200,
50);
layout.addView(edit, param2);
setView(layout);
setTitle(title);
setButton("確定", this);
setButton2("取消", (OnClickListener) null);
}
public void onClick(DialogInterface dialog, int which) {
// Log.v("cola","U click which="+which);
text = edit.getText().toString();
Log.v("cola", "U click text=" + text);
if (mCallback != null)
mCallback.onDateSet(text);
}
}
數(shù)據(jù)庫管理代碼:
Java代碼
package com.cola.ui;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
/**
* Provides access to a database of notes. Each note has a title, the note
* itself, a creation date and a modified data.
*/
public class BilldbHelper {
private static final String TAG = "Cola_BilldbHelper";
private static final String DATABASE_NAME = "cola.db";
SQLiteDatabase db;
Context context;
BilldbHelper(Context _context) {
context=_context;
db=context.openOrCreateDatabase(DATABASE_NAME, 0, null);
Log.v(TAG,"db path="+db.getPath());
}
public void CreateTable_acctitem() {
try{
db.execSQL("CREATE TABLE acctitem ("
+ "_ID INTEGER PRIMARY KEY,"
+ "PID integer,"
+ "NAME TEXT"
+ ");");
Log.v("cola","Create Table acctitem ok");
}catch(Exception e){
Log.v("cola","Create Table acctitem err,table exists.");
}
}
public void CreateTable_bills() {
try{
db.execSQL("CREATE TABLE bills ("
+ "_ID INTEGER PRIMARY KEY,"
+" acctitemid integer,"
+ "fee integer,"
+ "userid integer,"
+ "sdate TEXT,"
+ "stime TEXT,"
+ "desc TEXT"
+ ");");
Log.v("cola","Create Table acctitem ok");
}catch(Exception e){
Log.v("cola","Create Table acctitem err,table exists.");
}
}
public void CreateTable_colaconfig() {
try{
db.execSQL("CREATE TABLE colaconfig ("
+ "_ID INTEGER PRIMARY KEY,"
+ "NAME TEXT"
+ ");");
Log.v("cola","Create Table colaconfig ok");
}catch(Exception e){
Log.v("cola","Create Table acctitem err,table exists.");
}
}
public void InitAcctitem() {
try{
//s.getBytes(encoding);
db.execSQL("insert into acctitem values (1,null,'收入')");
db.execSQL("insert into acctitem values (2,1,'工資')");
db.execSQL("insert into acctitem values (9998,1,'其他')");
db.execSQL("insert into acctitem values (0,null,'支出')");
db.execSQL("insert into acctitem values (3,0,'生活用品')");
db.execSQL("insert into acctitem values (4,0,'水電煤氣費(fèi)')");
db.execSQL("insert into acctitem values (5,0,'汽油費(fèi)')");
db.execSQL("insert into acctitem values (9999,0,'其他')");
//db.execSQL("insert into bills values(100,135,10000,'','','備注')");
Log.v("cola","insert into ok");
}catch(Exception e)
{
Log.v("cola","init acctitem e="+e.getMessage());
}
}
public void Acctitem_newitem(String text,int type){
Cursor c =db.query("acctitem", new String[]{"max(_id)+1"}, "_id is not null and _id<9998", null, null, null, null);
c.moveToFirst();
int maxid=c.getInt(0);
String sql="insert into acctitem values ("+maxid+","+type+",'"+text+"')";
db.execSQL(sql);
Log.v("cola","newitem ok text="+text+" id="+type+" sql="+sql);
}
public void Acctitem_edititem(String text,int id){
db.execSQL("update acctitem set name='"+text+"' where _id="+id);
Log.v("cola","edititem ok text="+text+" id="+id);
}
public void Acctitem_delitem(int id){
db.execSQL("delete from acctitem where _id="+id);
Log.v("cola","delitem ok id="+id);
}
public void QueryTable_acctitem(){
}
public void FirstStart(){
try{
String col[] = {"type", "name" };
Cursor c =db.query("sqlite_master", col, "name='colaconfig'", null, null, null, null);
int n=c.getCount();
if (c.getCount()==0){
CreateTable_acctitem();
CreateTable_colaconfig();
CreateTable_bills();
InitAcctitem();
}
//getTree();
Log.v("cola","c.getCount="+n+"");
}catch(Exception e){
Log.v("cola","e="+e.getMessage());
}
}
public void close(){
db.close();
}
public Cursor getParentNode(){
return db.query("acctitem", new String[]{"_id", "name" }, "pid is null", null, null, null, "pid,_id");
}
public Cursor getChildenNode(String pid){
Log.v("cola","run getchildenNode");
return db.query("acctitem", new String[]{"_id", "name" }, "pid="+pid, null, null, null, "_id");
}
}
系列文章:
Android 個(gè)人理財(cái)工具六:顯示賬單明細(xì) 下
Android 個(gè)人理財(cái)工具五:顯示賬單明細(xì) 上
Android 個(gè)人理財(cái)工具四:添加賬單頁面 下
Android 個(gè)人理財(cái)工具三:添加賬單頁面 上
Android 個(gè)人理財(cái)工具二:使用SQLite實(shí)現(xiàn)啟動時(shí)初始化數(shù)據(jù)
Android 個(gè)人理財(cái)工具一:項(xiàng)目概述與啟動界面的實(shí)現(xiàn)
以上就Android 開發(fā)個(gè)人理財(cái)工具 添加賬單頁面的講解,后續(xù)繼續(xù)更新相應(yīng)文章,謝謝大家對本站的支持!
- Android 個(gè)人理財(cái)工具六:顯示賬單明細(xì) 下
- Android 個(gè)人理財(cái)工具五:顯示賬單明細(xì) 上
- Android 個(gè)人理財(cái)工具四:添加賬單頁面 下
- Android 個(gè)人理財(cái)工具二:使用SQLite實(shí)現(xiàn)啟動時(shí)初始化數(shù)據(jù)
- Android 個(gè)人理財(cái)工具一:項(xiàng)目概述與啟動界面的實(shí)現(xiàn)
- Android 錢包支付之輸入支付密碼的實(shí)現(xiàn)步驟
- Android 高仿微信轉(zhuǎn)賬金錢輸入框規(guī)則
- Android快速實(shí)現(xiàn)一個(gè)財(cái)務(wù)APP程序詳解
相關(guān)文章
解決webview內(nèi)的iframe中的事件不可用的問題
這篇文章主要介紹了解決webview內(nèi)的iframe中的事件不可用的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android自定義ViewGroup實(shí)現(xiàn)堆疊頭像的點(diǎn)贊Layout
這篇文章主要介紹了 Android自定義ViewGroup實(shí)現(xiàn)堆疊頭像的點(diǎn)贊Layout,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
android實(shí)現(xiàn)通知欄下載更新app示例
這篇文章主要介紹了android實(shí)現(xiàn)通知欄下載更新app示例,需要的朋友可以參考下2014-03-03

