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

作者:lqh 时间:2021-09-05 00:43:59 

         本文考虑把账单界面整理下,实现如下图中的功能。做之前感觉应该不难,但实际做时发现排列界面布局甚至比编写程序代码还要复杂。网上搜索发现,关于这种布局的资料能用的很少,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 理财工具详情页面的开发,后续继续补充,其他功能,谢谢大家对本站的支持!

标签:Android,理财工具
0
投稿

猜你喜欢

  • Java利用递归算法实现查询斐波那契数

    2023-08-04 00:02:29
  • Android仿ios年龄、生日、性别滚轮效果

    2022-02-22 11:59:03
  • Android编程设计模式之抽象工厂模式详解

    2023-07-15 09:35:38
  • Android开发之RecyclerView控件

    2023-08-14 08:57:37
  • 详解SpringBoot获得Maven-pom中版本号和编译时间戳

    2022-11-27 19:45:27
  • Android ListView与RecycleView的对比使用解析

    2022-05-05 16:56:02
  • Spring Security 强制退出指定用户的方法

    2022-10-04 18:13:04
  • C#语言主要语言区域

    2021-10-05 13:58:38
  • C#模式画刷HatchBrush用法实例

    2021-10-01 08:59:45
  • c#实现winform屏幕截图并保存的示例

    2022-08-09 09:06:33
  • Filter过滤器和Listener监听器详解

    2021-08-20 07:39:38
  • Android中简单的电话管理与短信管理App编写实例

    2021-10-11 13:45:50
  • 简单了解Java方法的定义和使用实现

    2021-11-07 06:12:53
  • 关于C#结构体 你需要知道的

    2022-01-04 13:11:49
  • [Alibaba-ARouter]浅谈简单好用的Android页面路由框架

    2023-06-28 06:37:22
  • Winform控件优化Paint事件实现圆角组件及提取绘制圆角的方法

    2022-04-04 15:41:13
  • C语言中求字符串长度的函数的几种实现方法

    2023-07-04 23:29:05
  • java开源区块链jdchain入门

    2022-08-07 11:44:44
  • C#实现快递api接口调用方法

    2022-06-15 01:31:58
  • Java设计模式之Strategy模式

    2023-11-21 03:58:22
  • asp之家 软件编程 m.aspxhome.com