这是一个简单的账本,目前的功能可以实现记账,显示总的支出、收入、结余,查看账单以及删除不想要的账单。后续功能慢慢完善。那么就开始代码和图演示。
如果有不足的地方,希望看到的大神给予指点建议,不胜感激!
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的宽和高 设置自己的宽和高
*/
@Override
protected 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隐藏
*/
@Override
protected 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);
}
}
@Override
public 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();
}
}
//抽屉菜单
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float scale = l * 1.0f / mMenuWidth; // 1 ~ 0
float leftAlpha = 0.6f + 0.4f * (1 - scale);
// 调用属性动画,设置TranslationX
ViewHelper.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;
@Override
protected 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;
}
@Override
public CharSequence getPageTitle(int position) {
return tabList.get(position);
}
@Override
public Fragment getItem(int position) {
return fragList.get(position);
}
@Override
public 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);
}
//首次创建时调用 一般用于建库 建表
@Override
public 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))");
}
@Override
public 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;
@Override
public 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;
}
@Override
public void onDestroy() {
mTimeHandler.removeCallbacksAndMessages(null);
mSqlHelper.close();
mDataBase.close();
super.onDestroy();
}
//跑一个线程handle 动态更新textView
public 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;
@Override
public 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;
}
//点击条目的监听 并进行跳转
@Override
public 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存入sqlite
private ArrayList<String> Data = new ArrayList<String>();
@Override
protected 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中加入选 支出 还是 收入 的不同情况spinner
radioButton_selected = "支出";
mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public 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_type
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
add_type = (String) spinner.getSelectedItem();
}
@Override
public 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);
//时间选择的dialog
timer_chooser.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Calendar c = Calendar.getInstance();
new DatePickerDialog(RecorderActiviity.this, new DatePickerDialog.OnDateSetListener() {
@Override
public 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() {
@Override
public 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() {
@Override
public 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();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
下面是“记一笔”的界面
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;
// 适配器
@Override
protected 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 ID
new 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() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
String cc = c.getString(c.getColumnIndex("_id")); //用cursor得到对应表中的id
Log.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);
}
@Override
public 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>
基本功能就实现了,后续会完善更多功能。