记账APP:小哈记账4——记账首页页面的制作(1)

项目介绍:

        小哈记账是一款用于记账APP,基于Android Studio开发工具,采用Java语言进行开发,同时使用litepal和阿里云数据库进行数据的增删查改,以图标的形式在App的界面上显示。App可以清晰显示收支情况,并以图表的形式展示每月收支情况;同时可以记录消费用途,项目能够精确到每一个款项的收入支出时间、结余并且可以设置每月的预算。超出预算提醒,并且有每周,每月及每年的账单统计,较为清晰明确帮助用户分析自己当前的支出和收入。同时拥有用户登录、注册、修改头像等功能。

        本项目中使用到的技术:LitePal数据库,阿里云RDS数据库,MPAndroidChart图表库,部分自定义控件等。

        支持Android5.0以上版本。

        本文将介绍小哈记账的首页页面制作。

 效果图:

记账APP:小哈记账4——记账首页页面的制作(1)_第1张图片 

源代码:

        首先,让我们介绍一下首页页面的模块组成。页面最顶部是一个卡片,其中展示了当前月份以及本月的收入、支出和结余情况。接下来,我们可以看到一个本月支出预算的模块,其中展示了当前支出的金额以及占总预算的百分比。第三部分是本月收支趋势图,其中展示了当前月份每日的收入和支出情况。最后,我们还可以看到今日、本周和本年的收入和支出情况,这一部分的信息也非常有用。

顶部卡片的制作(本月收支、结余)

第一步:本月统计样式的编写main.xml




    
    
    

        

        
    

    
    

        

            

            
        

        

            

            
        
    

背景图片为Adobe Illustrator制作。其余部分为LinearLayout和TextView组成,比较简单。

第二步:功能实现,编写MainActivity.java文件

该部分比较简单,从数据库获取数据,求和赋值给TextView即可。

public int year = MyUtils.initYear();
public int month = MyUtils.initMonth();
public int day = MyUtils.initDay();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    context = this;
    mActivity = new WeakReference(this);

    initView();//初始化控件
    main_month.setText(year+"年"+month+"月");//为卡片的当前月份赋值
}

@Override
protected void onStart() {
    super.onStart();
    if(is_add || is_delete){
        progressBarLayout.setVisibility(View.VISIBLE);
        main_layout.setVisibility(View.GONE);
        Message msg = new Message();
        sum_ThisMonth(month);//更新数据
        setThisDate();//添加当前数据
        handlerProgress.sendEmptyMessageDelayed(1,2000);
    }
}
/**
    * 求出数据和
    * @param mmonth 本月月份
    */
private void sum_ThisMonth(int mmonth){
    zc_week_money = 0;
    zc_day_money = 0;
    zc_year_money = 0;
    sr_week_money = 0;
    sr_day_money = 0;
    sr_year_money = 0;
    used_money = 0;
    sr_money = 0;
    jy_money = 0;

    lineChartMoney_zc.clear();
    lineChartMoney_zc = new ArrayList(Collections.nCopies(31, 0.0));
    lineChartMoney_sr.clear();
    lineChartMoney_sr = new ArrayList(Collections.nCopies(31, 0.0));

    List accDetails = LitePal.where("user_id = ?", String.valueOf(LoginActivity.mid))
            .find(AccDetails.class);
    for(AccDetails accDetails1 : accDetails){
        String[] date = accDetails1.getDet_date().split("-");
        /*获取本年收支*/
        if(Integer.valueOf(date[0]) == year && accDetails1.getDet_type_int() == 0){
            if(MyUtils.getTypeInt(accDetails1.getDet_type()) != -1){
                zc_year_money += accDetails1.getDet_money();
                /*获取本月支出*/
                if(Integer.valueOf(date[1]) == mmonth){
                    used_money += accDetails1.getDet_money();
                    lineChartMoney_zc.set(Integer.valueOf(date[2])-1, accDetails1.getDet_money()+lineChartMoney_zc.get(Integer.valueOf(date[2])-1));
                    if(Integer.valueOf(date[2]) == day){
                        zc_day_money += accDetails1.getDet_money();
                    }
                }
                /*获取本周支出*/
                for(int i = 0; i<7;i++){
                    if(String.valueOf(Integer.valueOf(date[1])+"-"+Integer.valueOf(date[2])).equals(MyUtils.weekDay.get(i))){
                        zc_week_money += accDetails1.getDet_money();
                    }
                }
            }
        } else if(Integer.valueOf(date[0]) == year && accDetails1.getDet_type_int() == 1){
            if(MyUtils.getTypeIncomeInt(accDetails1.getDet_type()) != -1){
                sr_year_money += accDetails1.getDet_money();
                /*获取本月收入*/
                if(Integer.valueOf(date[1]) == mmonth){
                    sr_money += accDetails1.getDet_money();
                    lineChartMoney_sr.set(Integer.valueOf(date[2])-1, accDetails1.getDet_money()+lineChartMoney_sr.get(Integer.valueOf(date[2])-1));
                    if(Integer.valueOf(date[2]) == day){
                        sr_day_money += accDetails1.getDet_money();
                    }
                }
                /*获取本周收入*/
                for(int i = 0; i<7;i++){
                    if(String.valueOf(Integer.valueOf(date[1])+"-"+Integer.valueOf(date[2])).equals(MyUtils.weekDay.get(i))){
                        sr_week_money += accDetails1.getDet_money();
                    }
                }
            }
        }
    }
    jy_money = sr_money - used_money;//本月结余
    if(ys_money != -1){

        used_per = (int) Math.round(used_money / ys_money*100);//四舍五入取整
        if(ys_money > used_money){
            ky_money = ys_money - used_money;
        } else {
            ky_money = used_money - ys_money;
        }
    }
    if(used_money == 0){
        ys_used_text.setText("已用 0.00");
        main_zc_money.setText("0.00");
    } else {
        ys_used_text.setText("已用 "+df.format(used_money));
        main_zc_money.setText(df.format(used_money));
    }
    if(sr_money == 0){
        main_sr_money.setText("0.00");
    } else {
        main_sr_money.setText(df.format(sr_money));
    }
    if(jy_money == 0){
        main_jy_money.setText("0.00");
    } else {
        main_jy_money.setText(df.format(jy_money));
    }
    if(ys_money != -1){
        ys_text.setText("总支出预算 "+df.format(ys_money));
        ys_used_per.setText(used_per+"%");
        if(ky_money == 0){
            ys_ky_text.setText("可用 0.00");
        } else {
            if(used_per >= 80 && used_per <= 100){
                ys_ky_text.setText("可用 "+df.format(ky_money));
                ys_ky_text.setTextColor(Color.parseColor("#e8b004"));
                ys_used_per.setTextColor(Color.parseColor("#e8b004"));
            } else if(used_per > 100){
                ys_ky_text.setText("已超出预算 "+df.format(ky_money));
                ys_ky_text.setTextColor(Color.parseColor("#ee3f4d"));
                ys_used_per.setTextColor(Color.parseColor("#ee3f4d"));
            } else {
                ys_ky_text.setText("可用 "+df.format(ky_money));
                ys_ky_text.setTextColor(Color.parseColor("#666666"));
                ys_used_per.setTextColor(Color.parseColor("#666666"));
            }
        }
    }

}

预算功能的实现

首先需要自定义一个进度条控件。

自定义进度条java文件:

package com.example.xiaohaaccounting.myView;

import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import com.example.xiaohaaccounting.R;


public class CircleProgressBar extends View {
   private Context mContext;
   private Paint mPaint;
   private int mProgress = 0;
   private static int MAX_PROGRESS = 100;
   /**
    * 弧度
    */
   private int mAngle;
   /**
    * 中间的文字
    */
   private String mText;
   /**
    * 外圆颜色
    */
   private int outRoundColor;
   /**
    * 内圆的颜色
    */
   private int inRoundColor;
   /**
    * 线的宽度
    */
   private int roundWidth;
   private int style;
   /**
    * 字体颜色
    */
   private int textColor;
   /**
    * 字体大小
    */
   private float textSize;
   /**
    * 字体是否加粗
    */
   private boolean isBold;

   /**
    * 进度条颜色
    */
   private int progressBarColor;

   public CircleProgressBar(Context context) {
      this(context, null);
   }

   public CircleProgressBar(Context context, AttributeSet attrs) {
      this(context, attrs, 0);
   }

   public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      mContext = context;
      init(attrs);
   }

   @TargetApi(21)
   public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
      super(context, attrs, defStyleAttr, defStyleRes);
      mContext = context;
      init(attrs);
   }

   /**
    * 解析自定义属性
    *
    * @param attrs
    */
   public void init(AttributeSet attrs) {
      mPaint = new Paint();
      TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar);
      outRoundColor = typedArray.getColor(R.styleable.CircleProgressBar_outCircleColor, getResources().getColor(R.color.grey_e));
      inRoundColor = typedArray.getColor(R.styleable.CircleProgressBar_inCircleColor, getResources().getColor(R.color.white));
      progressBarColor = typedArray.getColor(R.styleable.CircleProgressBar_progressColor, getResources().getColor(R.color.xiaoha));
      isBold = typedArray.getBoolean(R.styleable.CircleProgressBar_textBold, false);
      textColor = typedArray.getColor(R.styleable.CircleProgressBar_textColor, Color.BLACK);
      roundWidth = typedArray.getDimensionPixelOffset(R.styleable.CircleProgressBar_lineWidth, 20);
      typedArray.recycle();
   }

   @Override
   protected void onDraw(Canvas canvas) {
      /**
       * 画外圆
       */
      super.onDraw(canvas);
      int center = getWidth() / 2;        //圆心
      int radius = (center - roundWidth / 2);  //半径
      mPaint.setColor(outRoundColor);      //外圆颜色
      mPaint.setStrokeWidth(roundWidth);     //线的宽度
      mPaint.setStyle(Paint.Style.STROKE);    //空心圆
      mPaint.setAntiAlias(true);        //消除锯齿
      canvas.drawCircle(center, center, radius, mPaint);
      //内圆
      mPaint.setColor(inRoundColor);
      radius = radius - roundWidth;
      canvas.drawCircle(center, center, radius, mPaint);

      //画进度是一个弧线
      mPaint.setColor(progressBarColor);
      RectF rectF = new RectF(center - radius, center - radius, center + radius, center + radius);//圆弧范围的外接矩形
      canvas.drawArc(rectF, -90, mAngle, false, mPaint);
      canvas.save(); //平移画布之前保存之前画的

      //画进度终点的小球,旋转画布的方式实现
      mPaint.setStyle(Paint.Style.FILL);
      //将画布坐标原点移动至圆心
      canvas.translate(center, center);
      //旋转和进度相同的角度,因为进度是从-90度开始的所以-90度
      canvas.rotate(mAngle - 90);
      //同理从圆心出发直接将原点平移至要画小球的位置
      canvas.translate(radius, 0);
      canvas.drawCircle(0, 0, roundWidth, mPaint);
      //画完之后恢复画布坐标
      canvas.restore();

      //画文字将坐标平移至圆心
      canvas.translate(center, center);
      mPaint.setStrokeWidth(0);
      mPaint.setColor(textColor);
      if (isBold) {
         //字体加粗
         mPaint.setTypeface(Typeface.DEFAULT_BOLD);
      }
      if (TextUtils.isEmpty(mText)) {
         mText = mProgress + "%";
      }
      //动态设置文字长为圆半径,计算字体大小
      float textLength = mText.length();
      textSize = radius / textLength*2;
      mPaint.setTextSize(textSize);
      //将文字画到中间
      float textWidth = mPaint.measureText(mText);
      canvas.drawText(mText, -textWidth / 2, textSize / 2, mPaint);
   }


   public int getmProgress() {
      return mProgress;
   }

   /**
    * 设置进度
    *
    * @return
    */
   public void setmProgress(int p) {
      if (p > MAX_PROGRESS) {
         mProgress = MAX_PROGRESS;
         mAngle = 360;
      } else {
         mProgress = p;
         mAngle = 360 * p / MAX_PROGRESS;
      }
   }


   public String getmText() {
      return mText;
   }

   /**
    * 设置文本
    *
    * @param mText
    */
   public void setmText(String mText) {
      this.mText = mText;
   }

   /**
    * 设置带动画的进度
    * @param p
    */
   public void setAnimProgress(int p) {
      if (p > MAX_PROGRESS) {
         mProgress = MAX_PROGRESS;
      } else {
         mProgress = p;
      }
      //设置属性动画
      ValueAnimator valueAnimator = new ValueAnimator().ofInt(0, p);
      //动画从快到慢
      valueAnimator.setInterpolator(new DecelerateInterpolator());
      valueAnimator.setDuration(1200);
      //监听值的变化
      valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
         @Override
         public void onAnimationUpdate(ValueAnimator animation) {
            int currentV = (Integer) animation.getAnimatedValue();
            Log.e("fwc", "current" + currentV);
            mAngle = 360 * currentV / MAX_PROGRESS;
            mText = currentV + "%";
            invalidate();
         }
      });
      valueAnimator.start();
   }
}

arrts.xml文件:



    
        
        
        
        
        
        
    

整体样式xml如下




    

    
        
        

        

            

            
        

        

            

            
        
    

设置预算功能

/*设置预算*/
ys_layout.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        //点击弹出对话框
        final EditDialog editDialog = new EditDialog(MainActivity.this);
        editDialog.setTitle("请输入每月预算");
        editDialog.setYesOnclickListener("确定", new EditDialog.onYesOnclickListener() {
            @Override
            public void onYesClick(String ys) {
                if (TextUtils.isEmpty(ys)) {
                    Toast.makeText(MainActivity.this, "请输入每月预算", Toast.LENGTH_SHORT).show();
                } else if(Double.parseDouble(ys) <= 0){
                    Toast.makeText(MainActivity.this, "预算必须大于0", Toast.LENGTH_SHORT).show();
                } else {
                    Message msg = new Message();
                    ys_text.setText(ys);
                    ys_money = Double.parseDouble(ys);
                    save_User(ys_money);
                    sum_ThisMonth(month);
                    handlerProgress.sendEmptyMessageDelayed(1,0);
                    editDialog.dismiss();
            /*//让软键盘隐藏
            InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(getView().getApplicationWindowToken(), 0);*/
                }
            }
        });
        editDialog.setNoOnclickListener("取消", new EditDialog.onNoOnclickListener() {
            @Override
            public void onNoClick() {
                editDialog.dismiss();
            }
        });
        editDialog.show();
    }
});

今日、本周、本年模块

本部分也比较简单,和第一部分思路相同,直接上代码

xml代码



    
    

        
        

            

            
        

        

            

                

                
            

            

                

                
            
        
    
    
    
    

        

        

            

            
        

        

            

                

                
            

            

                

                
            
        
    
    
    
    

        

        

            

            
        

        

            

                

                
            

            

                

                
            
        
    

java代码同第一部分。

        本文介绍了首页的三个模块的代码,下一篇(记账APP:小哈记账5——记账首页页面的制作(2))将介绍首页中的收支趋势图的制作,使用MPAndroidChat技术实现。首页完整代码也将在下一篇文章中给出。

你可能感兴趣的:(移动应用开发(安卓),android,java)