irpas技术客

Android课设——理财小助手_憨憨tiantian_安卓课设

网络投稿 532

一: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方法 @Override public 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方法 @Override public 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 @Override public 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() { @Override public 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 { @Override protected 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 { // UI private AutoCompleteTextView mEmailView; private EditText mPasswordView; private Button mRegisterButton; private View mProgressView; private View mLoginFormView; @Override public 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() { @Override public 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() { @Override public void onClick(View view) { attemptLogin(); } });//设置监听,调用attemplogin方法判断邮箱和密码是否正确 mRegisterButton = view.findViewById(R.id.register_button);//注册按钮 mRegisterButton.setOnClickListener(new OnClickListener() { @Override public 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); // 跳转到ManageListActivity Intent 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() { @Override public 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() { @Override public 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; } else return 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表,也就是table2 private ManageCursorWrapper queryLogin(String whereClause, String[] whereArgs) { Cursor cursor = mDatabase.query( ManageTable2.NAME2, null,// null selects all columns whereClause, 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; } // 根据上下文获取LoginLab public 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; } // 保存部分数据 @Override public 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); } @Override public void onPause() { super.onPause(); // 更新数据库数据 ManageLab.get(getActivity()).updateManage(mManage); } // UI @Override public 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() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mManage.setTitle(s.toString()); } @Override public void afterTextChanged(Editable s) { } }); // 金额 mMoneyField = v.findViewById(R.id.manage_money); mMoneyField.setText(mManage.getMoney()); mMoneyField.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mManage.setMoney(s.toString()); } @Override public void afterTextChanged(Editable s) { } }); // 日期 mDateButton = v.findViewById(R.id.manage_date); Date date = mManage.getDate(); updateDate(); mDateButton.setOnClickListener(new View.OnClickListener() { @Override public 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() { @Override public 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(){ @Override public 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() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mManage.setRemark(s.toString()); } @Override public void afterTextChanged(Editable s) { } }); // 发送报告 mReportButton = v.findViewById(R.id.manage_report); mReportButton.setOnClickListener(new View.OnClickListener() { @Override public 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() { @Override public 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() { @Override public 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() { @Override public void onGlobalLayout() { updatePhotoView(mPhotoView.getWidth(), mPhotoView.getHeight()); } }); return v; } // 根据需求更新视图 @Override public 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()); } } // 创建菜单 @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.fragment_manage, menu); } // 根据选择响应 @Override public 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 columns whereClause, 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获取Manage public 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 { @Override protected 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"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } // UI @Override public 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() { @Override public 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; } @Override public void onResume() { super.onResume(); updateUI(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(SAVED_SUBTITLE_VISIBLE, mSubtitleVisible); } // 创建菜单 @Override public 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); } } // 响应菜单点击 @Override public 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()); } @Override public 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 @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { //先建立LayoutInflater LayoutInflater layoutInflater = LayoutInflater.from(getActivity()); return new ManageHolder(layoutInflater, parent); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { Manage manage = mManages.get(position); ((ManageHolder)holder).bind(manage); } @Override public 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; } @Override protected 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() { @Override public 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); } } @Override public void onPageSelected(int i) { } @Override public void onPageScrollStateChanged(int i) { } }); btn_first = findViewById(R.id.btn_to_first); btn_first.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mViewPager.setCurrentItem(0); } }); btn_last = findViewById(R.id.btn_to_last); btn_last.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mViewPager.setCurrentItem(mManages.size() - 1); } }); mManages = ManageLab.get(this).getManages(); FragmentManager fragmentManager = getSupportFragmentManager(); mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) { @Override public Fragment getItem(int position) { Manage manage = mManages.get(position); return ManageFragment.newInstance(manage.getId()); } @Override public 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; } // 创建对话框 @Override public 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; //读入和创建常量bitmap return 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 { @Override protected 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 { // UI private AutoCompleteTextView mEmailView; private EditText mPasswordView; private View mProgressView; private View mLoginFormView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public 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() { @Override public 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() { @Override public 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 logic return email.contains("@"); } private boolean isPasswordValid(String password) {//密码太短 //TODO: Replace this with your own logic return 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() { @Override public 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() { @Override public 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 { @Override protected 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 { // UI private TextView mTextView; private EditText mSearchView; private Button mSearchButton; @Override public 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); // 跳转到搜索的activity mSearchButton.setOnClickListener(new View.OnClickListener() { @Override public 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 @Override protected 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 { @Override protected 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; @Override public 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() { @Override public 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_TIME public static final String EXTRA_DATE = "wengxiaoyang.hziee.criminalintent.date"; private static final String ARG_DATE = "date"; private TimePicker mTimePicker; @NonNull @Override public 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() { @Override public 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"> <path android:fillColor="#008577" android:pathData="M0,0h108v108h-108z" /> <path android:fillColor="#00000000" android:pathData="M9,0L9,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M19,0L19,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M29,0L29,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M39,0L39,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M49,0L49,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M59,0L59,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M69,0L69,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M79,0L79,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M89,0L89,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M99,0L99,108" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,9L108,9" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,19L108,19" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,29L108,29" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,39L108,39" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,49L108,49" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,59L108,59" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,69L108,69" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,79L108,79" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,89L108,89" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M0,99L108,99" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M19,29L89,29" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M19,39L89,39" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M19,49L89,49" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M19,59L89,59" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M19,69L89,69" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M19,79L89,79" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M29,19L29,89" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M39,19L39,89" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M49,19L49,89" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M59,19L59,89" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android:fillColor="#00000000" android:pathData="M69,19L69,89" android:strokeWidth="0.8" android:strokeColor="#33FFFFFF" /> <path android: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"> <path android: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"> <path android: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"> <path android: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"> <path android: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"> <path android: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"> <gradient android:endX="78.5885" android:endY="90.9159" android:startX="48.7653" android:startY="61.0927" android:type="linear"> <item android:color="#44000000" android:offset="0.0" /> <item android:color="#00000000" android:offset="1.0" /> </gradient> </aapt:attr> </path> <path android: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"> <FrameLayout android: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"?> <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="@drawable/t10"> <android.support.v4.view.ViewPager android:id="@+id/manage_view_pager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <FrameLayout android:layout_width="match_parent" android:layout_height="67dp" android:padding="16dp"> <Button android: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"/> <Button android: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"> <ImageView android: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 --> <ProgressBar android: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" /> <ScrollView android:id="@+id/login_form" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/email_login_form" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <AutoCompleteTextView android: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.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android: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> <Button android: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" /> <Button android: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"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp"> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:id="@+id/manage_photo" android:layout_width="80dp" android:layout_height="80dp" android:scaleType="centerInside" android:cropToPadding="true" android:background="@android:color/darker_gray"/> <ImageButton android:id="@+id/manage_camera" android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@android:drawable/ic_menu_camera"/> </LinearLayout> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> </LinearLayout> <LinearLayout android:orientation="vertical" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginStart="10dp"> <TextView style="?android:listSeparatorTextViewStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/manage_title_label" android:textColor="#000000"/> <EditText android: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> <TextView style="?android:listSeparatorTextViewStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/manage_details_money" android:textColor="#000000"/> <EditText android: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"/> <TextView style="?android:listSeparatorTextViewStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/manage_details_time" android:textColor="#000000"/> <Button android:id="@+id/manage_date" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/round_bg"/> <Button android:id="@+id/manage_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/round_bg"/> <TextView style="?android:listSeparatorTextViewStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/manage_details_label" android:textColor="#000000"/> <RadioGroup android:id="@+id/manage_pay_method" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <RadioButton android: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"/> <RadioButton android:id="@+id/manage_card" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/manage_card_label" android:textColor="#000000"/> </RadioGroup> <EditText android: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"/> <Button android: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"?> <RelativeLayout xmlns: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.RecyclerView android: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" /> <TextView android: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" /> <Button android: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 --> <ProgressBar android: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" /> <ScrollView android:id="@+id/register_form" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/email_register_form" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <AutoCompleteTextView android: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.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android: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> <Button android: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"> <TextView android: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" /> <EditText android: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"/> <Button android: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"> <EditText android: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" /> <EditText android: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"/> <EditText android: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"/> <Button android: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"/> <TextView android: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"> <TextView android: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" /> <TextView android: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"> <item android: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"> <item android:id="@+id/new_manage" android:icon="@drawable/ic_menu_add" android:title="@string/new_manage" app:showAsAction="ifRoom|withText" /> <item android:id="@+id/search_manage" android:icon="@drawable/ic_menu_search" android:title="@string/search" app:showAsAction="ifRoom|withText" /> <item android:id="@+id/statistic_manage" android:icon="@drawable/ic_menu_statistic" android:title="@string/item_statistic" app:showAsAction="ifRoom|withText" /> <item android: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 email completions." </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-path name="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-feature android:name="android.hardware.camera2" android:required="false" /> <application android: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" /> <activity android: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" /> <activity android:name=".ManagePagerActivity" android:parentActivityName=".ManageListActivity" /> <provider android:name="android.support.v4.content.FileProvider" android:authorities="wengxiaoyang.personalfinanceassistant.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android: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 { @Test public void addition_isCorrect() { assertEquals(4, 2 + 2); } }

怕你们还没有弄清楚,现在将工程目录再进行截图: 最后的java代码不知道为什么会报错,但是程序能够运行,希望大佬知道原因的评论区交流一下。


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #安卓课设