欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 个人理财工具四:添加账单页面 下

程序员文章站 2024-03-06 18:05:44
         本文考虑把账单界面整理下,实现如下图中的功能。做之前感觉应该不难,但实际做...

         本文考虑把账单界面整理下,实现如下图中的功能。做之前感觉应该不难,但实际做时发现排列界面布局甚至比编写程序代码还要复杂。网上搜索发现,关于这种布局的资料能用的很少,google demo中用的最多的就是listview了,但本实例的界面似乎要复杂一些。

       spinner和cursor如何配合使用成了完成此实例过程中的难点,本来应该很简单,但却把我郁闷坏了。

       先给大家贴上最终的效果图片:

Android 个人理财工具四:添加账单页面 下

       界面的xml:

xml/html代码

<?xml version="1.0" encoding="utf-8"?> 
<scrollview xmlns:android="http://schemas.android.com/apk/res/android" 
 android:orientation="vertical" 
 android:layout_height="fill_parent" android:layout_width="fill_parent"> 
<linearlayout android:id="@+id/linearlayout01" android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_parent"> 
 <linearlayout android:id="@+id/linearlayout02" android:layout_width="wrap_content" android:layout_height="wrap_content"> 
 <textview android:id="@+id/textview01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选择账目" android:minwidth="80dip" android:textappearance="?android:attr/textappearancelarge"></textview> 
 <edittext android:id="@+id/edittext_acctitem" android:layout_width="wrap_content" android:layout_height="wrap_content" android:width="200dip" android:maxlines="1" android:editable="false" android:cursorvisible="false"></edittext>  
 </linearlayout> 
 <view android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listdivider"/> 
 <linearlayout android:id="@+id/linearlayout03" android:layout_width="wrap_content" android:layout_height="wrap_content"> 
 <textview android:id="@+id/textview03" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="填入费用" android:minwidth="80dip" android:textappearance="?android:attr/textappearancelarge"></textview> 
 <edittext android:id="@+id/fee" android:layout_width="wrap_content" android:layout_height="wrap_content" android:numeric="decimal" android:width="160dip"></edittext> 
 <textview android:id="@+id/textview13" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="(元)" android:textappearance="?android:attr/textappearancelarge"></textview> 
 </linearlayout> 
 <view android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listdivider"/> 
 <linearlayout android:id="@+id/linearlayout04" android:layout_height="wrap_content" android:layout_width="fill_parent"> 
 <textview android:id="@+id/textview02" android:layout_height="wrap_content" android:text="选择时间" android:layout_width="fill_parent" android:fadingedge="horizontal" android:height="24dip" android:drawablepadding="2dip"></textview> 
 </linearlayout> 
 
 <linearlayout android:id="@+id/linearlayout05" android:layout_width="wrap_content" android:layout_height="wrap_content"> 
 <textview android:id="@+id/vdate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textappearance="?android:attr/textappearancelarge" android:width="120dip"></textview> 
 <button android:id="@+id/btndate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+" android:textstyle="bold" android:textsize="24dip" android:height="30dip" android:width="30dip"></button> 
 <textview android:id="@+id/vtime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textappearance="?android:attr/textappearancelarge" android:width="80dip" android:gravity="center_horizontal"></textview> 
 <button android:id="@+id/btntime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+" android:textstyle="bold" android:textsize="24dip"></button> 
 </linearlayout> 
 <view android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listdivider"/> 
 <linearlayout android:id="@+id/linearlayout06" android:layout_height="wrap_content" android:layout_width="fill_parent"> 
 <textview android:id="@+id/textview01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="账目类型" android:minwidth="80dip" android:textappearance="?android:attr/textappearancelarge"></textview> 
 
 <spinner android:id="@+id/spinner01" android:layout_height="wrap_content" android:minwidth="200dip" android:layout_width="wrap_content"></spinner> 
 </linearlayout> 
 <view android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listdivider"/> 
 <textview android:id="@+id/textview07" android:layout_height="wrap_content" android:text="填写备注" android:layout_width="fill_parent" android:height="24dip" ></textview> 
 <edittext android:id="@+id/edittextdesc" android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="4" android:gravity="top"></edittext> 
 <view android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listdivider"/> 
 <linearlayout android:id="@+id/linearlayout08" android:layout_height="wrap_content" android:layout_width="fill_parent"> 
 <button android:id="@+id/btnsave" android:width="160dip" android:text="保 存" android:textstyle="bold" android:textsize="24dip" android:layout_width="wrap_content" android:layout_height="wrap_content"></button> 
 <button android:id="@+id/btncancel" android:width="160dip" android:text="取 消" android:textstyle="bold" android:textsize="24dip" android:layout_width="wrap_content" android:layout_height="wrap_content"></button> 
 
</linearlayout> 
 <view android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listdivider"/> 
</linearlayout> 
</scrollview> 

       下面我们来看下spinner和cursor的用法。

       主要就是一个simplecursoradapter。

       代码如下:

java代码

s1=(spinner) findviewbyid(r.id.spinner01); 
string[] from= new string[]{"caption"};//需要显示游标里面的字段 
int[] to=new int[]{android.r.id.text1}; 
cursor cur=billdb.getuserid(); 
simplecursoradapter madapter=new simplecursoradapter(this,android.r.layout.simple_spinner_item, cur,from, to); 
madapter.setdropdownviewresource(android.r.layout.simple_spinner_dropdown_item); 
s1.setadapter(madapter); 

       我在这儿居然搞了2天,其实写法一直没错,可是每次报未知的行 _id。这个错误我也知道就是使用simplecursoradapter 该方法的游标里面必须包括一个_id的字段,可是我的表里面肯定有的,在我重试了无数次后发现,区分大小写,我倒!

       而事实上我建表的语句是:

java代码

db.execsql("create table tusers (_id integer primary key autoincrement," + 
 "caption text not null)"); 

       而我在函数getuserid 里面cursor定义是:

java代码

public cursor getuserid(){ 
 log.v("cola","run get users cursor"); 
 return db.query("tusers", new string[]{"_id", "caption" }, null, null, null, null, null); 
 
} 

       你单独测试这个cursor是没有问题的。

       这都没用问题,也就是在这儿是不区分大小写的。但是如果你用这个cursor 绑定到simplecursoradapter 这个里面去,一定要和建表语句的一致,不然就出错。这儿把我郁闷坏了。

       上面界面布局和这个spinner 搞定后,后面就是完善代码,完善界面的功能,没有新的地方了。

       在用户选择完账目,填写费用,选择时间,账目类型后就保存进数据库bills表。

       附最新的代码frm_addbills.java:

java代码

package com.cola.ui; 
import java.util.calendar; 
import java.util.timezone; 
import android.app.activity; 
import android.app.alertdialog; 
import android.app.datepickerdialog; 
import android.app.dialog; 
import android.app.timepickerdialog; 
import android.content.dialoginterface; 
import android.content.intent; 
import android.database.cursor; 
import android.os.bundle; 
import android.util.log; 
import android.view.keyevent; 
import android.view.menu; 
import android.view.menuitem; 
import android.view.view; 
import android.view.view.onclicklistener; 
import android.widget.button; 
import android.widget.datepicker; 
import android.widget.edittext; 
import android.widget.simplecursoradapter; 
import android.widget.spinner; 
import android.widget.textview; 
import android.widget.timepicker; 
import android.widget.toast; 
public class frm_addbills extends activity implements onclicklistener { 
 edittext edittext_acctitem,edittextdesc,fee; 
 textview mdate; 
 textview mtime; 
 static final int rg_request = 0; 
 
 private int myear; 
 private int mmonth; 
 private int mday; 
 private int mhour; 
 private int mminute; 
 spinner s1; 
 button btndate,btntime; 
 button btncancel,btnsave; 
 
 billdbhelper billdb; 
 
 int acctitemid=-1; 
 public void oncreate(bundle icicle) { 
 super.oncreate(icicle); 
 settitle("colabox-添加账单"); 
 setcontentview(r.layout.frm_addbills); 
 
 edittext_acctitem = (edittext)findviewbyid(r.id.edittext_acctitem); 
 edittext_acctitem.setonclicklistener(this); 
 
 edittextdesc=(edittext)findviewbyid(r.id.edittextdesc); 
 fee=(edittext)findviewbyid(r.id.fee); 
 
 btndate=(button)findviewbyid(r.id.btndate); 
 btndate.setonclicklistener(this); 
 btntime=(button)findviewbyid(r.id.btntime); 
 btntime.setonclicklistener(this); 
 
 btncancel=(button)findviewbyid(r.id.btncancel); 
 btncancel.setonclicklistener(this); 
 btnsave=(button)findviewbyid(r.id.btnsave); 
 btnsave.setonclicklistener(this); 
 
 mdate = (textview) findviewbyid(r.id.vdate); 
 mtime = (textview) findviewbyid(r.id.vtime); 
 
 //calendar c=calendar.getinstance(locale.china); 
 inittime(); 
  
 setdatetime(); 
 billdb = new billdbhelper(this); 
 s1=(spinner) findviewbyid(r.id.spinner01); 
 string[] from= new string[]{"caption"}; 
 int[] to=new int[]{android.r.id.text1}; 
 cursor cur=billdb.getuserid(); 
 simplecursoradapter madapter=new simplecursoradapter(this,android.r.layout.simple_spinner_item, cur,from, to); 
 madapter.setdropdownviewresource(android.r.layout.simple_spinner_dropdown_item); 
 s1.setadapter(madapter); 
 
 
 } 
 public boolean oncreateoptionsmenu(menu menu) { 
 super.oncreateoptionsmenu(menu); 
 menu.add(0, 1, 0, "账目明细").seticon(r.drawable.editbills); 
 menu.add(0, 2, 0, "账目统计").seticon(r.drawable.editbills2); 
 menu.add(0, 3, 0, "账目报表").seticon(r.drawable.billsum1); 
 menu.add(0, 4, 0, "退 出").seticon(r.drawable.quit); 
 
 return true; 
 } 
 public void onclick(view v) { 
 if (v.equals(edittext_acctitem)) { 
 log.v("colabox", "cmd=edittext_acctitem"); 
 intent intent = new intent(); 
 intent.setclass(frm_addbills.this, frm_editacctitem.class); 
 startactivityforresult(intent, rg_request); 
 } else if (v.equals(btntime)){ 
 showdialog(1); 
 } else if (v.equals(btndate)){ 
 showdialog(2); 
 } else if (v.equals(btncancel)){ 
 cancel(); 
 } else if (v.equals(btnsave)){ 
 save(); 
 } 
 
 } 
 public boolean onoptionsitemselected(menuitem item) { 
 //log.v("colabox", "getmenuitemid=" + item.getitemid()); 
 switch (item.getitemid()) { 
 case 1: 
 return true; 
 case 2: 
 
 return true; 
 case 3: 
 return true; 
 case 4: 
 quitapp(); 
 return true; 
 } 
 return false; 
 } 
 public void quitapp() { 
 new alertdialog.builder(frm_addbills.this).settitle("提示").setmessage( 
 "确定退出?").seticon(r.drawable.quit).setpositivebutton("确定", 
 new dialoginterface.onclicklistener() { 
  public void onclick(dialoginterface dialog, int whichbutton) { 
  billdb.close(); 
  finish(); 
  } 
 }).setnegativebutton("取消", 
 new dialoginterface.onclicklistener() { 
  public void onclick(dialoginterface dialog, int whichbutton) { 
  } 
 }).show(); 
 } 
 protected void onactivityresult(int requestcode, int resultcode, intent data) { 
 if (requestcode == rg_request) { 
 if (resultcode == result_canceled) { 
 // settitle("canceled..."); 
 } else if (resultcode == result_ok) { 
 // settitle((string)data.getcharsequenceextra("datakey")); 
 edittext_acctitem.settext((string) data.getcharsequenceextra("name")); 
 acctitemid=integer.parseint((string)data.getcharsequenceextra("id")); 
 log.v("cola","get acctitemid="+acctitemid); 
  
 } 
 } 
 } 
 
 private void cancel(){ 
 log.v("cola","u put cancel btn"); 
 edittext_acctitem.settext(""); 
 fee.settext(""); 
 acctitemid=-1; 
 inittime();setdatetime(); 
 edittextdesc.settext(""); 
 } 
 private void save(){ 
 log.v("cola","u put save btn"); 
 if (acctitemid==-1){ 
 new alertdialog.builder(this) 
 .setmessage("请首先选择账目.") 
 .show(); 
 return; 
 } 
 int fee=0; 
 string s=fee.gettext().tostring(); 
 int pos=s.indexof("."); 
 //log.v("cola","i="+(s.length()-pos)); 
 if (pos>0){ 
 if (s.length()-pos<3){ 
 s=s+"0"; 
 } 
 fee=integer.parseint(s.substring(0,pos)+s.substring(pos+1,pos+3)); 
 }else{ 
 fee=integer.parseint(s)*100; 
 
 } 
 log.v("cola","u put save btn"); 
 if (billdb.bills_save(acctitemid,fee,(int)s1.getselecteditemid(), ((textview)mdate).gettext().tostring(), ((textview)mtime).gettext().tostring(),edittextdesc.gettext().tostring())){ 
 toast.maketext(this, "保存成功.", toast.length_short).show(); 
 cancel(); 
 }else{ 
 toast.maketext(this, "保存失败,请检查数据.", toast.length_short).show(); 
 } 
 } 
 
 public boolean onkeydown(int keycode, keyevent event) { 
 
 switch (keycode) { 
 case keyevent.keycode_back: 
 quitapp(); 
 return true; 
 
 } 
 return false; 
 } 
 private void inittime(){ 
 calendar c = calendar. getinstance(timezone.gettimezone("gmt+08:00")); 
 myear = c.get(calendar.year); 
 mmonth = c.get(calendar.month); 
 mday = c.get(calendar.day_of_month); 
 mhour = c.get(calendar.hour_of_day); 
 mminute = c.get(calendar.minute); 
 } 
 
 private void setdatetime(){ 
 mdate.settext(myear+"-"+mmonth+"-"+mday); 
 mtime.settext(pad(mhour)+":"+pad(mminute)); 
 } 
 
 @override 
 protected dialog oncreatedialog(int id) { 
 switch (id) { 
 case 1: 
 return new timepickerdialog(this, 
  mtimesetlistener, mhour, mminute, false); 
 case 2: 
 return new datepickerdialog(this, 
  mdatesetlistener, 
  myear, mmonth, mday); 
 } 
 return null; 
 } 
 @override 
 protected void onpreparedialog(int id, dialog dialog) { 
 switch (id) { 
 case 1: 
 ((timepickerdialog) dialog).updatetime(mhour, mminute); 
 break; 
 case 2: 
 ((datepickerdialog) dialog).updatedate(myear, mmonth, mday); 
 break; 
 } 
 } 
 
 private datepickerdialog.ondatesetlistener mdatesetlistener = 
 new datepickerdialog.ondatesetlistener() { 
 public void ondateset(datepicker view, int year, int monthofyear, 
  int dayofmonth) { 
 myear = year; 
 mmonth = monthofyear; 
 mday = dayofmonth; 
 setdatetime(); 
 } 
 }; 
 private timepickerdialog.ontimesetlistener mtimesetlistener = 
 new timepickerdialog.ontimesetlistener() { 
 public void ontimeset(timepicker view, int hourofday, int minute) { 
 mhour = hourofday; 
 mminute = minute; 
 setdatetime(); 
 } 
 }; 
 private static string pad(int c) { 
 if (c >= 10) 
 return string.valueof(c); 
 else 
 return "0" + string.valueof(c); 
 } 
} 

       最新的billdbhelper.java :

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 autoincrement," 
  +" 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 boolean bills_save(int acctid,int fee,int userid,string date,string time,string text){ 
 string sql=""; 
 try{ 
 sql="insert into bills values(null,"+acctid+","+fee+","+userid+",'"+date+"','"+time+"','"+text+"')"; 
 db.execsql(sql); 
 
 log.v("cola","insert table bills ok"); 
 return true; 
 
 }catch(exception e){ 
 log.v("cola","insert table bills err="+sql); 
 return false; 
 } 
 } 
 
 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 createtable_users() { 
 try{ 
 db.execsql("create table tusers (_id integer primary key autoincrement," + 
  "caption text not null)"); 
 log.v("cola","create table users ok"); 
 db.execsql("insert into tusers values (null,'个人')"); 
 db.execsql("insert into tusers values (null,'公司')"); 
 }catch(exception e){ 
 log.v("cola","create table tusers 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,'水电煤气费')"); 
 db.execsql("insert into acctitem values (5,0,'汽油费')"); 
 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(); 
 createtable_users(); 
 initacctitem(); 
 } 
 //test(); 
 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"); 
 } 
 
 public cursor getuserid(){ 
 log.v("cola","run get users cursor"); 
 return db.query("tusers", new string[]{"_id", "caption" }, null, null, null, null, null); 
 } 
 
 public string test(){ 
 try{  
 cursor c2 =getuserid(); 
 string ss=""; 
 c2.movetofirst(); 
 while(!c2.isafterlast()){  
 ss = c2.getstring(0) +", "+ c2.getstring(1); 
 //byte b[]=c2.getstring(1).getbytes(); 
  
 c2.movetonext(); 
  
 log.v("cola","ss="+ss+""); 
 }  
 return ss; 
 }catch(exception e){ 
 log.v("cola","e="+e.getmessage()); 
 return "err"; 
 } 
 } 
} 

            系列文章:

                       android 个人理财工具六:显示账单明细 下

                       android 个人理财工具五:显示账单明细 上

                       android 个人理财工具四:添加账单页面 下

                       android 个人理财工具三:添加账单页面 上

                       android 个人理财工具二:使用sqlite实现启动时初始化数据

                       android 个人理财工具一:项目概述与启动界面的实现

           以上就android 理财工具详情页面的开发,后续继续补充,其他功能,谢谢大家对本站的支持!