一:app介绍
理财小助手是一款利用Android studio软件实现的APP,可以录入每天的消费项目以及消费金额,同时也可以查找消费记录、统计消费总额。我用到的Android studio版本如下:
二、模块设计
下面是我实现的一些模块:
1:进入理财小助手app时会有一个登陆界面,包括邮箱和密码,邮箱和密码都有限制,如邮箱必须带有@符号,而密码必须不少于特定位数。
2:如果没有登录的邮箱或者密码时选择注册账号:
3:进入理财app先进入理财记录的首页:(此时还没有添加一条记录,首页显示为空)
4:添加一条消费记录,消费主体是lunch,消费金额是12,消费感受是good
5:点击左上方的箭头会默认自动保存此记录,如果点击右上方的X,就会删去这条记录,这样,在理财app的主页就会显示添加的消费记录:
6:也可以双击每一条记录,这样就会出现此记录的详细信息,比如我选择了第一条记录:
7:查看第五个步骤可以发现第五个步骤的图像右上方有三个符号,第一个+符号是添加一条记录,第二个符号是查找消息记录,第三个符号是可以统计金钱总额也可以显示出所有的消费记录:
第一个符号:
第二个符号查找记录:
第三符号有两个功能:
(1):统计功能:
比如统计今天记录:2022年1月15日
(2)显示记录的条数:如下,显示了添加的两条记录
三、代码设计
此代码设计分为两个部分,一个为前端的局面分布,一个为后端的java编写。如下:
1:java文件夹里面包含的是后端的代码,其中包含了database和wengxiaoyang.personalfinanceassistant。其中包括的类如下图所示:
2:res文件夹里面包括的是图片和前端代码,包括button或者布局等,是安卓必须掌握的基础知识点。
其中可可爱爱的蜡笔小新就来自与drawable,当然也可以换成其他的图片啦。在这里插入图片描述
layout里面存放的就是整个app的布局:
menu用来控制右上方的三个符号功能:
values用来控制button按钮:
注意:其他没有特别说明就是图片。
四、详细代码
1:先贴入java后端的代码
database中的ManageBaseHelp类
package database;
//数据库的继承类,并重写两种方法
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;import database.ManageDbSchema.ManageTable;
import database.ManageDbSchema.ManageTable2;
//打开数据库
public class ManageBaseHelper extends SQLiteOpenHelper {private static final int VERSION = 1;private static final String DATABASE_NAME = "manageBase.db";
//在此构造方法中用super方法调用父类的构造方法。传入四个参数,上下文对象,数据库名称,null,数据库版本public ManageBaseHelper(Context context) {super(context, DATABASE_NAME, null, VERSION);}//重写子类的onCreate方法@Overridepublic void onCreate(SQLiteDatabase db) {// manage表,暴力名称,金钱,支付方式等db.execSQL("create table " + ManageTable.NAME + "(" +"_id integer primary key autoincrement, " +ManageTable.Cols.UUID + ", " +ManageTable.Cols.TITLE + ", " +ManageTable.Cols.MONEY + ", " +ManageTable.Cols.DATE + ", " +ManageTable.Cols.PAYMETHOD + ", " +ManageTable.Cols.REMARK + ")");// 账号密码表db.execSQL("create table " + ManageTable2.NAME2 + "(" +"_id integer primary key autoincrement, " +ManageTable2.Cols2.UUID + ", " +ManageTable2.Cols2.ACCOUNT + ", " +ManageTable2.Cols2.PASSWORD + ")");}//重写子类的onUpgrade方法@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}
ManageCursorWrapper类
package database;
//将用户信息和消费消息写入数据库
import android.database.Cursor;
import android.database.CursorWrapper;import java.util.Date;
import java.util.UUID;import database.ManageDbSchema.ManageTable;
import database.ManageDbSchema.ManageTable2;
import wengxiaoyang.personalfinanceassistant.Login;
import wengxiaoyang.personalfinanceassistant.Manage;
//获得manage和login表格填写时的信息,并把他们放入数据库里面
public class ManageCursorWrapper extends CursorWrapper {public ManageCursorWrapper(Cursor cursor) {super(cursor);}public Manage getManage() {// 获得manage信息String uuidString = getString(getColumnIndex(ManageTable.Cols.UUID));//得到相对应的列索引,并赋值给string对象String title = getString(getColumnIndex(ManageTable.Cols.TITLE));String money = getString(getColumnIndex(ManageTable.Cols.MONEY));Long date = getLong(getColumnIndex(ManageTable.Cols.DATE));int payMethod = getInt(getColumnIndex(ManageTable.Cols.PAYMETHOD));String remark = getString(getColumnIndex(ManageTable.Cols.REMARK));// 将数据写入数据库Manage manage = new Manage(UUID.fromString(uuidString));manage.setTitle(title);manage.setMoney(money);manage.setDate(new Date(date));manage.setPayMethod(payMethod);manage.setRemark(remark);return manage;}public Login getLogin() {// 获得登录信息String uuidString = getString(getColumnIndex(ManageTable2.Cols2.UUID));String account = getString(getColumnIndex(ManageTable2.Cols2.ACCOUNT));String password = getString(getColumnIndex(ManageTable2.Cols2.PASSWORD));// 将登录信息存入数据库Login login = new Login(UUID.fromString(uuidString));login.setAccount(account);login.setPassword(password);return login;}
}
ManageDbSchema类
package database;public class ManageDbSchema {// Manage表,定义常量public static final class ManageTable {public static final String NAME = "manages";public static final class Cols {public static final String UUID = "uuid";public static final String TITLE = "title";public static final String MONEY = "money";public static final String DATE = "date";public static final String PAYMETHOD = "paymethod";public static final String REMARK = "remark";}}// 账号密码表public static final class ManageTable2 {public static final String NAME2 = "login";public static final class Cols2 {public static final String UUID = "uuid";public static final String ACCOUNT = "account";public static final String PASSWORD = "password";}}}
然后开始编写wengxiaoyang.personalfinanceassistant部分
DatePickerFragment类
package wengxiaoyang.personalfinanceassistant;import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.DatePicker;import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
//记录花销的日期(年月日)
public class DatePickerFragment extends DialogFragment {public static final String EXTRA_DATE = "wengxiaoyang.hziee.criminalintent.date";private static final String ARG_DATE = "date";private DatePicker mDatePicker;public static DatePickerFragment newInstance(Date date) {Bundle args = new Bundle();args.putSerializable(ARG_DATE, date);DatePickerFragment fragment = new DatePickerFragment();fragment.setArguments(args);return fragment;}@NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {Date date = (Date) getArguments().getSerializable(ARG_DATE);Calendar calendar = Calendar.getInstance();calendar.setTime(date);int year = calendar.get(Calendar.YEAR);int month = calendar.get(Calendar.MONTH);int day = calendar.get(Calendar.DAY_OF_MONTH);View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_date, null);mDatePicker = v.findViewById(R.id.dialog_date_picker);mDatePicker.init(year, month, day, null);return new AlertDialog.Builder(getActivity()).setView(v).setTitle(R.string.date_picker_title).setPositiveButton(android.R.string.ok,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {int year = mDatePicker.getYear();int month = mDatePicker.getMonth();int day = mDatePicker.getDayOfMonth();Date date = new GregorianCalendar(year, month, day).getTime();sendResult(Activity.RESULT_OK, date);}}).create();}private void sendResult(int resultCode, Date date) {if (getTargetFragment() == null) {return;}Intent intent = new Intent();intent.putExtra(EXTRA_DATE, date);getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode,intent);}
}
Login
package wengxiaoyang.personalfinanceassistant;
import java.util.UUID;
public class Login {private UUID mId;private String mAccount;private String mPassword;public Login() {this(UUID.randomUUID());}public Login(UUID id) {mId = id;}public UUID getId() {return mId;}public String getAccount() {return mAccount;}public void setAccount(String account) {mAccount = account;}public String getPassword() {return mPassword;}public void setPassword(String password) {mPassword = password;}}
LoginActivity
package wengxiaoyang.personalfinanceassistant;import android.content.Context;
import android.content.Intent;
import android.support.v4.app.Fragment;public class LoginActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new LoginFragment();}public static Intent newIntent(Context packageContext) {Intent intent = new Intent(packageContext, LoginActivity.class);return intent;}}
LoginFragment
package wengxiaoyang.personalfinanceassistant;import android.support.v4.app.Fragment;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;import android.os.Build;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;public class LoginFragment extends Fragment {// UIprivate AutoCompleteTextView mEmailView;private EditText mPasswordView;private Button mRegisterButton;private View mProgressView;private View mLoginFormView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}//onCreateView是创建该fragment的视图,并返回给调用者。public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_login, container, false);// 建立视图mEmailView = (AutoCompleteTextView) view.findViewById(R.id.email);mPasswordView = (EditText) view.findViewById(R.id.password);mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {@Overridepublic boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {//输入密码之后监听哪个按钮的触发if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {//对应“完成”按钮和回车按钮,说明选择的是登录而不是注册attemptLogin();return true;}return false;}});Button mEmailSignInButton = (Button) view.findViewById(R.id.email_sign_in_button);//登录按钮mEmailSignInButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {attemptLogin();}});//设置监听,调用attemplogin方法判断邮箱和密码是否正确mRegisterButton = view.findViewById(R.id.register_button);//注册按钮mRegisterButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {//跳转到注册界面Intent intent = new Intent(getActivity(), RegisterActivity.class);startActivity(intent);}});mLoginFormView = view.findViewById(R.id.login_form);mProgressView = view.findViewById(R.id.login_progress);return view;}private void attemptLogin() {//判断邮箱和密码是否能和数据库里面的数据匹配// 重置,不能记住密码mEmailView.setError(null);mPasswordView.setError(null);// 获取登录的信息String email = mEmailView.getText().toString();String password = mPasswordView.getText().toString();boolean cancel = false;View focusView = null;// 校验账号和密码if (login(email, password)) {//调用下面的login方法进行邮箱密码比对,比对在loginlab中进行mEmailView.setError(getString(R.string.error_error_acpw));focusView = mEmailView;cancel = true;//比对不成功则提示报错}if (cancel) {// 聚焦到错误发生地focusView.requestFocus();} else {// 成功登录showProgress(true);// 跳转到ManageListActivityIntent intent = ManageListActivity.newIntent(getActivity());startActivity(intent);}}@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)// 动画private void showProgress(final boolean show) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);mLoginFormView.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);}});mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);mProgressView.animate().setDuration(shortAnimTime).alpha(show ? 1 : 0).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);}});} else {// 若API不支持,则简单显示mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);}}public boolean login(String account, String password) {//验证此账号密码是否正确Login login = LoginLab.get(getActivity()).getAccountAndPassword(account, password);if (login != null) {return false;} elsereturn true;}
}
LoginLab
package wengxiaoyang.personalfinanceassistant;import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;import database.ManageDbSchema.ManageTable2;
import database.ManageCursorWrapper;
import database.ManageBaseHelper;public class LoginLab {private static LoginLab sLoginLab;private Context mContext;private SQLiteDatabase mDatabase;// 构造方法private LoginLab(Context context) {mContext = context.getApplicationContext();mDatabase = new ManageBaseHelper(mContext).getWritableDatabase();//获得可读写操作对象}// 注册界面添加账号密码,创建contentvalues对象,调用mdatabase的insert方法将数据插入到数据库里面public void addLogin(Login l) {ContentValues values = getContentValues(l);mDatabase.insert(ManageTable2.NAME2, null, values);}// 在数据库中找到Login表,也就是table2private ManageCursorWrapper queryLogin(String whereClause, String[] whereArgs) {Cursor cursor = mDatabase.query(ManageTable2.NAME2,null,// null selects all columnswhereClause,whereArgs,null,null,null);return new ManageCursorWrapper(cursor);}// 根据返回的参数cursor,在找到的login表里面再根据账号密码查找对应的用户public Login getAccountAndPassword(String account, String password) {ManageCursorWrapper cursor = queryLogin(ManageTable2.Cols2.ACCOUNT + " = ? and " + ManageTable2.Cols2.PASSWORD+ " = ?",new String[] { account, password });try {if (cursor.getCount() == 0) {//此用户不存在return null;}cursor.moveToFirst();//从表的第一个用户开始查找return cursor.getLogin();} finally {cursor.close();}}// 获得Login数据,后一个参数的值赋给前面的一个参数,返回的login的值进行对比private static ContentValues getContentValues(Login login) {ContentValues values = new ContentValues();values.put(ManageTable2.Cols2.UUID, login.getId().toString());values.put(ManageTable2.Cols2.ACCOUNT, login.getAccount());values.put(ManageTable2.Cols2.PASSWORD, login.getPassword());return values;}// 根据上下文获取LoginLabpublic static LoginLab get(Context context) {if (sLoginLab == null) {sLoginLab = new LoginLab(context);}return sLoginLab;}}
Manage
package wengxiaoyang.personalfinanceassistant;import java.util.Date;
import java.util.UUID;public class Manage {private UUID mId;private String mTitle;private String mMoney;private Date mDate;private int mPayMethod;private String mRemark;public Manage() {this(UUID.randomUUID());}public Manage(UUID id) {mId = id;mDate = new Date();}public UUID getId() {return mId;}public String getTitle() {return mTitle;}public void setTitle(String title) {mTitle = title;}public String getMoney() {return mMoney;}public void setMoney(String money) {mMoney = money;}public Date getDate() {return mDate;}public void setDate(Date date) {mDate = date;}public int getPayMethod() {return mPayMethod;}public void setPayMethod(int payMethod) {mPayMethod = payMethod;}public String getRemark() {return mRemark;}public void setRemark(String remark) {mRemark = remark;}public String getPhotoFilename() {return "IMG_" + getId().toString() + ".jpg";}}
ManageFragment
package wengxiaoyang.personalfinanceassistant;import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.ShareCompat;
import android.support.v4.content.FileProvider;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
//manager的总布局public class ManageFragment extends Fragment {private static final String ARG_MANAGE_ID = "manage_id";private static final String DIALOG_DATE = "dialogDate";private static final String DIALOG_TIME = "dialogTime";private static final String DIALOG_PHOTO = "dialogPhoto";private static final int REQUEST_DATE = 0;private static final int REQUEST_TIME = 0;private static final int REQUEST_PHOTO = 3;private Manage mManage;private File mPhotoFile;private EditText mTitleField;private EditText mMoneyField;private Button mDateButton;private RadioGroup mRadioGroup;private RadioButton mRadioButton_cash;private RadioButton mRadioButton_card;private EditText mRemarkField;private Button mTimeButton;private Button mReportButton;private ImageButton mPhotoButton;private ImageView mPhotoView;//根据ID创建实例public static ManageFragment newInstance(UUID manageId) {Bundle args = new Bundle();args.putSerializable(ARG_MANAGE_ID, manageId);ManageFragment fragment = new ManageFragment();fragment.setArguments(args);return fragment;}// 保存部分数据@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);UUID manageId = (UUID) getArguments().getSerializable(ARG_MANAGE_ID);mManage = ManageLab.get(getActivity()).getManage(manageId);setHasOptionsMenu(true);mPhotoFile = ManageLab.get(getActivity()).getPhotoFile(mManage);}@Overridepublic void onPause() {super.onPause();// 更新数据库数据ManageLab.get(getActivity()).updateManage(mManage);}// UI@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View v = inflater.inflate(R.layout.fragment_manage, container, false);// 标题mTitleField = v.findViewById(R.id.manage_title);mTitleField.setText(mManage.getTitle());mTitleField.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {mManage.setTitle(s.toString());}@Overridepublic void afterTextChanged(Editable s) {}});// 金额mMoneyField = v.findViewById(R.id.manage_money);mMoneyField.setText(mManage.getMoney());mMoneyField.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {mManage.setMoney(s.toString());}@Overridepublic void afterTextChanged(Editable s) {}});// 日期mDateButton = v.findViewById(R.id.manage_date);Date date = mManage.getDate();updateDate();mDateButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {FragmentManager manager = getFragmentManager();DatePickerFragment dialog = DatePickerFragment.newInstance(mManage.getDate());dialog.setTargetFragment(ManageFragment.this, REQUEST_DATE);dialog.show(manager, DIALOG_DATE);}});// 时间mTimeButton = v.findViewById(R.id.manage_time);String dateString2 = (String) DateFormat.format("h:mm a", date);updateTime(dateString2);mTimeButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {FragmentManager manager = getFragmentManager();TimePickerFragment dialog = TimePickerFragment.newInstance(mManage.getDate());dialog.setTargetFragment(ManageFragment.this, REQUEST_TIME);dialog.show(Objects.requireNonNull(manager), DIALOG_TIME); //第二个参数是tag}});// 支付方式mRadioGroup = v.findViewById(R.id.manage_pay_method);mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {Manage manage = new Manage();switch (checkedId) {case R.id.manage_cash:manage.setPayMethod(1);break;case R.id.manage_card:manage.setPayMethod(2);break;default:break;}}});System.out.println(mManage.getPayMethod());mRadioButton_cash = v.findViewById(R.id.manage_cash);mRadioButton_card = v.findViewById(R.id.manage_card);int PayMethod = mManage.getPayMethod();if (PayMethod == 1) {mRadioButton_cash.setChecked(true);} else if (PayMethod == 2) {mRadioButton_card.setChecked(true);}// 备注mRemarkField = v.findViewById(R.id.manage_remark);mRemarkField.setText(mManage.getRemark());mRemarkField.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {mManage.setRemark(s.toString());}@Overridepublic void afterTextChanged(Editable s) {}});// 发送报告mReportButton = v.findViewById(R.id.manage_report);mReportButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ShareCompat.IntentBuilder i = ShareCompat.IntentBuilder.from(getActivity());i.setType("text/plain");i.setText(getManageReport());i.setSubject(getString(R.string.manage_report_subject));i.createChooserIntent();i.startChooser();}});PackageManager packageManager = getActivity().getPackageManager();// 拍照mPhotoButton = v.findViewById(R.id.manage_camera);final Intent captureImage = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 如果不能拍照就禁用按钮boolean canTakePhoto = mPhotoFile != null &&captureImage.resolveActivity(packageManager) != null;mPhotoButton.setEnabled(canTakePhoto);// 跳转到相机mPhotoButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Uri uri = FileProvider.getUriForFile(getActivity(),"wengxiaoyang.personalfinanceassistant.fileprovider", mPhotoFile);captureImage.putExtra(MediaStore.EXTRA_OUTPUT, uri);List<ResolveInfo> cameraActivities = getActivity().getPackageManager().queryIntentActivities(captureImage, PackageManager.MATCH_DEFAULT_ONLY);for (ResolveInfo activity : cameraActivities) {getActivity().grantUriPermission(activity.activityInfo.packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);}startActivityForResult(captureImage, REQUEST_PHOTO);}});// 显示照片mPhotoView = v.findViewById(R.id.manage_photo);mPhotoView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mPhotoFile == null || !mPhotoFile.exists()) {mPhotoView.setImageDrawable(null);} else {FragmentManager manager = getFragmentManager();PhotoDetailFragment dialog = PhotoDetailFragment.newInstance(mPhotoFile);dialog.setTargetFragment(ManageFragment.this, REQUEST_PHOTO);dialog.show(manager, DIALOG_PHOTO);}}});ViewTreeObserver mPhotoObserver = mPhotoView.getViewTreeObserver();mPhotoObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {updatePhotoView(mPhotoView.getWidth(), mPhotoView.getHeight());}});return v;}// 根据需求更新视图@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode != Activity.RESULT_OK) {return;}if (requestCode == REQUEST_DATE) {Date date = (Date) data.getSerializableExtra(DatePickerFragment.EXTRA_DATE);mManage.setDate(date);updateDate();}if (requestCode == REQUEST_TIME) {Date date = mManage.getDate();String dateString2 = (String) DateFormat.format("h:mm a", date);updateTime(dateString2);}else if (requestCode == REQUEST_PHOTO) {Uri uri = FileProvider.getUriForFile(getActivity(),"wengxiaoyang.personalfinanceassistant.fileprovider", mPhotoFile);getActivity().revokeUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);updatePhotoView(mPhotoView.getWidth(), mPhotoView.getHeight());}}// 创建菜单@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {super.onCreateOptionsMenu(menu, inflater);inflater.inflate(R.menu.fragment_manage, menu);}// 根据选择响应@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.delete_manage:ManageLab.get(getActivity()).removeManage(mManage);getActivity().finish();return true;case android.R.id.home: //向上导航时保证子标题可见状态getActivity().finish();return true;default:return super.onOptionsItemSelected(item);}}private void updateDate() {mDateButton.setText(mManage.getDate().toString());}private void updateTime(String s) {mTimeButton.setText(s);}// 发送报告private String getManageReport() {String payString = null;if (mManage.getPayMethod() == 1) {payString = getString(R.string.manage_report_cash);} else if (mManage.getPayMethod() == 2){payString = getString(R.string.manage_report_card);}String dateString = (String) DateFormat.format("EEE, MMM dd, yyyy", mManage.getDate());String report = getString(R.string.manage_report,mManage.getTitle(), dateString, payString, mManage.getRemark());return report;}// 更新照片视图private void updatePhotoView(int width, int height) {if (mPhotoFile == null || !mPhotoFile.exists()) {mPhotoView.setImageDrawable(null);} else {Bitmap bitmap = PictureUtils.getScaledBitmap(mPhotoFile.getPath(), width, height);mPhotoView.setImageBitmap(bitmap);}}}
ManageLab
package wengxiaoyang.personalfinanceassistant;import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;import database.ManageDbSchema.ManageTable;
import database.ManageCursorWrapper;
import database.ManageBaseHelper;
//对每一条记录的操作:增加、删除、修改、查找
public class ManageLab {private static ManageLab sManageLab;private Context mContext;private SQLiteDatabase mDatabase;private ManageLab(Context context) {mContext = context.getApplicationContext();mDatabase = new ManageBaseHelper(mContext).getWritableDatabase();}// 添加记录public void addManage(Manage m) {ContentValues values = getContentValues(m);mDatabase.insert(ManageTable.NAME, null, values);}// 删除记录public void removeManage(Manage c) {String uuidString = c.getId().toString();mDatabase.delete(ManageTable.NAME, ManageTable.Cols.UUID + " = ?", new String[]{uuidString});}// 得到照片public File getPhotoFile(Manage manage) {File filesDir = mContext.getFilesDir();return new File(filesDir, manage.getPhotoFilename());}// 更新记录public void updateManage(Manage manage) {String uuidString = manage.getId().toString();ContentValues values = getContentValues(manage);mDatabase.update(ManageTable.NAME, values, ManageTable.Cols.UUID + " = ?", new String[]{uuidString});}// 查找记录private ManageCursorWrapper queryManages(String whereClause, String[] whereArgs) {Cursor cursor = mDatabase.query(ManageTable.NAME,null,// null selects all columnswhereClause,whereArgs,null,null,null);return new ManageCursorWrapper(cursor);}// 得到Manages集合public List<Manage> getManages() {List<Manage> manages = new ArrayList<>();ManageCursorWrapper cursor = queryManages(null,null);try {cursor.moveToFirst();while (!cursor.isAfterLast()) {manages.add(cursor.getManage());cursor.moveToNext();}}finally {cursor.close();}return manages;}// 根据ID获取Managepublic Manage getManage(UUID id) {ManageCursorWrapper cursor = queryManages(ManageTable.Cols.UUID + " = ?",new String[] { id.toString() });try {if (cursor.getCount() == 0) {return null;}cursor.moveToFirst();return cursor.getManage();} finally {cursor.close();}}// 获得数据库数据private static ContentValues getContentValues(Manage manage) {ContentValues values = new ContentValues();values.put(ManageTable.Cols.UUID, manage.getId().toString());values.put(ManageTable.Cols.TITLE, manage.getTitle());values.put(ManageTable.Cols.MONEY, manage.getMoney());values.put(ManageTable.Cols.DATE, manage.getDate().getTime());values.put(ManageTable.Cols.PAYMETHOD, manage.getPayMethod());values.put(ManageTable.Cols.REMARK, manage.getRemark());return values;}public static ManageLab get(Context context) {if (sManageLab == null) {sManageLab = new ManageLab(context);}return sManageLab;}}
ManageListActivity
package wengxiaoyang.personalfinanceassistant;import android.content.Context;
import android.content.Intent;
import android.support.v4.app.Fragment;public class ManageListActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new ManageListFragment();}public static Intent newIntent(Context packageContext) {Intent intent = new Intent(packageContext, ManageListActivity.class);return intent;}
}
ManageFragment
package wengxiaoyang.personalfinanceassistant;import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
//显示消费记录public class ManageListFragment extends Fragment {private RecyclerView mManageRecyclerView;private ManageAdapter mAdapter;private static int mManageIndex;private boolean mSubtitleVisible;private TextView mNullManageListTextView;private Button mAddManageButton;private static final String SAVED_SUBTITLE_VISIBLE = "subtitle";@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setHasOptionsMenu(true);}// UI@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_manage_list, container, false);mManageRecyclerView = view.findViewById(R.id.manage_recycler_view);mManageRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));mNullManageListTextView = view.findViewById(R.id.null_manage_list);mAddManageButton = view.findViewById(R.id.add_manage);mAddManageButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Manage manage = new Manage();ManageLab.get(getActivity()).addManage(manage);//下面的两个按钮Intent intent = ManagePagerActivity.newIntent(getActivity(), manage.getId());startActivity(intent);}});// 保持记录条数可见if (savedInstanceState != null) {mSubtitleVisible = savedInstanceState.getBoolean(SAVED_SUBTITLE_VISIBLE);}updateUI();return view;}@Overridepublic void onResume() {super.onResume();updateUI();}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putBoolean(SAVED_SUBTITLE_VISIBLE, mSubtitleVisible);}// 创建菜单@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {super.onCreateOptionsMenu(menu, inflater);inflater.inflate(R.menu.fragment_manage_list, menu);MenuItem subtitleItem = menu.findItem(R.id.show_subtitle);if (mSubtitleVisible) {subtitleItem.setTitle(R.string.hide_subtitle);} else {subtitleItem.setTitle(R.string.show_subtitle);}}// 响应菜单点击@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.new_manage: // 创建新记录Manage manage = new Manage();ManageLab.get(getActivity()).addManage(manage);Intent intent = ManagePagerActivity.newIntent(getActivity(), manage.getId());startActivity(intent);return true;case R.id.search_manage: //搜索intent = SearchActivity.newIntent(getActivity());startActivity(intent);return true;case R.id.statistic_manage: //统计intent = new Intent(getActivity(), StatisticActivity.class);startActivity(intent);return true;case R.id.show_subtitle: //显示记录条数mSubtitleVisible = !mSubtitleVisible;getActivity().invalidateOptionsMenu();updateSubtitle();return true;default:return super.onOptionsItemSelected(item);}}// 更新记录条数private void updateSubtitle() {ManageLab manageLab = ManageLab.get(getActivity());int manageCount = manageLab.getManages().size();String subtitle = getString(R.string.subtitle_format, manageCount);if (!mSubtitleVisible) {subtitle = null;}AppCompatActivity activity = (AppCompatActivity) getActivity();activity.getSupportActionBar().setSubtitle(subtitle);}// 更新UI界面private void updateUI() {ManageLab manageLab = ManageLab.get(getActivity());List<Manage> manages = manageLab.getManages();if (mAdapter == null) {mAdapter = new ManageAdapter(manages);mManageRecyclerView.setAdapter(mAdapter);} else {//重绘当前可见区域//mAdapter.notifyDataSetChanged();//部分重绘mAdapter.setManages(manages);mAdapter.notifyItemChanged(mManageIndex);}if (manages.size() != 0) {mNullManageListTextView.setVisibility(View.INVISIBLE);mAddManageButton.setVisibility(View.INVISIBLE);} else {mNullManageListTextView.setVisibility(View.VISIBLE);mAddManageButton.setVisibility(View.VISIBLE);}updateSubtitle();}private class ManageHolder extends RecyclerView.ViewHolder implements View.OnClickListener {private TextView mTitleTextView;private TextView mDateTextView;private Manage mManage;public ManageHolder(LayoutInflater inflater, ViewGroup parent) {super(inflater.inflate(R.layout.list_item_manage, parent, false));itemView.setOnClickListener(this);mTitleTextView = itemView.findViewById(R.id.manage_title);mDateTextView = itemView.findViewById(R.id.manage_date);}public void bind(Manage manage) {mManage = manage;mTitleTextView.setText(mManage.getTitle());Date date = manage.getDate();mDateTextView.setText(date.toString());}@Overridepublic void onClick(View view) {Intent intent = ManagePagerActivity.newIntent(getActivity(), mManage.getId());mManageIndex = getAdapterPosition(); //返回数据在adapter中的位置startActivity(intent);}}private class ManageAdapter extends RecyclerView.Adapter {private List<Manage> mManages;public ManageAdapter(List<Manage> manages) {mManages = manages;}//视图类别功能@NonNull@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {//先建立LayoutInflaterLayoutInflater layoutInflater = LayoutInflater.from(getActivity());return new ManageHolder(layoutInflater, parent);}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {Manage manage = mManages.get(position);((ManageHolder)holder).bind(manage);}@Overridepublic int getItemCount() {return mManages.size();}public void setManages(List<Manage> manages) {mManages = manages;}}}
ManagePagerActivity
package wengxiaoyang.personalfinanceassistant;import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;import java.util.List;
import java.util.UUID;
//主页的最下面两个按钮,可依次跳转支出的详情界面,tolast and tofirst
public class ManagePagerActivity extends AppCompatActivity {private static final String EXTRA_MANAGE_ID = "wengxiaoyang.personalfinanceassistant.manage_id";private static final String EXTRA_MANAGE_TITLE = "wengxiaoyang.personalfinanceassistant.manage_title";private ViewPager mViewPager;private List<Manage> mManages;private Button btn_first;private Button btn_last;public static Intent newIntent(Context packageContext, UUID manageId) {Intent intent = new Intent(packageContext, ManagePagerActivity.class);intent.putExtra(EXTRA_MANAGE_ID, manageId);return intent;}public static Intent newIntent(Context packageContext, String title) {Intent intent = new Intent(packageContext, ManagePagerActivity.class);intent.putExtra(EXTRA_MANAGE_TITLE, title);return intent;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_manage_pager);UUID manageId = (UUID) getIntent().getSerializableExtra(EXTRA_MANAGE_ID);mViewPager = findViewById(R.id.manage_view_pager);// 根据所处位置隐藏按钮mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {if (position == 0) {btn_first.setVisibility(View.INVISIBLE);btn_last.setVisibility(View.VISIBLE);} else if (position == mManages.size() - 1) {btn_first.setVisibility(View.VISIBLE);btn_last.setVisibility(View.INVISIBLE);} else {btn_first.setVisibility(View.VISIBLE);btn_last.setVisibility(View.VISIBLE);}}@Overridepublic void onPageSelected(int i) {}@Overridepublic void onPageScrollStateChanged(int i) {}});btn_first = findViewById(R.id.btn_to_first);btn_first.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mViewPager.setCurrentItem(0);}});btn_last = findViewById(R.id.btn_to_last);btn_last.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mViewPager.setCurrentItem(mManages.size() - 1);}});mManages = ManageLab.get(this).getManages();FragmentManager fragmentManager = getSupportFragmentManager();mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {@Overridepublic Fragment getItem(int position) {Manage manage = mManages.get(position);return ManageFragment.newInstance(manage.getId());}@Overridepublic int getCount() {return mManages.size();}});// 给每条记录编号for (int i = 0; i < mManages.size(); i++) {if (mManages.get(i).getId().equals(manageId)) {mViewPager.setCurrentItem(i);break;}}}
}
PhotoDetailFragment
package wengxiaoyang.personalfinanceassistant;import android.app.AlertDialog;
import android.app.Dialog;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;import java.io.File;public class PhotoDetailFragment extends DialogFragment {private static final String ARG_FILE = "file";private ImageView mPhotoView;// 照片细节public static PhotoDetailFragment newInstance(File file) {Bundle args = new Bundle();args.putSerializable(ARG_FILE, file);PhotoDetailFragment fragment =new PhotoDetailFragment();fragment.setArguments(args);return fragment;}// 创建对话框@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {File file = (File) getArguments().getSerializable(ARG_FILE);View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_photo, null);mPhotoView = v.findViewById(R.id.manage_photo_detail);Bitmap bitmap = PictureUtils.getScaledBitmap(file.getPath(), getActivity());mPhotoView.setImageBitmap(bitmap);return new AlertDialog.Builder(getActivity()).setView(v).setPositiveButton(android.R.string.ok, null).create();}
}
PictureUtils
package wengxiaoyang.personalfinanceassistant;import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;public class PictureUtils {public static Bitmap getScaledBitmap(String path, int destWidth, int destHeight) {//读入磁盘上图像的尺寸BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, options);float srcWidth = options.outWidth;float srcHeight = options.outHeight;//弄清要减少多少int inSampleSize = 1;if (srcHeight > destHeight || srcWidth > destWidth) {float heightScale = srcHeight / destHeight;float widthScale = srcWidth / destWidth;inSampleSize = Math.round(heightScale > widthScale ? heightScale : widthScale);}options = new BitmapFactory.Options();options.inSampleSize = inSampleSize;//读入和创建常量bitmapreturn BitmapFactory.decodeFile(path, options);}public static Bitmap getScaledBitmap(String path, Activity activity) {Point size = new Point();activity.getWindowManager().getDefaultDisplay().getSize(size);return getScaledBitmap(path, size.x, size.y);}
}
RegisterActivity
package wengxiaoyang.personalfinanceassistant;import android.support.v4.app.Fragment;public class RegisterActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new RegisterFragment();}
}
RegisterFragment
package wengxiaoyang.personalfinanceassistant;
//注册界面
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.support.v4.app.Fragment;public class RegisterFragment extends Fragment {// UIprivate AutoCompleteTextView mEmailView;private EditText mPasswordView;private View mProgressView;private View mLoginFormView;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// 布局//onCreateView是创建该fragment的视图,并返回给调用者。View view = inflater.inflate(R.layout.fragment_register, container, false);mEmailView = (AutoCompleteTextView) view.findViewById(R.id.email);mPasswordView = (EditText) view.findViewById(R.id.password);mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {@Overridepublic boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {//输入密码之后监听触发了哪个按钮attemptLogin();return true;}return false;}});Button mEmailSignInButton = (Button) view.findViewById(R.id.email_sign_in_button);//登录按钮mEmailSignInButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {attemptLogin();}});mLoginFormView = view.findViewById(R.id.register_form);mProgressView = view.findViewById(R.id.register_progress);return view;}private void attemptLogin() {// 重置错误mEmailView.setError(null);mPasswordView.setError(null);// 获取输入内容String email = mEmailView.getText().toString();String password = mPasswordView.getText().toString();boolean cancel = false;View focusView = null;// 检查密码是否有效if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {mPasswordView.setError(getString(R.string.error_invalid_password));focusView = mPasswordView;cancel = true;}// 确认有效的邮箱地址if (TextUtils.isEmpty(email)) {mEmailView.setError(getString(R.string.error_field_required));focusView = mEmailView;cancel = true;} else if (!isEmailValid(email)) {mEmailView.setError(getString(R.string.error_invalid_email));focusView = mEmailView;cancel = true;}if (cancel) {// 聚焦到错误发生地focusView.requestFocus();} else {// 成功后showProgress(true);// 将数据添加进数据库Login login = new Login();login.setAccount(email);login.setPassword(password);LoginLab.get(getActivity()).addLogin(login);Intent intent = LoginActivity.newIntent(getActivity());startActivity(intent);}}private boolean isEmailValid(String email) {//邮箱必须有@符号//TODO: Replace this with your own logicreturn email.contains("@");}private boolean isPasswordValid(String password) {//密码太短//TODO: Replace this with your own logicreturn password.length() > 4;}@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)private void showProgress(final boolean show) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);mLoginFormView.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);}});mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);mProgressView.animate().setDuration(shortAnimTime).alpha(show ? 1 : 0).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);}});} else {// The ViewPropertyAnimator APIs are not available, so simply show// and hide the relevant UI components.mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);}}}
SearchActivity
package wengxiaoyang.personalfinanceassistant;import android.content.Context;
import android.content.Intent;
import android.support.v4.app.Fragment;public class SearchActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new SearchFragment();}public static Intent newIntent(Context packageContext) {Intent intent = new Intent(packageContext, SearchActivity.class);return intent;}}
SearchFragment
package wengxiaoyang.personalfinanceassistant;import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;public class SearchFragment extends Fragment {// UIprivate TextView mTextView;private EditText mSearchView;private Button mSearchButton;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// 布局View view = inflater.inflate(R.layout.fragment_search, container, false);mTextView = view.findViewById(R.id.textView_search);mSearchView = (EditText) view.findViewById(R.id.edit_search);mSearchButton = (Button) view.findViewById(R.id.button_search1);// 跳转到搜索的activitymSearchButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {String search = mSearchView.getText().toString();Intent intent = ManagePagerActivity.newIntent(getActivity(), search);startActivity(intent);}});return view;}
}
SingleFragmentActivity
package wengxiaoyang.personalfinanceassistant;import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;public abstract class SingleFragmentActivity extends AppCompatActivity {protected abstract Fragment createFragment();// 创建fragment@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_fragment);FragmentManager fm = getSupportFragmentManager();Fragment fragment = fm.findFragmentById(R.id.fragment_container);if (fragment == null) {fragment = createFragment();fm.beginTransaction().add(R.id.fragment_container, fragment).commit();}}
}
StatisticActivity
package wengxiaoyang.personalfinanceassistant;import android.support.v4.app.Fragment;public class StatisticActivity extends SingleFragmentActivity {@Overrideprotected Fragment createFragment() {return new StatisticFragment();}}
StatisticFragment
package wengxiaoyang.personalfinanceassistant;import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
//统计年月日的花销总额度
public class StatisticFragment extends Fragment {private EditText mYear;private EditText mMonth;private EditText mDay;private Button mButton;private TextView mMoney;private Double totalMoney = 0.0;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// 布局View view = inflater.inflate(R.layout.fragment_statistic, container, false);// 年mYear = view.findViewById(R.id.edit_year);// 月mMonth = view.findViewById(R.id.edit_month);// 日mDay = view.findViewById(R.id.edit_day);mButton = view.findViewById(R.id.button_statistic);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 获取输入框内容String year = mYear.getText().toString();String month = mMonth.getText().toString();String day = mDay.getText().toString();// 查找到所有记录List<Manage> manages = ManageLab.get(getActivity()).getManages();// 匹配有相同时间的记录,获得其金额并相加for (int i = 0; i < manages.size(); i++){if (year.equals(manages.get(i).getDate().toString().substring(24,28)) || month.equals(manages.get(i).getDate().toString().substring(4,7)) || day.equals(manages.get(i).getDate().toString().substring(8,10))) {totalMoney += Double.parseDouble(manages.get(i).getMoney());}}mMoney.setText(totalMoney.toString() + "元");totalMoney = 0.0;}});mMoney = view.findViewById(R.id.text_money);return view;}
}
TimePickerFragment
package wengxiaoyang.personalfinanceassistant;import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TimePicker;import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
//支出具体的时间(小时、分钟、秒)
public class TimePickerFragment extends DialogFragment {//两个按钮公用一个EXTRA_DATE,所以不用新添加一个TimePicker专用的RXTRA_TIMEpublic static final String EXTRA_DATE = "wengxiaoyang.hziee.criminalintent.date";private static final String ARG_DATE = "date";private TimePicker mTimePicker;@NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {Date date = (Date) getArguments().getSerializable(ARG_DATE);final Calendar calendar = Calendar.getInstance();calendar.setTime(date);//不加final的话,GregorianCalendar的构造方法会报错final int year = calendar.get(Calendar.YEAR);final int month = calendar.get(Calendar.MONTH);final int day = calendar.get(Calendar.DAY_OF_MONTH);//时分int hour = calendar.get(Calendar.HOUR_OF_DAY);int minute = calendar.get(Calendar.MINUTE);View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_time, null);mTimePicker = v.findViewById(R.id.dialog_time_picker);mTimePicker.setCurrentHour(hour);mTimePicker.setCurrentMinute(minute);return new AlertDialog.Builder(getActivity()).setView(v).setTitle(R.string.date_picker_title).setPositiveButton(android.R.string.ok,new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {int hour = mTimePicker.getCurrentHour();int minute = mTimePicker.getCurrentMinute();Date date = new GregorianCalendar(year, month, day, hour, minute).getTime();sendResult(Activity.RESULT_OK, date);}}).create();}private void sendResult(int resultCode, Date date) {if (getTargetFragment() == null) {return;}Intent intent = new Intent();intent.putExtra(EXTRA_DATE, date);getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode,intent);}public static TimePickerFragment newInstance(Date date) {Bundle args = new Bundle();args.putSerializable(ARG_DATE, date);TimePickerFragment fragment = new TimePickerFragment();fragment.setArguments(args);return fragment;}
}
res部分的drawable
ic_launcher_background.xml(如果源文件里面存在此文件,就可以不要新建)
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="108dp"android:height="108dp"android:viewportWidth="108"android:viewportHeight="108"><pathandroid:fillColor="#008577"android:pathData="M0,0h108v108h-108z" /><pathandroid:fillColor="#00000000"android:pathData="M9,0L9,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,0L19,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M29,0L29,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M39,0L39,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M49,0L49,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M59,0L59,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M69,0L69,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M79,0L79,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M89,0L89,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M99,0L99,108"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,9L108,9"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,19L108,19"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,29L108,29"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,39L108,39"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,49L108,49"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,59L108,59"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,69L108,69"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,79L108,79"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,89L108,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M0,99L108,99"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,29L89,29"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,39L89,39"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,49L89,49"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,59L89,59"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,69L89,69"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M19,79L89,79"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M29,19L29,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M39,19L39,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M49,19L49,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M59,19L59,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M69,19L69,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" /><pathandroid:fillColor="#00000000"android:pathData="M79,19L79,89"android:strokeWidth="0.8"android:strokeColor="#33FFFFFF" />
</vector>
round_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="@color/colorPrimary"/><corners android:radius="100dp"/>
round_border.xml
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"><stroke android:color="@color/colorPrimary"android:width="1dp"/><corners android:radius="100dp"/>
接下来是插入的9张可可爱爱的蜡笔小新图片,在drawable文件夹里面添加任意图片,根据个人喜好,添加的方式参考其他博客。
在drawable-anydpi文件夹里面添加以下文件
ic_menu_add.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"android:tint="#333333"><pathandroid:fillColor="#FF000000"android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>
ic_menu_delete.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"android:tint="#333333"><pathandroid:fillColor="#FF000000"android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>
ic_menu_search.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"android:tint="#333333"><pathandroid:fillColor="#FF000000"android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
</vector>
ic_menu_statistic.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"android:tint="#333333"><pathandroid:fillColor="#FF000000"android:pathData="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.78,0 2.44,0.85 2.5,2.1h2.21c-0.07,-1.72 -1.12,-3.3 -3.21,-3.81V3h-3v2.16c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -2.06,0 -2.87,-0.92 -2.98,-2.1h-2.2c0.12,2.19 1.76,3.42 3.68,3.83V21h3v-2.15c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.81 -4.7,-4.4z"/>
</vector>
在drawable-v24文件夹添加以下文件
ic_launcher_foreground.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"xmlns:aapt="http://schemas.android.com/aapt"android:width="108dp"android:height="108dp"android:viewportWidth="108"android:viewportHeight="108"><pathandroid:fillType="evenOdd"android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"android:strokeWidth="1"android:strokeColor="#00000000"><aapt:attr name="android:fillColor"><gradientandroid:endX="78.5885"android:endY="90.9159"android:startX="48.7653"android:startY="61.0927"android:type="linear"><itemandroid:color="#44000000"android:offset="0.0" /><itemandroid:color="#00000000"android:offset="1.0" /></gradient></aapt:attr></path><pathandroid:fillColor="#FFFFFF"android:fillType="nonZero"android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"android:strokeWidth="1"android:strokeColor="#00000000" />
</vector>
接下来是layout文件夹,这是前端布局代码,添加以下文件:
activity_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"android:exported="true"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ManagePagerActivity"><FrameLayoutandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/t10"/>
activity_manage.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ManageActivity"android:background="@drawable/t10">
activity_manage_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="@drawable/t10"><android.support.v4.view.ViewPagerandroid:id="@+id/manage_view_pager"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" /><FrameLayoutandroid:layout_width="match_parent"android:layout_height="67dp"android:padding="16dp"><Buttonandroid:id="@+id/btn_to_first"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/btn_to_first"android:background="@drawable/round_bg"/><Buttonandroid:id="@+id/btn_to_last"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="end"android:text="@string/btn_to_last"android:background="@drawable/round_bg"/></FrameLayout></LinearLayout>
dialog_date.xml
<?xml version="1.0" encoding="utf-8"?>
<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/dialog_date_picker"android:layout_width="wrap_content"android:layout_height="wrap_content"android:calendarViewShown="true"android:headerBackground="@android:color/holo_blue_bright">
</DatePicker>
dialog_photo.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/manage_photo_detail"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>
dialog_time.xml
<?xml version="1.0" encoding="utf-8"?>
<TimePicker xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/dialog_time_picker"android:layout_width="wrap_content"android:layout_height="wrap_content"android:calendarViewShown="true"android:timePickerMode="spinner">
</TimePicker>
fragment_login.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingBottom="@dimen/activity_vertical_margin"android:background="@drawable/t8"tools:context=".LoginActivity"><!-- Login progress --><ProgressBarandroid:id="@+id/login_progress"style="?android:attr/progressBarStyleLarge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="8dp"android:visibility="gone" /><ScrollViewandroid:id="@+id/login_form"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/email_login_form"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><AutoCompleteTextViewandroid:id="@+id/email"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/prompt_email"android:textColorHint="#000000"android:textColor="#000000"android:inputType="textEmailAddress"android:maxLines="1"android:singleLine="true" /></android.support.design.widget.TextInputLayout><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:id="@+id/password"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/prompt_password"android:textColor="#000000"android:textColorHint="#000000"android:imeActionId="6"android:imeActionLabel="@string/action_sign_in_short"android:imeOptions="actionUnspecified"android:inputType="textPassword"android:maxLines="1"android:singleLine="true" /></android.support.design.widget.TextInputLayout><Buttonandroid:id="@+id/email_sign_in_button"style="?android:textAppearanceSmall"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:text="@string/action_sign_in"android:background="@drawable/round_bg"android:textStyle="bold" /><Buttonandroid:id="@+id/register_button"style="?android:textAppearanceSmall"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:text="@string/register_button"android:background="@drawable/round_bg"android:textStyle="bold" /></LinearLayout></ScrollView>
</LinearLayout>
fragment_manage.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="16dp"android:background="@drawable/t4"><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"><LinearLayoutandroid:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/manage_photo"android:layout_width="80dp"android:layout_height="80dp"android:scaleType="centerInside"android:cropToPadding="true"android:background="@android:color/darker_gray"/><ImageButtonandroid:id="@+id/manage_camera"android:layout_width="match_parent"android:layout_height="wrap_content"android:src="@android:drawable/ic_menu_camera"/></LinearLayout><LinearLayoutandroid:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"></LinearLayout><LinearLayoutandroid:orientation="vertical"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:layout_marginStart="10dp"><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_title_label"android:textColor="#000000"/><EditTextandroid:id="@+id/manage_title"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/manage_title_hint"android:textColorHint="#000000"android:textColor="#000000"/></LinearLayout></LinearLayout><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_details_money"android:textColor="#000000"/><EditTextandroid:id="@+id/manage_money"android:layout_width="match_parent"android:inputType="numberDecimal"android:layout_height="wrap_content"android:hint="@string/manage_money_hint"android:textColorHint="#000000"android:textColor="#000000"/><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_details_time"android:textColor="#000000"/><Buttonandroid:id="@+id/manage_date"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/round_bg"/><Buttonandroid:id="@+id/manage_time"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/round_bg"/><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_details_label"android:textColor="#000000"/><RadioGroupandroid:id="@+id/manage_pay_method"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButtonandroid:id="@+id/manage_cash"android:layout_width="match_parent"android:layout_height="wrap_content"android:checked="true"android:text="@string/manage_cash_label"android:textColor="#000000"/><RadioButtonandroid:id="@+id/manage_card"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_card_label"android:textColor="#000000"/></RadioGroup><EditTextandroid:id="@+id/manage_remark"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/manage_remark_label"android:textColor="#000000"android:textColorHint="#000000"/><Buttonandroid:id="@+id/manage_report"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/manage_report_text"/>
fragment_manage_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_height="match_parent"android:layout_width="match_parent"android:background="@drawable/t6"><android.support.v7.widget.RecyclerViewandroid:id="@+id/manage_recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentStart="true"android:layout_alignParentTop="true"android:textColor="#000000"android:textSize="30dp" /><TextViewandroid:id="@+id/null_manage_list"style="?android:listSeparatorTextViewStyle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_centerHorizontal="true"android:layout_marginTop="280dp"android:text="@string/null_manage_list_text"android:textColor="#000000"android:textSize="20dp" /><Buttonandroid:id="@+id/add_manage"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/null_manage_list"android:layout_marginLeft="32dp"android:layout_marginRight="32dp"android:text="@string/add_manage"android:textColor="#000000"android:textSize="25dp"android:background="@drawable/round_bg"/>
</RelativeLayout>
fragment_register.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingBottom="@dimen/activity_vertical_margin"android:background="@drawable/t4"tools:context=".RegisterActivity"><!-- Login progress --><ProgressBarandroid:id="@+id/register_progress"style="?android:attr/progressBarStyleLarge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="8dp"android:visibility="gone" /><ScrollViewandroid:id="@+id/register_form"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/email_register_form"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><AutoCompleteTextViewandroid:id="@+id/email"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/prompt_email"android:textColor="#000000"android:textColorHint="#000000"android:inputType="textEmailAddress"android:maxLines="1"android:singleLine="true" /></android.support.design.widget.TextInputLayout><android.support.design.widget.TextInputLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:id="@+id/password"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/prompt_password"android:textColorHint="#000000"android:textColor="#000000"android:imeActionId="6"android:imeActionLabel="@string/action_sign_in_short"android:imeOptions="actionUnspecified"android:inputType="textPassword"android:maxLines="1"android:singleLine="true" /></android.support.design.widget.TextInputLayout><Buttonandroid:id="@+id/email_sign_in_button"style="?android:textAppearanceSmall"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:text="@string/action_register_in"android:background="@drawable/round_bg"android:textStyle="bold" /></LinearLayout></ScrollView>
</LinearLayout>
fragment_search.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="@drawable/t7"><TextViewandroid:id="@+id/textView_search"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="@string/search"android:textColor="#000000"android:textSize="30dp" /><EditTextandroid:id="@+id/edit_search"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:hint="@string/edit_search"android:textColor="#000000"android:textSize="20dp"android:textColorHint="#000000"/><Buttonandroid:id="@+id/button_search1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="@string/search"android:textSize="20dp"android:background="@drawable/round_bg"/>
fragment_statistic.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/t5"><EditTextandroid:id="@+id/edit_year"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:hint="@string/edit_year"android:textColorHint="#000000"android:textColor="#000000"android:textSize="20sp" /><EditTextandroid:id="@+id/edit_month"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:hint="@string/edit_month"android:textColor="#000000"android:textSize="20sp"android:textColorHint="#000000"/><EditTextandroid:id="@+id/edit_day"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:hint="@string/edit_day"android:textColor="#000000"android:textSize="20sp"android:textColorHint="#000000"/><Buttonandroid:id="@+id/button_statistic"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="统计金额"android:textColor="#000000"android:textSize="20dp"android:background="@drawable/round_bg"/><TextViewandroid:id="@+id/text_money"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:textColor="#000000"android:layout_marginTop="100dp"android:layout_gravity="center"android:textSize="20dp"android:hint="是否超出预算"android:textColorHint="#000000"/></LinearLayout>
list_item_manage.xml
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/linearLayout"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="8dp"><TextViewandroid:id="@+id/manage_title"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="16dp"android:layout_marginEnd="8dp"android:text="@string/item_manage_title"android:textSize="18sp"app:layout_constraintBottom_toTopOf="@+id/manage_date"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_chainStyle="packed" /><TextViewandroid:id="@+id/manage_date"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="8dp"android:layout_marginEnd="8dp"android:text="@string/item_manage_date"android:textColor="#000000"android:textColorHint="#000000"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/manage_title" />
接下来是menu文件夹,添加以下文件:
fragment_manage.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><itemandroid:id="@+id/delete_manage"android:icon="@drawable/ic_menu_delete"app:showAsAction="ifRoom|withText"android:title="@string/delete_manage" />
fragment_manage_list.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><itemandroid:id="@+id/new_manage"android:icon="@drawable/ic_menu_add"android:title="@string/new_manage"app:showAsAction="ifRoom|withText" /><itemandroid:id="@+id/search_manage"android:icon="@drawable/ic_menu_search"android:title="@string/search"app:showAsAction="ifRoom|withText" /><itemandroid:id="@+id/statistic_manage"android:icon="@drawable/ic_menu_statistic"android:title="@string/item_statistic"app:showAsAction="ifRoom|withText" /><itemandroid:id="@+id/show_subtitle"android:title="@string/show_subtitle"app:showAsAction="ifRoom" /></menu>
接下来是mipmap-anydpi-v26文件夹,包括以下文件:
ic_launcher.xml
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"><background android:drawable="@drawable/ic_launcher_background" /><foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
ic_launcher_round.xml
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"><background android:drawable="@drawable/ic_launcher_background" /><foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
接下来是values文件夹,其包括colors.xml dimens.xml strings.xml styles.xml
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources><color name="colorPrimary">#0099ff</color><color name="colorPrimaryDark">#0099ff</color><color name="colorAccent">#03dac5</color>
</resources>
dimens.xml
<resources><!-- Default screen margins, per the Android Design guidelines. --><dimen name="activity_horizontal_margin">16dp</dimen><dimen name="activity_vertical_margin">16dp</dimen><dimen name="text_margin">16dp</dimen>
</resources>
strings.xml
<resources><string name="app_name">理财小助手</string><!-- Strings related to login --><string name="prompt_email">邮箱</string><string name="prompt_password">密码</string><string name="action_sign_in">登录</string><string name="action_register_in">注册</string><string name="action_sign_in_short">Sign in</string><string name="error_invalid_email">无效的邮箱地址</string><string name="error_error_acpw">账号或密码错误</string><string name="error_invalid_password">密码太短</string><string name="error_incorrect_password">密码错误</string><string name="error_field_required">必填</string><string name="permission_rationale">"Contacts permissions are needed for providing emailcompletions."</string><string name="manage_title_hint">加一个标题吧</string><string name="manage_title_label">项目名称</string><string name="manage_details_money">金额</string><string name="manage_money_hint">快写上你花了多少钱</string><string name="manage_details_label">支付方式</string><string name="manage_details_time">时间</string><string name="manage_cash_label">现金</string><string name="manage_card_label">银行卡</string><string name="manage_remark_label">备注</string><string name="btn_to_first">To First</string><string name="btn_to_last">To Last</string><string name="date_picker_title">记录日期</string><string name="new_manage">新记录</string><string name="show_subtitle">显示记录条数</string><string name="hide_subtitle">隐藏记录条数</string><string name="subtitle_format">%1$d 条记录</string><string name="delete_manage">删除记录</string><string name="null_manage_list_text">尚未存在理财记录</string><string name="add_manage">添加记录</string><string name="manage_report_text">发送理财报告</string><string name="manage_report">%1$s! 理财在 %2$s. %3$s 和 %4$s发生</string><string name="manage_report_cash">现金支付</string><string name="manage_report_card">信用卡支付</string><string name="manage_report_subject">PersonalFinanceAssistant理财报告</string><string name="send_report">发送理财报告通过: </string><string name="item_manage_title">Manage Title</string><string name="item_manage_date">Manage Date</string><string name="register_button">还没有注册?点我注册</string><string name="search">搜索</string><string name="edit_search">输入你想搜索的内容</string><string name="edit_year">输入年</string><string name="edit_month">输入月</string><string name="edit_day">输入日</string><string name="item_statistic">统计</string>
</resources>
styles.xml
<resources><!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat"><!-- Customize your theme here. --><item name="colorPrimary">#000000</item><item name="colorPrimaryDark">#000000</item><item name="colorAccent">#000000</item></style></resources>
接下来是xml文件夹,其中包括了一个文件files.xml
files.xml
<?xml version="1.0" encoding="utf-8"?>
<paths><files-pathname="crime_photos"path="." />
</paths>
清单文件:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="wengxiaoyang.personalfinanceassistant"><!-- To auto-complete the email text field in the login form with the user's emails --><uses-permission android:name="android.permission.GET_ACCOUNTS" /><uses-permission android:name="android.permission.READ_PROFILE" /><uses-permission android:name="android.permission.READ_CONTACTS" /><uses-featureandroid:name="android.hardware.camera2"android:required="false" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".StatisticActivity"></activity><activity android:name=".SearchActivity" /><activity android:name=".RegisterActivity" /><activityandroid:name=".LoginActivity"android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name=".ManageListActivity" /><activityandroid:name=".ManagePagerActivity"android:parentActivityName=".ManageListActivity" /><providerandroid:name="android.support.v4.content.FileProvider"android:authorities="wengxiaoyang.personalfinanceassistant.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/files" /></provider></application></manifest>
最后一个test文件夹
ExampleUnitTest
package wengxiaoyang.personalfinanceassistant;import org.junit.Test;import static org.junit.Assert.*;/*** Example local unit test, which will execute on the development machine (host).** @see <a href="http://d.android.com/tools/testing">Testing documentation</a>*/
public class ExampleUnitTest {@Testpublic void addition_isCorrect() {assertEquals(4, 2 + 2);}
}
怕你们还没有弄清楚,现在将工程目录再进行截图:
最后的java代码不知道为什么会报错,但是程序能够运行,希望大佬知道原因的评论区交流一下。