安卓练习之——记账软件

news/2024/10/23 7:32:23/

这是一个简单的账本,目前的功能可以实现记账,显示总的支出、收入、结余,查看账单以及删除不想要的账单。后续功能慢慢完善。那么就开始代码和图演示。
如果有不足的地方,希望看到的大神给予指点建议,不胜感激!

1.页面介绍:左侧侧滑菜单,实现功能还在施工,可以加一些设置之类。
首页使用ViewPager+Fragment分为两页,首页实现总账目,第二页实现记账和查看账单。
这里写图片描述

2.左侧滑菜单:通过HorizontalScrollView实现

package view;import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;import com.chase.cn.demon.R;
import com.nineoldandroids.view.ViewHelper;/*** Created by Chase on 2016/11/7.*/public class SlidingMenu extends HorizontalScrollView {private LinearLayout mWapper;private ViewGroup mMenu;private ViewGroup mContent;private int mScreenWidth;private int mMenuWidth;private int mMenuRightPadding = 50;private boolean once;private boolean isOpen;/*** 未使用自定义属性时,调用** @param context* @param attrs*/public SlidingMenu(Context context, AttributeSet attrs){this(context, attrs, 0);}/*** 当使用了自定义属性时,会调用此构造方法** @param context* @param attrs* @param defStyle*/public SlidingMenu(Context context, AttributeSet attrs, int defStyle){super(context, attrs, defStyle);// 获取我们定义的属性TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.SlidingMenu, defStyle, 0);int n = a.getIndexCount();for (int i = 0; i < n; i++){int attr = a.getIndex(i);switch (attr){case R.styleable.SlidingMenu_rightPadding:mMenuRightPadding = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()));break;}}a.recycle();//获取屏幕宽高WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);mScreenWidth = outMetrics.widthPixels;}public SlidingMenu(Context context){this(context, null);}/*** 设置子View的宽和高 设置自己的宽和高*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){if (!once){mWapper = (LinearLayout) getChildAt(0);mMenu = (ViewGroup) mWapper.getChildAt(0);mContent = (ViewGroup) mWapper.getChildAt(1);mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth- mMenuRightPadding;mContent.getLayoutParams().width = mScreenWidth;once = true;}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}/*** 通过设置偏移量,将menu隐藏*/@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b){super.onLayout(changed, l, t, r, b);if (changed){this.scrollTo(mMenuWidth, 0);}}@Overridepublic boolean onTouchEvent(MotionEvent ev){int action = ev.getAction();switch (action){case MotionEvent.ACTION_UP:// 隐藏在左边的宽度int scrollX = getScrollX();if (scrollX >= mMenuWidth / 2){this.smoothScrollTo(mMenuWidth, 0);isOpen = false;} else{this.smoothScrollTo(0, 0);isOpen = true;}return true;}return super.onTouchEvent(ev);}//切换菜单按钮的开关逻辑public void openMenu(){if (isOpen)return;this.smoothScrollTo(0,0);isOpen = true;}public void closeMenu(){if (!isOpen)return;this.smoothScrollTo(mMenuWidth,0);isOpen = false;}public void  toggle(){if (isOpen){closeMenu();}else{openMenu();}}//抽屉菜单@Overrideprotected void onScrollChanged(int l, int t, int oldl, int oldt) {super.onScrollChanged(l, t, oldl, oldt);float scale = l * 1.0f / mMenuWidth; // 1 ~ 0float leftAlpha = 0.6f + 0.4f * (1 - scale);// 调用属性动画,设置TranslationXViewHelper.setTranslationX(mMenu, l);ViewHelper.setAlpha(mMenu, leftAlpha);}
}

其中两个子View,Content和Menu:

下面是Content的xml文件,其中content部分包含了ViewPager。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#dbd0a7"android:orientation="vertical"android:weightSum="1"><include layout="@layout/titlebar"/><android.support.v4.view.ViewPager
        android:id="@+id/content_viewPager"android:layout_width="match_parent"android:layout_height="match_parent"><!--Fragment的Tab--><android.support.v4.view.PagerTabStrip  android:id="@+id/tab"android:layout_width="match_parent"android:layout_height="wrap_content"></android.support.v4.view.PagerTabStrip></android.support.v4.view.ViewPager></LinearLayout>

其中上面的文件include的Title bar文件如下,其实就是一个Fragment

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:background="#e69b03"><Button
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="toggleMenu"android:text="切换菜单"android:textColor="#ffffff"/><TextView
        android:layout_width="match_parent"android:layout_height="wrap_content"android:text="MyMoney"android:gravity="center_horizontal"android:textSize="20sp"/>
</RelativeLayout>

下面是LeftMenu的xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#d1494e"><LinearLayout
        android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:orientation="vertical"><RelativeLayout
            android:layout_width="fill_parent"android:layout_height="wrap_content"><ImageView
                android:id="@+id/image1"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/ic_launcher" /><TextView
                android:layout_centerVertical="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/image1"android:text="施工中1"android:textColor="#ffffff"android:layout_marginLeft="20dp"android:textSize="20sp" /></RelativeLayout><RelativeLayout
            android:layout_width="fill_parent"android:layout_height="wrap_content"><ImageView
                android:id="@+id/image2"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/ic_launcher" /><TextView
                android:layout_centerVertical="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/image2"android:text="施工中2"android:textColor="#ffffff"android:layout_marginLeft="20dp"android:textSize="20sp" /></RelativeLayout><RelativeLayout
            android:layout_width="fill_parent"android:layout_height="wrap_content"><ImageView
                android:id="@+id/image3"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/ic_launcher" /><TextView
                android:layout_centerVertical="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/image3"android:text="施工中3"android:textColor="#ffffff"android:layout_marginLeft="20dp"android:textSize="20sp" /></RelativeLayout><RelativeLayout
            android:layout_width="fill_parent"android:layout_height="wrap_content"><ImageView
                android:id="@+id/image4"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerVertical="true"android:layout_marginLeft="20dp"android:layout_marginTop="20dp"android:src="@mipmap/ic_launcher" /><TextView
                android:layout_centerVertical="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/image4"android:text="施工中4"android:textColor="#ffffff"android:layout_marginLeft="20dp"android:textSize="20sp" /></RelativeLayout></LinearLayout></RelativeLayout>

现在来看MainActivity:

package com.chase.cn.demon;import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.Window;import java.util.ArrayList;
import java.util.List;import view.SlidingMenu;public class MainActivity extends FragmentActivity {private SlidingMenu mLeftMennu;private ViewPager mContentPager;private List<Fragment> fragList;private List<String> tabList;private PagerTabStrip myTab;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);mLeftMennu = (SlidingMenu) findViewById(R.id.leftMenu);//fragment的数据源fragList = new ArrayList<Fragment>();fragList.add(new Content_Fragment1());fragList.add(new Content_Fragment2());//tab的数据源tabList = new ArrayList<String>();tabList.add("首页");tabList.add("我的账本");MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragList, tabList);mContentPager = (ViewPager) findViewById(R.id.content_viewPager);mContentPager.setAdapter(pagerAdapter);myTab = (PagerTabStrip) findViewById(R.id.tab);myTab.setDrawFullUnderline(false);myTab.setTextSpacing(5);}public void toggleMenu(View v) {mLeftMennu.toggle();} //切换菜单按键}

MainActivity的xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:chase="http://schemas.android.com/apk/res-auto"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><view.SlidingMenu
        android:id="@+id/leftMenu"android:layout_width="match_parent"android:layout_height="match_parent"chase:rightPadding="150dp"><LinearLayout
            android:layout_width="wrap_content"android:layout_height="match_parent"android:orientation="horizontal"><!--引入左菜单--><include layout="@layout/leftmenu" /><!--内容区域--><include layout="@layout/content" /></LinearLayout></view.SlidingMenu></RelativeLayout>

MainActivity用到的FragmentAdapter如下:

package com.chase.cn.demon;import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;import java.util.List;/*** Created by Chase on 2016/11/8.*/public class MyFragmentPagerAdapter extends FragmentPagerAdapter{private List<Fragment> fragList;private List<String> tabList;public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragList, List<String> tabList) {super(fm);this.fragList = fragList;this.tabList = tabList;}@Overridepublic CharSequence getPageTitle(int position) {return tabList.get(position);}@Overridepublic Fragment getItem(int position) {return fragList.get(position);}@Overridepublic int getCount() {return fragList.size();}
}

因为主要功能是在Fragment里实现的,所以两个页面的Fragment中来写代码,首先先建立数据库,使用SQLiteOpenHelper:

package com.chase.cn.demon;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;/*** Created by Chase on 2016/11/8.*/public class MySQLiteOpenHelper extends SQLiteOpenHelper {public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {super(context, name, null, 1);}//首次创建时调用 一般用于建库 建表@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL("create table if not exists finance" +"(_id integer primary key autoincrement," +"Type varchar(10)," +"Time varchar(20)," +"Fee double," +"Budget varchar(10))");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}

Fragment1的代码:

package com.chase.cn.demon;import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;/*** Created by Chase on 2016/11/8.*/public class Content_Fragment1 extends android.support.v4.app.Fragment {private MySQLiteOpenHelper mSqlHelper;private SQLiteDatabase mDataBase;private TextView textRemaind,textPay,textIncome;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View pager1 = inflater.inflate(R.layout.fragment_page1, container, false);//初始统计值double resultPay = 0, resultIncome = 0, resultRemain = 0;textRemaind = (TextView) pager1.findViewById(R.id.resultRemain);textPay = (TextView) pager1.findViewById(R.id.resultPay);textIncome = (TextView) pager1.findViewById(R.id.resultIncome);//sqliteOpenHelper创建数据库mTimeHandler.sendEmptyMessageDelayed(0, 1000);return pager1;}@Overridepublic void onDestroy() {mTimeHandler.removeCallbacksAndMessages(null);mSqlHelper.close();mDataBase.close();super.onDestroy();}//跑一个线程handle 动态更新textViewpublic Handler mTimeHandler = new Handler() {public void handleMessage(android.os.Message msg) {if (msg.what == 0) {double resultPay = 0, resultIncome = 0, resultRemain = 0;mSqlHelper = new MySQLiteOpenHelper(getActivity(), "finance.db", null, 1);mDataBase = mSqlHelper.getReadableDatabase();Cursor cursor = mDataBase.rawQuery("select Fee,Budget from finance",null);if (cursor.getCount()>0) {while (cursor.moveToNext()) {
//                          cursor.move(i);//移动到指定记录double Fee = cursor.getDouble(cursor.getColumnIndex("Fee"));String budget = cursor.getString(cursor.getColumnIndex("Budget"));if (budget.equals("支出")) {resultPay += Fee;} else if (budget.equals("收入")) {resultIncome += Fee;}}}//保留小数点后两位java.text.DecimalFormat df = new java.text.DecimalFormat(".##");textPay.setText(String.valueOf(df.format(resultPay)));textIncome.setText(String.valueOf(df.format(resultIncome)));textRemaind.setText(String.valueOf(df.format(resultIncome - resultPay)));sendEmptyMessageDelayed(0, 1000);cursor.close();}}};}

Fragment2的代码:

package com.chase.cn.demon;import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;/*** Created by Chase on 2016/11/8.*/public class Content_Fragment2 extends android.support.v4.app.Fragment implements View.OnClickListener{private LinearLayout recordLinearlayout;private LinearLayout billLinearlayout;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View pager2 = inflater.inflate(R.layout.fragment_page2, container, false);recordLinearlayout = (LinearLayout) pager2.findViewById(R.id.record_layout);billLinearlayout = (LinearLayout) pager2.findViewById(R.id.bill_layout);recordLinearlayout.setOnClickListener(this);billLinearlayout.setOnClickListener(this);return pager2;}//点击条目的监听 并进行跳转@Overridepublic void onClick(View v){switch (v.getId()){case R.id.record_layout:{Intent intentRecorder = new Intent(getActivity(),RecorderActiviity.class);startActivity(intentRecorder);int version = Integer.valueOf(android.os.Build.VERSION.SDK);if(version  >= 5) {this.getActivity().overridePendingTransition(R.anim.push_up_in,R.anim.push_up_out);}break;}case R.id.bill_layout:{Intent intentBill = new Intent(getActivity(),BillActivity.class);startActivity(intentBill);this.getActivity().overridePendingTransition(R.anim.push_up_in,R.anim.push_up_out);break;}}}}

在Fragment2中,点击“记一笔”和“查看账单”,进入不同的Activity中:
下面是“记一笔”代码:

package com.chase.cn.demon;import android.app.Activity;
import android.app.DatePickerDialog;
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.TextView;import java.util.ArrayList;
import java.util.Calendar;/*** Created by Chase on 2016/11/8.*/public class RecorderActiviity extends Activity {private RadioGroup mRadioGroup;private TextView  TextTime;private EditText TextMoney;private Spinner spinner;private Button Confirm, Cancel;private MySQLiteOpenHelper sqLiteOpenHelper;private SQLiteDatabase mDataBase;private ImageButton timer_chooser;//保存类型数据private String add_type, radioButton_selected;//将这些数据保存一组data 用Data存入sqliteprivate ArrayList<String> Data = new ArrayList<String>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.recorder);mRadioGroup = (RadioGroup) findViewById(R.id.recorder_radioGroup);spinner = (Spinner) findViewById(R.id.record_spinner);Confirm = (Button) findViewById(R.id.recorder_confirm);Cancel = (Button) findViewById(R.id.recorder_cancel);TextTime = (TextView) findViewById(R.id.record_textView_time);TextMoney = (EditText) findViewById(R.id.record_textView_money);timer_chooser = (ImageButton) findViewById(R.id.timer_chooser);TextMoney.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);//设置输入的钱为数字和小数//spinner设置属性 设置收入 和 支出的 spinner 利用arrays中的数据final ArrayAdapter<CharSequence> spinnerAdapterPay = ArrayAdapter.createFromResource(this,R.array.type1, android.R.layout.simple_spinner_item);spinnerAdapterPay.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);final ArrayAdapter<CharSequence> spinnerAdapterIncome = ArrayAdapter.createFromResource(this,R.array.type2, android.R.layout.simple_spinner_item);spinner.setAdapter(spinnerAdapterPay);//匹配不选情况下默认的pay//在radioButton中加入选 支出 还是 收入 的不同情况spinnerradioButton_selected = "支出";mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {int radioButtonId = group.getCheckedRadioButtonId();if (radioButtonId == R.id.radio_pay) {spinner.setAdapter(spinnerAdapterPay);spinnerAdapterPay.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);} else {spinner.setAdapter(spinnerAdapterIncome);spinnerAdapterIncome.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);}//根据ID获取RadioButton的选的是 收入 还是 支出
//                radioButton_selected = (((RadioButton) findViewById(radioButtonId)).getText()).toString();RadioButton radioButton = (RadioButton) findViewById(mRadioGroup.getCheckedRadioButtonId());radioButton_selected = radioButton.getText().toString();}});//Spinner获取选中的内容 赋值给add_typespinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {add_type = (String) spinner.getSelectedItem();}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});Calendar cnow = Calendar.getInstance();final int year = cnow.get(Calendar.YEAR);final int month = cnow.get(Calendar.MONTH)+1;final int day = cnow.get(Calendar.DAY_OF_MONTH);Log.i("time", "time" + year + month + day);TextTime.setHint(year + "-" + month + "-" + day);//时间选择的dialogtimer_chooser.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Calendar c = Calendar.getInstance();new DatePickerDialog(RecorderActiviity.this, new DatePickerDialog.OnDateSetListener() {@Overridepublic void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {TextTime.setHint(year + "-" + (month+1) + "-" + dayOfMonth);}},c.get(Calendar.YEAR),c.get(Calendar.MONTH),c.get(Calendar.DAY_OF_MONTH)).show();}});//确定按钮Confirm.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Data.clear();Data.add(add_type);Data.add(TextTime.getHint().toString());Data.add(TextMoney.getText().toString());Data.add(radioButton_selected);WriteData(Data);finish();overridePendingTransition(R.anim.push_up_in,R.anim.push_up_out);Log.i("info", "add_type" + add_type);Log.i("info", "radioButton_selected" + radioButton_selected);}});//取消按钮Cancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {finish();overridePendingTransition(R.anim.push_up_in,R.anim.push_up_out);}});}public void WriteData(ArrayList<String> Data) {sqLiteOpenHelper = new MySQLiteOpenHelper(this, "finance.db", null, 1);mDataBase = sqLiteOpenHelper.getWritableDatabase();ContentValues values = new ContentValues();values.clear();values.put("Type", Data.get(0));values.put("Time", Data.get(1));values.put("Fee", Data.get(2));values.put("Budget", Data.get(3));mDataBase.insert("finance", "Type", values);mDataBase.close();sqLiteOpenHelper.close();}@Overrideprotected void onDestroy() {super.onDestroy();}
}

下面是“记一笔”的界面
Recorder界面

xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="#547387"><LinearLayout
        android:layout_marginTop="15dp"android:background="@drawable/recorder_radio_bg"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"><RadioGroup
            android:gravity="center"android:id="@+id/recorder_radioGroup"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButton
                android:layout_marginRight="95dp"android:id="@+id/radio_pay"android:layout_width="wrap_content"android:layout_height="wrap_content"android:checked="true"android:textSize="25sp"android:text="支出" /><RadioButton
                android:id="@+id/radio_income"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="25sp"android:text="收入" /></RadioGroup></LinearLayout><LinearLayout
        android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:background="@drawable/recorder_type_bg"><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="种类:"android:textSize="25sp"android:id="@+id/textView" /><Spinner
            android:scrollbarSize="20dp"android:id="@+id/record_spinner"android:layout_width="match_parent"android:layout_height="wrap_content"></Spinner></LinearLayout><LinearLayout
        android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:background="@drawable/recorder_time_bg"><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="时间:"android:textSize="25sp"android:id="@+id/textView2" /><TextView
                android:id="@+id/record_textView_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="25sp"android:hint="null" /><ImageButton
                android:layout_marginRight="15dp"android:layout_marginTop="4dp"android:id="@+id/timer_chooser"android:layout_width="40dp"android:layout_height="40dp"android:background="@mipmap/recorder_calendar"/></LinearLayout><LinearLayout
        android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginTop="10dp"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:background="@drawable/recorder_money_bg"><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="金额:"android:textSize="25sp"android:textColor="#fff"android:id="@+id/textView3" /><EditText
            android:id="@+id/record_textView_money"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="25sp"android:textColorHint="#afe1e2"android:hint="请输入消费/收入的金额"/></LinearLayout><LinearLayout
        android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Button
            android:id="@+id/recorder_confirm"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="确定"android:textAllCaps="false"android:layout_weight="1"/><Button
            android:id="@+id/recorder_cancel"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="取消"android:textAllCaps="false"android:layout_weight="1"/></LinearLayout></LinearLayout>

“记一笔中”的种类选择spinner用到在values文件夹下添加的array.xml文件:
这个文件中分别定义了两个type来对应“收入”和“支出”。

<?xml version="1.0" encoding="utf-8"?>
<resources><string-array name="type1"><item>一般</item><item>用餐</item><item>交通</item><item>服饰</item><item>丽人</item><item>旅行</item><item>果蔬</item><item>日用品</item><item>网购</item><item>购物</item></string-array><string-array name="type2"><item>一般</item><item>报销</item><item>工资</item><item>零花钱</item><item>兼职</item><item>红包</item><item>生活费</item><item>奖金</item><item>投资</item><item>其他</item></string-array></resources>

“查看账单”的代码如下,查看账单,从数据库中取得信息,我用的是CursorAdapter,所以在长按动态删除时,我用adapter change cursor实现。

package com.chase.cn.demon;import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;/*** Created by Chase on 2016/11/10.*/
public class BillActivity extends Activity {private ListView billListView;private MySQLiteOpenHelper sqLiteOpenHelper;private SQLiteDatabase mDataBase;private SimpleCursorAdapter billAdapter;private boolean flag = true;// 存储数据的数组列表//  ArrayList<HashMap<String, Object>> listData;// 适配器@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.bill);sqLiteOpenHelper = new MySQLiteOpenHelper(BillActivity.this, "finance.db", null, 1);mDataBase = sqLiteOpenHelper.getReadableDatabase();final Cursor c = mDataBase.rawQuery("select * from finance", null);Log.i("database", "data" + mDataBase.isOpen());//        int columnsSize = c.getColumnCount();
//        listData = new ArrayList<HashMap<String, Object>>();// 获取表的内容//        while (c.moveToNext()) {
//            HashMap<String, Object> map = new HashMap<String, Object>();
//            for (int i = 0; i < columnsSize; i++) {
//                map.put("Type", c.getString(c.getColumnIndex("Type")));  //Type time fee budget
//                map.put("Time", c.getString(c.getColumnIndex("Time")));
//                String budget = c.getString(c.getColumnIndex("Budget"));
//                if (budget.equals("收入")) {
//                    map.put("Fee", "+" + c.getString(c.getColumnIndex("Fee")));
//                } else {
//                    map.put("Fee", "-" + c.getString(c.getColumnIndex("Fee")));
//                }
//                map.put("Budget", c.getString(c.getColumnIndex("Budget")));
//
//
//                Log.i("data", "data= " + map.get("Time"));
//                Log.i("data", "data= " + map.get("Type"));
//                Log.i("data", "data= " + map.get("Budget"));
//                Log.i("data", "data= " + map.get("Fee"));
//            }
//            listData.add(map);
//
//
//        }
        mDataBase.close();  先不关 等activity不在了再关
        sqLiteOpenHelper.close();
        c.close();billListView = (ListView) findViewById(R.id.bill_listView);//优化使用cursorAdapter减少代码billAdapter = new SimpleCursorAdapter(BillActivity.this,R.layout.bill_item,c,// ListItem的XML实现// 动态数组与Item对应的子项new String[]{"Time", "Fee", "Budget", "Type"},// ImageItem的XML文件里面的一个ImageView,两个TextView IDnew int[]{R.id.billItem_time, R.id.billItem_money, R.id.billItem_budget, R.id.billItem_type});billListView.setAdapter(billAdapter);//item监听billListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {String cc = c.getString(c.getColumnIndex("_id")); //用cursor得到对应表中的idLog.i("info", "cc=  " + cc);Toast.makeText(BillActivity.this, "删除了", Toast.LENGTH_SHORT).show();//删除表中的对应id的行mDataBase.execSQL("delete from finance where _id="+ cc);/*** 也就是说,在数据库中删除一条记录之后,紧跟着直接用ListView的remove() 方法删掉对应的View,但是这样报错:Java.lang.UnsupportedOperationException: removeView(View) is not supported in AdapterView说明不能直接用ListView的remove()方法。于是网上查了查,找到了新的方法,而且也更合理:[java] view plain copy 在CODE上查看代码片派生到我的代码片for(Sample sample : selectedSamples){SampleManager.get(getActivity()).deleteSample(Long.parseLong(sample.getId()));}((SampleCursor)adapter.getCursor()).requery();adapter.notifyDataSetChanged();lv.setAdapter(adapter);也就是说:1. 对应的cursor要重新查询一边,2. 然后适配器adapter调用notifiyDataSetChanged()方法,3. 最后重新设置一下ListView的adapter*/(billAdapter.getCursor()).requery();billAdapter.notifyDataSetChanged();Log.i("info","c  "+c.isClosed());
////                mDataBase.close();
//                sqLiteOpenHelper.close();return false;}});//        mTimeHandler2.sendEmptyMessageDelayed(0, 500);}@Overridepublic void onDestroy() {mTimeHandler2.removeCallbacksAndMessages(null);//        sqLiteOpenHelper.close();
//        mDataBase.close();super.onDestroy();}public Handler mTimeHandler2 = new Handler() {public void handleMessage(android.os.Message msg) {if (msg.what == 0) {//                billAdapter.changeCursor(c);}}};}

对应的xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="#b3d66e"><TextView
        android:layout_width="match_parent"android:layout_height="wrap_content"android:text="长按删除每条账目"android:textSize="20sp"android:gravity="center"/><ListView
        android:id="@+id/bill_listView"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:layout_marginTop="5dp"></ListView></LinearLayout>

上面的listview的适配器为simpleCursorAdapter,所以每条对应的item的xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/bill_bottom_bg"android:orientation="vertical"android:layout_marginRight="5dp"android:layout_marginLeft="5dp"android:layout_marginBottom="5dp"android:layout_marginTop="5dp"><RelativeLayout
        android:layout_marginRight="4dp"android:layout_marginLeft="4dp"android:layout_marginBottom="2dp"android:layout_marginTop="4dp"android:background="@drawable/bill_bottom_up_bg"android:layout_width="match_parent"android:layout_height="wrap_content"><TextView
            android:id="@+id/billItem_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Time"android:textColor="#fff"android:textSize="30sp" /><TextView
            android:id="@+id/billItem_budget"android:layout_alignParentRight="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Pay?Income"android:textColor="#fff"android:textSize="30sp"/></RelativeLayout><RelativeLayout
        android:layout_marginRight="4dp"android:layout_marginLeft="4dp"android:layout_marginBottom="4dp"android:layout_marginTop="2dp"android:background="@drawable/bill_bottom_down_bg"android:layout_width="match_parent"android:layout_height="wrap_content"><TextView
            android:id="@+id/billItem_type"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Type"android:textColor="#fff"android:textSize="30sp"/><TextView
            android:id="@+id/billItem_money"android:layout_alignParentRight="true"android:layout_marginLeft="100dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Money"android:textColor="#fff"android:textSize="30sp" /></RelativeLayout></LinearLayout>

这张图为“查看账单”的界面:
这里写图片描述

然后跳转Activity的动画可以自己定义,这里我使用了:

<set xmlns:android="http://schemas.android.com/apk/res/android"><translate
        android:duration="500"android:fromYDelta="100%p"android:toYDelta="0"/><alpha
        android:duration="500"android:fromAlpha="0.0"android:toAlpha="1.0"/>
</set>

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" ><translate
        android:duration="500"android:fromYDelta="0"android:toYDelta="-100%p" /><alpha
        android:duration="500"android:fromAlpha="1.0"android:toAlpha="0.0" />
</set>

基本功能就实现了,后续会完善更多功能。


http://www.ppmy.cn/news/434762.html

相关文章

简账(开源记账软件)-功能介绍

文章目录 简账(开源记账软件)-功能介绍前言一、主要技术栈简介二、主要功能三、项目难点四、总结 简账(开源记账软件)-功能介绍 前言 由于自己有记账的需求&#xff0c;在尝试使用过市面上的记账软件后&#xff0c;发现大多数都有以下几个问题 广告比较多&#xff0c;主要分为…

奚记--最简洁的记账软件

最近几天一直在开发个人的第一个应用--奚记。在昨天我的第一个Android应用终于在豌豆荚平台上架了&#xff0c;真的是激动万分啊&#xff0c;今天就不要脸的来推广介绍下我的软件&#xff0c;让各位见笑我的幼稚的作品了。 奚记&#xff0c;是一款最简洁的记账软件&#xff01…

简单记账本-android版

Android开发也自学了一段时间&#xff0c;家里的pc机上安装了一个家庭理财软件&#xff0c;所以趁着业余时间就用android做了个迷你账本。主要功能其实很简单&#xff1a;账目的添加、修改、删除以及一些统计功能&#xff0c;比如一年的所有收支项统计&#xff0c;一年各月的收…

记账软件哪个好用,亲测有效

当人们从超前消费的狂风中清醒之后&#xff0c;开始对自己的资产重新重视起来了&#xff0c;开始学习记账就成了大家省钱的第一步&#xff0c;但是手写账本非常浪费时间&#xff0c;记起来也比较繁琐&#xff0c;下面就给大家分享几个好用的记账技巧。 电脑端——晨曦记账本 一…

三款好用的记账软件推荐

花钱如流水的我们&#xff0c;是不是还在烦恼记账问题&#xff1f;实际上现在的很多年轻人不仅不爱存钱&#xff0c;也不清楚花的钱都去了哪儿了&#xff0c;这就需要记账了。 根据对比推荐几款用的比较多的免费记账软件&#xff1a;随手记、小鱼记账、松鼠记账。 分别介绍一…

Python网络爬虫开发:使用PyQt5和WebKit构建可定制的爬虫

部分数据来源:ChatGPT 引言 在网络爬虫开发中,使用Web浏览器模拟用户行为是非常重要的。而在这个过程中,基于 WebKit 的框架可以提供比其他技术更紧密的浏览器集成,以及更高效、更多样化的页面交互方式。 在本文中,我们将通过一个使用基于 WebKit 的爬虫示例,并与类似…

实验篇(7.2) 16. 站对站安全隧道 - 通过聚合隧道走对方上网(FortiGate-IPsec) ❀ 远程访问

【简介】前面所有实验基本上是由向导来完成的&#xff0c;只有隧道聚合实验是手动设置的。那么远程访问经常用到的走对方宽带上网功能&#xff0c;需要怎样手动配置呢&#xff1f; 实验要求与环境 OldMei集团深圳总部防火墙现在有三条宽带了&#xff0c;二条普通宽带用来上网及…

mongodbTempalte常用操作方法,增删改查,分页等

一、CRUD之添加 在项目中实现添加时比较简单的&#xff1a; save()与insert是等价的。 Stud stud new Stud(1,"fenganchen",18) //实例化一个实体类 MongodbTemplage.save(stud ); 或者 MongodbTemplage.insert(stud); 二、CRUD之删除 删除也是比较简单的&…