Android課設——理財小助手

一: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 tofirstpublic 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 Testing documentation */public class ExampleUnitTest {    @Test    public void addition_isCorrect() {        assertEquals(4, 2 + 2);    }}

怕你們還沒有弄清楚,現在將工程目錄再進行截圖:




最後的java代碼不知道為什麼會報錯,但是程序能夠運行,希望大佬知道原因的評論區交流一下。

本文來自網絡,不代表程式碼花園立場,如有侵權,請聯系管理員。https://www.codegarden.cn/article/31356/
返回顶部