Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > Android 个人理财工具开发

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

投稿:lqh

本文主要介绍Android 个人理财工具添加账单页面,这里是添加账单的详情页面及如何使用Android Spinner控件的简单示例,有需要的小伙伴可以参考下

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

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

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

       界面的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 理财工具详情页面的开发,后续继续补充,其他功能,谢谢大家对本站的支持!

您可能感兴趣的文章:
阅读全文