0


Android——一个简单的记账本APP

一个简单的记账本APP

视频效果预览

添加账目记录

效果预览

添加账目记录实现

简述

日期选择采用

  1. CalendarView

控件,时间选择采用

  1. TimePicker

控件,然后通过

  1. switch

控件控制其

  1. VISIBLE

  1. GONE

属性,类型通过PopUpWindows弹窗显示,标签通过

  1. SharedPreferences

进行传递。最后插入SQLite数据库中。

实现

获取日期

因为获取的日历控件的月份要比实际少一个月,故因此需要把月份加上一。
然后将获取的年月日字符串数据转为Date格式,最后将Date格式转为当时的星期

字符串时间戳转Date
  1. public static Date getStringToDate(String str){
  2. mSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
  3. try {
  4. Date date = mSimpleDateFormat.parse(str);
  5. return date;
  6. } catch (ParseException e) {
  7. e.printStackTrace();
  8. }
  9. return null;
  10. }
Date转星期
  1. public static String getWeekOfDate(Date date) {
  2. String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
  3. Calendar cal = Calendar.getInstance();
  4. cal.setTime(date);
  5. int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
  6. if (w < 0)
  7. w = 0;
  8. return weekDays[w];
  9. }

最后将获取的日期、星期进行保存

  1. /**
  2. * 显示选择的年月日,并将选择的年月日转为星期
  3. */
  4. private void getDate() {
  5. mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
  6. @Override
  7. public void onSelectedDayChange(@NonNull CalendarView view, int year, int month, int dayOfMonth) {
  8. month = month + 1;
  9. CNDate = year + "年" + month + "月" + dayOfMonth + "日";
  10. String date = year + "-" + month + "-" + dayOfMonth;
  11. Log.d(TAG, "date=" + date);
  12. Log.d(TAG, "CNdate=" + CNDate);
  13. //string日期转date日期,在转为星期
  14. String week = DateUtils.getWeekOfDate(DateUtils.getStringToDate(date));
  15. Log.d(TAG, "week=" + week);
  16. SelectDate.setText(CNDate + " " + week);
  17. }
  18. });
  19. }

获取时间

直接对

  1. TimePicker

控件进行事件监听,然后将获取的时间进行保存即可

  1. private void getTime() {
  2. mTimePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
  3. @Override
  4. public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
  5. String time = hourOfDay + ":" + minute;
  6. SelectTime.setText(time);
  7. Log.d(TAG, time);
  8. }
  9. });
  10. }

Switch控制显示和隐藏

更改Switch样式

建立thumb.xml和track.xml两个选择器
thumb.xml如下

  1. <selector xmlns:android="http://schemas.android.com/apk/res/android">
  2. <item android:state_checked="true" android:drawable="@drawable/open_thumb"/>
  3. <item android:drawable="@drawable/shut_thumb"/>
  4. </selector>

track.xml如下

  1. <selector xmlns:android="http://schemas.android.com/apk/res/android">
  2. <item android:state_checked="true" android:drawable="@drawable/open_track"/>
  3. <item android:drawable="@drawable/shut_track"/>
  4. </selector>

然后分别建立两个选择器的不同状态下的效果文件
open_thumb.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:shape="rectangle" >
  4. <!-- 高度40 -->
  5. <size android:height="30dp" android:width="30dp"/>
  6. <!-- 圆角弧度 20 -->
  7. <corners android:radius="15dp"/>
  8. <!-- 变化率 -->
  9. <gradient
  10. android:endColor="#eeeeee"
  11. android:startColor="#eeeeee" />
  12. <!--<stroke android:width="1dp"-->
  13. <!-- android:color="#2196F3"/>-->
  14. </shape>

shut_thumb.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:shape="rectangle" >
  4. <size android:height="30dp" android:width="30dp"/>
  5. <!-- 圆角弧度 20 -->
  6. <corners android:radius="15dp"/>
  7. <!-- 变化率 -->
  8. <gradient
  9. android:endColor="#eeeeee"
  10. android:startColor="#eeeeee" />
  11. <stroke android:width="1dp"
  12. android:color="#A8A7A7"/>
  13. </shape>

open_track.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:shape="rectangle">
  4. <!-- 高度30 此处设置宽度无效-->
  5. <size android:height="30dp"/>
  6. <!-- 圆角弧度 15 -->
  7. <corners android:radius="15dp"/>
  8. <!-- 变化率 定义从左到右的颜色不变 -->
  9. <solid android:color="#07ED7D"/>
  10. </shape>

shut_track.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:shape="rectangle">
  4. <size android:height="30dp" android:width="30dp"/>
  5. <corners android:radius="15dp"/>
  6. <gradient android:startColor="#eeeeee"
  7. android:endColor="#eeeeee"/>
  8. <stroke android:width="1dp"
  9. android:color="#A8A7A7"/>
  10. </shape>

最后应用于switch效果如下

  1. <Switch
  2. android:id="@+id/DateSwitch"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content"
  5. android:layout_gravity="center"
  6. android:gravity="center"
  7. android:thumb="@drawable/thumb"
  8. android:track="@drawable/track" />
事件监听

通过监听Switch事件,判断false和true两种状态,分别对应控件的隐藏和显示

  1. class SwitchListener implements CompoundButton.OnCheckedChangeListener {
  2. @Override
  3. public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
  4. switch (buttonView.getId()) {
  5. case R.id.DateSwitch:
  6. if (isChecked)
  7. DateLayout.setVisibility(View.VISIBLE);
  8. else
  9. DateLayout.setVisibility(View.GONE);
  10. break;
  11. case R.id.TimeSwitch:
  12. if (isChecked)
  13. TimeLayout.setVisibility(View.VISIBLE);
  14. else
  15. TimeLayout.setVisibility(View.GONE);
  16. break;
  17. }
  18. }
  19. }

保存至SQLite数据库

  1. /**
  2. * 账单记录保存到SQLite中
  3. */
  4. public void SaveMessage(View view) {
  5. String date = SelectDate.getText().toString().trim();
  6. String time = SelectTime.getText().toString().trim();
  7. String type = TypeText.getText().toString();
  8. String label = TextLabel.getText().toString();
  9. String name = GoodsName.getText().toString();
  10. String price = GoodsPrice.getText().toString().trim();
  11. if (TextUtils.isEmpty(type) || type.equals("支出or收入")){
  12. toastUtils.ShowFail("类型错误!");
  13. return;
  14. }
  15. if (TextUtils.isEmpty(label) || label.equals("暂未选择")){
  16. toastUtils.ShowFail("标签错误!");
  17. return;
  18. }
  19. if (TextUtils.isEmpty(name) || TextUtils.isEmpty(price)){
  20. toastUtils.ShowFail("商品信息或者商品价格格式!");
  21. return;
  22. }
  23. int t = type.equals("支出") ? 1 : 0;
  24. Record record = new Record(date,time,t,label,name,price);
  25. int flag = dao.Insert(record);
  26. if (flag == 1){
  27. toastUtils.ShowSuccess("保存成功!");
  28. }else {
  29. toastUtils.ShowFail("保存失败!");
  30. }
  31. }

标签选择实现

效果预览

实现

状态改变

每一个标签有两种状态,选择和不被选择状态,分别对应两种样式效果,一种呈灰色,另一种呈高亮,在进行选择时可以同时点亮多个标签,但最后进行保存时,只能选择一个标签,若条件不满足,系统给予错误提示。

事件监听

  1. class TypeListener implements View.OnClickListener{
  2. @Override
  3. public void onClick(View v) {
  4. switch (v.getId()){
  5. case R.id.type_1:
  6. setTag(type_1,getTag(type_1));
  7. setBG(type_1,1);
  8. break;
  9. case R.id.type_2:
  10. setTag(type_2,getTag(type_2));
  11. setBG(type_2,2);
  12. break;
  13. case R.id.type_3:
  14. setTag(type_3,getTag(type_3));
  15. setBG(type_3,3);
  16. break;
  17. case R.id.type_4:
  18. setTag(type_4,getTag(type_4));
  19. setBG(type_4,4);
  20. break;
  21. case R.id.type_5:
  22. setTag(type_5,getTag(type_5));
  23. setBG(type_5,5);
  24. break;
  25. case R.id.type_6:
  26. setTag(type_6,getTag(type_6));
  27. setBG(type_6,6);
  28. break;
  29. case R.id.type_7:
  30. setTag(type_7,getTag(type_7));
  31. setBG(type_7,7);
  32. break;
  33. case R.id.type_8:
  34. setTag(type_8,getTag(type_8));
  35. setBG(type_8,8);
  36. break;
  37. }
  38. }
  39. }

状态监听

每一个标签被点击,其tag自增一次,若未被点击,初始值为1

  1. private void setTag(LinearLayout layout,int tag){
  2. tag++;
  3. layout.setTag(tag);
  4. }
  1. private int getTag(LinearLayout layout){
  2. Object tag = layout.getTag();
  3. if (tag == null)return 1;
  4. return (int) tag;
  5. }

然后通过tag值改变标签的样式,成偶数则高亮,奇数则灰色,并记录当前状态值,同时保存被选择的标签数量。

  1. private void setBG(LinearLayout layout,int index){
  2. int tag = (int)layout.getTag();
  3. if (tag % 2 == 0) {
  4. layout.setBackground(getResources().getDrawable(R.drawable.blue_radius_bg));
  5. TotalNum++;
  6. b_select[index-1] = true;
  7. }
  8. else {
  9. layout.setBackground(getResources().getDrawable(R.drawable.grey_radius_bg));
  10. TotalNum--;
  11. b_select[index-1] = false;
  12. }
  13. }

然后通过监听保存按钮点击事件,取出状态值为true的标签值进行返回

  1. private String selectTag(){
  2. for (int i = 0; i < 8; i++) {
  3. if ( b_select[i]){
  4. return s_select[i];
  5. }
  6. }
  7. return null;
  8. }

同时监听被选择的标签总数,若小于1,则未选择任何标签,给予提升;若大于1,则选择多个标签,同样给予提升。最后通过

  1. SharedPreferences

进行数据传回;使用Intent传输应该会更安全,一开始设计使用EventBus,但最后不了了。

  1. public void SaveMessage(View view){
  2. if (TotalNum > 1){
  3. toastUtils.ShowFail("选择标签数量不能超过一");
  4. }else if (TotalNum <= 0){
  5. toastUtils.ShowFail("选择标签数量不能少于一");
  6. }else {
  7. toastUtils.ShowSuccess("success");
  8. String tag = selectTag();
  9. Log.d(TAG,"TAG="+tag);
  10. SP sp = SP.getInstance();
  11. sp.PutData(LabelActivity.this,"Label",tag);
  12. //EventBus.getDefault().post(new TextClass(tag));
  13. KillProcess.POP(LabelActivity.this);
  14. }
  15. }

导航界面

采用底部导航控件

  1. BottomNavigationView

切换账单记录界面和账单概览界面,并通过

  1. ViewPager

进行页面滑动,两个子页面采用两个不同的

  1. Fragment

创建menu

次menu即为底部导航的文字和图片效果,可以使用选择器,监听选择和不被选择两种状态,改变其效果。若不设置,系统模式使用样式颜色作为高亮显示。灰色呈不被选择状态。

  1. <menu xmlns:android="http://schemas.android.com/apk/res/android">
  2. <item
  3. android:id="@+id/menu_navigation_record"
  4. android:icon="@drawable/ic_home_black_24dp"
  5. android:title="@string/title_record" />
  6. <item
  7. android:id="@+id/menu_navigation_general"
  8. android:icon="@drawable/ic_dashboard_black_24dp"
  9. android:title="@string/title_general" />
  10. </menu>

创建Fragment

由于本APP只需要两个节目,故只需要创建两个fragment,然后在与nav进行绑定即可,此处仅作为标记,详细介绍如下文所示

绑定Fragment

  1. /**
  2. * Set a listener that will be notified when a bottom navigation item is selected. This listener
  3. * will also be notified when the currently selected item is reselected, unless an {@link
  4. * OnNavigationItemReselectedListener} has also been set.
  5. *
  6. * @param listener The listener to notify
  7. * @see #setOnNavigationItemReselectedListener(OnNavigationItemReselectedListener)
  8. */

设置底部导航栏当前页面显示

  1. navView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
  2. @Override
  3. public boolean onNavigationItemSelected(@NonNull MenuItem item) {
  4. switch (item.getItemId()) {
  5. case R.id.menu_navigation_record:
  6. mViewPager.setCurrentItem(0);
  7. return true;
  8. case R.id.menu_navigation_general:
  9. mViewPager.setCurrentItem(1);
  10. return true;
  11. }
  12. return false;
  13. }
  14. });

将ViewPager和两个fragment进行绑定

  1. private void setupViewPager(ViewPager viewPager) {
  2. BottomAdapter adapter = new BottomAdapter(getSupportFragmentManager());
  3. adapter.addFragment(new RecordFragment());
  4. adapter.addFragment(new GeneralFragment());
  5. viewPager.setAdapter(adapter);
  6. }

并通过监听ViewPager事件,进行页面切换

  1. mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
  2. @Override
  3. public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
  4. }
  5. @Override
  6. public void onPageSelected(int position) {
  7. navView.getMenu().getItem(position).setChecked(true);
  8. }
  9. @Override
  10. public void onPageScrollStateChanged(int state) {
  11. }
  12. });
  13. }

账单记录显示

效果预览

简述

此界面就比较简单,从数据库中拿出所有数据并构建一个集合类对象,然后放入RecyclerView中进行显示,最后根据类型计算总支出和总收入金额

RecyclerView显示

建立适配器

  1. public class OrderAdapter extends RecyclerView.Adapter<OrderAdapter.ViewHolder> {
  2. private String[] s_select = {"日用百货","文化休闲","交通出行","生活服务","服装装扮","餐饮美食","数码电器","其他标签"};
  3. private int[] img_select = {
  4. R.drawable.icon_type_one,
  5. R.drawable.icon_type_two,
  6. R.drawable.icon_type_three,
  7. R.drawable.icon_type_four,
  8. R.drawable.icon_type_five,
  9. R.drawable.icon_type_six,
  10. R.drawable.icon_type_seven,
  11. R.drawable.icon_type_eight};
  12. private List<Record> recordList;
  13. public OrderAdapter(List<Record> recordList){
  14. this.recordList = recordList;
  15. }
  16. @NonNull
  17. @Override
  18. public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  19. View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_item,parent,false);
  20. return new ViewHolder(view);
  21. }
  22. @Override
  23. public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
  24. Record record = recordList.get(position);
  25. holder.item_date.setText(record.getDate());
  26. holder.item_time.setText("时间 "+record.getTime());
  27. holder.item_label.setText("["+record.getLabel()+"]");
  28. holder.item_name.setText(record.getGoodsName());
  29. if (record.getType() == 1){
  30. holder.item_price.setText("-"+record.getGoodsPrice());
  31. }else {
  32. holder.item_price.setText("+"+record.getGoodsPrice());
  33. }
  34. for (int i = 0; i < 8; i++) {
  35. if (record.getLabel().equals(s_select[i])){
  36. holder.item_img.setImageResource(img_select[i]);
  37. }
  38. }
  39. }
  40. @Override
  41. public int getItemCount() {
  42. return recordList.size();
  43. }
  44. class ViewHolder extends RecyclerView.ViewHolder{
  45. private TextView item_date,item_time,item_label,item_name,item_price;
  46. private ImageView item_img;
  47. public ViewHolder(@NonNull View itemView) {
  48. super(itemView);
  49. item_date = itemView.findViewById(R.id.item_date);
  50. item_time = itemView.findViewById(R.id.item_time);
  51. item_label = itemView.findViewById(R.id.item_label);
  52. item_name = itemView.findViewById(R.id.item_name);
  53. item_price = itemView.findViewById(R.id.item_price);
  54. item_img = itemView.findViewById(R.id.item_img);
  55. }
  56. }
  57. }

获取数据源

从数据库中获取实体类集合对象,然后根据其收入和支出两种状态计算相对应的总金额

  1. /**
  2. * 获取RecyclerView数据源*/
  3. private void getData(){
  4. recordList = dao.QueryAll();
  5. if (recordList.size() == 0 || recordList == null){
  6. IsEmpty(true);
  7. return;
  8. }
  9. for (int i = 0; i < recordList.size(); i++) {
  10. /**
  11. * 1为支出
  12. * 0为收入*/
  13. if (recordList.get(i).getType() == 1){
  14. totalPay += Double.parseDouble(recordList.get(i).getGoodsPrice());
  15. }else {
  16. totalIncome += Double.parseDouble(recordList.get(i).getGoodsPrice());
  17. }
  18. }
  19. IsEmpty(TotalPay,totalPay,1);
  20. IsEmpty(TotalIncome,totalIncome,0);
  21. }

保留两位小数

由于在转换格式的之后,进行加减运算精度会失衡,会产生很多位小数点,但由于美观以及界面设计,一般设计保留2位小数即可

  1. 12.345678为例:
  2. 12.345678*100 = 1234.5678
  3. 然后将其转为整数,则变为 1234
  4. 最后除以100.0,此处标签,是100.0不是100,因为前面已经为整型数据,整型除整型依旧为整型,只有除100.0int数据类型才会强制转换为float或者double类型
  1. private double SaveDecimal(double n){
  2. return n = ((int)(n*100))/100.0;
  3. }

概览

效果预览

简述

此界面显示的内容包括共计收入、支出多少笔和合计收入、支出多少金额,以及通过标签分类显示支出、收入占比,以及全部收入、支出记录中前三甲。

分类显示

通过获取单个标签的所有金额除以全部标签的总金额,获取百分比占比,并通过view进行显示,条形bar通过获取屏幕宽度,例如:我的手机屏幕宽度为1080,就以数码电器为例:

  1. 11998.99/总金额 * 1080 = 条形bar的长度

百分比占比同样以数码电器为例:

  1. 11998.99/总金额 * 100 = 数码电器百分比

创建适配器

  1. public class BarAdapter extends RecyclerView.Adapter<BarAdapter.ViewHolder> {
  2. private String[] s_select = {"日用百货", "文化休闲", "交通出行", "生活服务", "服装装扮", "餐饮美食", "数码电器", "其他标签"};
  3. private int[] img_select = {
  4. R.drawable.icon_type_one,
  5. R.drawable.icon_type_two,
  6. R.drawable.icon_type_three,
  7. R.drawable.icon_type_four,
  8. R.drawable.icon_type_five,
  9. R.drawable.icon_type_six,
  10. R.drawable.icon_type_seven,
  11. R.drawable.icon_type_eight};
  12. private List<ViewBar> viewBarList;
  13. public BarAdapter(List<ViewBar> viewBarList) {
  14. this.viewBarList = viewBarList;
  15. }
  16. @NonNull
  17. @Override
  18. public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  19. View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.pay_type_item, parent, false);
  20. return new ViewHolder(view);
  21. }
  22. @Override
  23. public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
  24. int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
  25. int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
  26. holder.item_bar.measure(w, h);
  27. ViewBar viewBar = viewBarList.get(position);
  28. holder.item_bar.setLayoutParams(new LinearLayout.LayoutParams(viewBar.getWidth(), viewBar.getHeight()));
  29. holder.item_label.setText(viewBar.getLabel());
  30. holder.item_num.setText(viewBar.getNum());
  31. holder.item_price.setText(viewBar.getPrice());
  32. Log.d("testLabel",viewBar.getLabel());
  33. for (int i = 0; i < 8; i++) {
  34. if (viewBar.getLabel().trim().equals(s_select[i])){
  35. Log.d("testLabel",viewBar.getLabel());
  36. holder.item_img.setImageResource(img_select[i]);
  37. }
  38. }
  39. }
  40. @Override
  41. public int getItemCount() {
  42. return viewBarList.size();
  43. }
  44. class ViewHolder extends RecyclerView.ViewHolder {
  45. private TextView item_label, item_num, item_price;
  46. private ImageView item_img;
  47. private View item_bar;
  48. public ViewHolder(@NonNull View itemView) {
  49. super(itemView);
  50. item_label = itemView.findViewById(R.id.pay_type_label);
  51. item_num = itemView.findViewById(R.id.pay_type_num);
  52. item_price = itemView.findViewById(R.id.pay_type_price);
  53. item_img = itemView.findViewById(R.id.pay_type_img);
  54. item_bar = itemView.findViewById(R.id.pay_type_bar);
  55. }
  56. }
  57. }

获取数据源

获取屏幕宽度,以此作为基数

  1. manager = requireActivity().getWindowManager();
  2. width = manager.getDefaultDisplay().getWidth();
  1. private void getData(){
  2. if (TotalPrice <= 0)return;
  3. for (int i = 0; i < d_price.length; i++) {
  4. if (d_price[i] == 0)continue;
  5. int n = (int) (d_price[i] / TotalPrice * width);
  6. double t = SaveDecimal(d_price[i] / TotalPrice * 100);
  7. barList.add(new ViewBar(s_select[i]+" ",t+"%","¥"+d_price[i],n,10));
  8. }
  9. }

前三甲

通过比较所有账单记录,根据金额升序获取前三甲

创建适配器

  1. public class RankAdapter extends RecyclerView.Adapter<RankAdapter.ViewHolder> {
  2. private int[] img_select = {
  3. R.drawable.gold,
  4. R.drawable.silver,
  5. R.drawable.tongpai,
  6. };
  7. private List<RankList> rankLists;
  8. public RankAdapter(List<RankList> rankLists){
  9. this.rankLists = rankLists;
  10. }
  11. @NonNull
  12. @Override
  13. public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  14. View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.ranking_list_item,parent,false);
  15. return new ViewHolder(view);
  16. }
  17. @Override
  18. public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
  19. RankList rank = rankLists.get(position);
  20. holder.item_label.setText("["+rank.getLabel()+"]");
  21. holder.item_content.setText(rank.getContent());
  22. if (rank.getType() == 1){
  23. holder.item_price.setText("-"+rank.getPrice());
  24. }else {
  25. holder.item_price.setText("+"+rank.getPrice());
  26. }
  27. switch (rank.getPosition()){
  28. case 1:
  29. holder.item_img.setImageResource(img_select[0]);
  30. break;
  31. case 2:
  32. holder.item_img.setImageResource(img_select[1]);
  33. break;
  34. case 3:
  35. holder.item_img.setImageResource(img_select[2]);
  36. break;
  37. }
  38. }
  39. @Override
  40. public int getItemCount() {
  41. return rankLists.size();
  42. }
  43. class ViewHolder extends RecyclerView.ViewHolder{
  44. private TextView item_label,item_content,item_price;
  45. private ImageView item_img;
  46. public ViewHolder(@NonNull View itemView) {
  47. super(itemView);
  48. item_label = itemView.findViewById(R.id.Rank_label);
  49. item_content = itemView.findViewById(R.id.Rank_name);
  50. item_price = itemView.findViewById(R.id.Rank_price);
  51. item_img = itemView.findViewById(R.id.Rank_img);
  52. }
  53. }
  54. }

获取数据源

代码虽不比递归以及排序整洁,但是时间复杂度控制在0(n),效率比冒泡排序、快速排序等要高一点

  1. /**
  2. * 选出账单支出前三甲*/
  3. private void getRankings(){
  4. if (recordList.size() == 0 || recordList == null)return;
  5. double maxPrice = -32768,midPrice = -32768,lowPrice = -32768;
  6. int maxIndex = -1,midIndex = -1,lowIndex = -1;
  7. for (int i = 0; i < recordList.size(); i++) {
  8. double price = Double.parseDouble(recordList.get(i).getGoodsPrice());
  9. if ( price > maxPrice){
  10. lowPrice = midPrice;
  11. lowIndex = midIndex;
  12. midPrice = maxPrice;
  13. midIndex = maxIndex;
  14. maxPrice = price;
  15. maxIndex = i;
  16. }
  17. if (price < maxPrice && price > midPrice){
  18. lowPrice = midPrice;
  19. lowIndex = midIndex;
  20. midPrice = price;
  21. midIndex = i;
  22. }
  23. if (price < maxPrice && price < midPrice && price > lowPrice){
  24. lowPrice = price;
  25. lowIndex = i;
  26. }
  27. }
  28. int[] poi = {maxIndex,midIndex,lowIndex};
  29. for (int i = 0; i < 3; i++) {
  30. if (poi[i] == -1)continue;
  31. rankListList.add(new RankList(i+1,recordList.get(poi[i]).getLabel(),recordList.get(poi[i]).getGoodsName(),recordList.get(poi[i]).getGoodsPrice(),recordList.get(poi[i]).getType()));
  32. }
  33. }

单标签总价以及总金额

  1. /**
  2. * 获取单个标签总价以及所有商品总价*/
  3. private void getPrice(){
  4. if (recordList.size() == 0 || recordList == null)return;
  5. d_price = new double[s_select.length];
  6. for (int i = 0; i < recordList.size(); i++) {
  7. for (int j = 0; j < s_select.length; j++) {
  8. if (recordList.get(i).getLabel().equals(s_select[j])){
  9. d_price[j] += Double.parseDouble(recordList.get(i).getGoodsPrice());
  10. TotalPrice += Double.parseDouble(recordList.get(i).getGoodsPrice());
  11. break;
  12. }
  13. }
  14. }
  15. }

可视化概览

效果预览

简述

本可视化图表工具采用的是AAChartView,此工具相对于老牌MPChartView和HelloChartView而言,使用更加简单,种类更加齐全,重点是粉粉嫩嫩,但他的导入方式与其他不同,不是通过导入闭包进行使用;而且通过复制它到一些文件到自己工程项目中,其样式使用的js写的,所有需要导入一些js文件以及一些其他java文件。这一点不比导入闭包方便。根据需要进行选择使用。

折线图

通过

  1. aa_drawChartWithChartModel()

方法获取

  1. AAChartModel

对象即可,使用超级简单

  1. lineChartView.aa_drawChartWithChartModel(InitLineChart());

然后可通过配置一些参数,更加形象化图表

  1. 例如:categories x轴数据源,类型为String[]
  2. yAxisMin y轴数据源最小值
  3. yAxisMax y轴数据源最大值
  4. series 每个数据点的提示内容,其中name为标题;data为数据,类型为Object[]
  1. private AAChartModel InitLineChart() {
  2. return new AAChartModel()
  3. .chartType(AAChartType.Areaspline)
  4. .legendEnabled(false)
  5. .yAxisVisible(true)
  6. .markerRadius(6f)
  7. .markerSymbolStyle(AAChartSymbolStyleType.InnerBlank)
  8. .zoomType(AAChartZoomType.XY)
  9. .categories(s_select)
  10. .yAxisMin(2.0f)//Y轴数据最大值和最小值范围
  11. .yAxisMax(2000.0f)
  12. .xAxisTickInterval(2)
  13. .series(new AASeriesElement[]{
  14. new AASeriesElement()
  15. .name("合计")
  16. .color("#2494F3")
  17. .data( getPrice())
  18. });
  19. }

获取数据源

由于需要的是Object[] 类型数据,所有需要将string类型数据转为double,然后将double转为Double类型,然后进行强制转换,最后变为Object类型

  1. private Object[] getPrice(){
  2. if (recordList.size() == 0 || recordList == null)return null;
  3. double[] d_price = new double[s_select.length];
  4. Object[] o_price = new Object[s_select.length];
  5. for (int i = 0; i < recordList.size(); i++) {
  6. for (int j = 0; j < s_select.length; j++) {
  7. if (recordList.get(i).getLabel().equals(s_select[j])){
  8. Log.d("DetailedActivity",Double.parseDouble(recordList.get(i).getGoodsPrice())+"");
  9. d_price[j] += Double.parseDouble(recordList.get(i).getGoodsPrice());
  10. break;
  11. }
  12. }
  13. }
  14. for (int i = 0; i < s_select.length; i++) {
  15. o_price[i] = new Double(d_price[i]);
  16. }
  17. return o_price;
  18. }

南丁格尔玫瑰图

同样适用

  1. aa_drawChartWithChartModel

方法进行数据体现,同时无论什么类型的图表类型,都知使用

  1. AAChartView

控件,并且只需要返回

  1. AAChartModel

对象,这极大程度方便进行封装使用

  1. mapChartView.aa_drawChartWithChartModel(InitRoseChart());
  1. private AAChartModel InitRoseChart() {
  2. return new AAChartModel()
  3. .yAxisTitle("cm")
  4. .chartType(AAChartType.Column)
  5. .xAxisVisible(false)//是否显示最外一层圆环
  6. .yAxisVisible(true)//是否显示中间的多个圆环
  7. .yAxisAllowDecimals(true)
  8. .legendEnabled(false)//隐藏图例(底部可点按的小圆点)
  9. .categories(getTitles())
  10. .dataLabelsEnabled(true)
  11. .polar(true)//极地化图形
  12. .series(new AASeriesElement[]{
  13. new AASeriesElement()
  14. .name("价格")
  15. .data(getRosePrice()),
  16. }
  17. );
  18. }

获取数据源

  1. /**
  2. * 南丁格尔玫瑰图数据源x*/
  3. private Object[] getRosePrice(){
  4. if (recordList.size() == 0 || recordList == null)return null;
  5. double[] d_price = new double[recordList.size()];
  6. Object[] o_price = new Object[recordList.size()];
  7. for (int i = 0; i < recordList.size(); i++) {
  8. d_price[i] = Double.parseDouble(recordList.get(i).getGoodsPrice());
  9. }
  10. for (int i = 0; i < recordList.size(); i++) {
  11. o_price[i] = new Double(d_price[i]);
  12. }
  13. return o_price;
  14. }

记录删除

效果图

首先删除数据库中的对象,然后删除当前列表数据

  1. adapter.setDeleteListener(new OrderAdapter.onDeleteListener() {
  2. @Override
  3. public void onClickListener(int pos, Record bean) {
  4. dao.Delete(bean.getGoodsName());
  5. recordList.remove(pos);
  6. adapter.notifyDataSetChanged();
  7. EventBus.getDefault().postSticky(new UpdateBean(false));
  8. }
  9. });

尾言

此代码为刚入门所敲,很多不足之处,最近有很多人找我要此项目代码,修复了一些Bug,增加删除功能,但由于之前技术不足,框架构建不是很好,无心去重构,再次感谢大家的厚爱

标签: android sqlite xml

本文转载自: https://blog.csdn.net/News53231323/article/details/125128638
版权归原作者 FranzLiszt1847 所有, 如有侵权,请联系我们删除。

“Android——一个简单的记账本APP”的评论:

还没有评论