Android自定义控件实现支付宝记账饼图

作者:匡效国 时间:2022-04-19 13:27:02 

本文实例为大家分享了Android实现支付宝记账饼图,点击旋转到最下面,供大家参考,具体内容如下

Android自定义控件实现支付宝记账饼图

代码:


package com.example.a_102.myapplication7.ui;

import java.util.ArrayList;
import java.util.List;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;

import com.example.a_102.myapplication7.util.Util;

/**
*
*/
public class SelectPieView extends View {

private static final String TAG = "CustomPie_tag";
private int width;
private SelectPieCallBack mCallBack;
private boolean initPostion = false;
/**
 * 当前选中的区域
 */
private int currentDownPostion;

public SelectPieView(Context context) {
 super(context);
}

public SelectPieView(Context context, AttributeSet attrs) {
 super(context, attrs);
}

public SelectPieView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 int width;
 int hight;

int widthmode = MeasureSpec.getMode(widthMeasureSpec);
 int widthsize = MeasureSpec.getSize(widthMeasureSpec);

int hightmode = MeasureSpec.getMode(heightMeasureSpec);
 int hightsize = MeasureSpec.getSize(heightMeasureSpec);

if (MeasureSpec.EXACTLY == widthmode) {
  width = widthsize;
 } else {
  width = 200;
  if (MeasureSpec.AT_MOST == widthmode) {
   width = Math.min(widthsize, 200);
  }
 }

if (MeasureSpec.EXACTLY == hightmode) {
  hight = hightsize;
 } else {
  hight = 200;
  if (MeasureSpec.AT_MOST == hightmode) {
   hight = Math.min(hightsize, 200);
  }
 }

setMeasuredDimension(Math.min(width, hight), Math.min(width, hight));
}

/**
 * 笔宽
 */
private int mPaintWid;
/**
 * 外边圆半径
 */
private int mOutRoot;
/**
 * 内边圆半径
 */
private int mIntRoot;
/**
 * 空白处宽度
 */
private int emptysize = -1;
/**
 * 点击前的圆和点击后的圆半径差距
 */
private float betweenSize = 10;
/**
 * 向限
 */
private int XIANGXAIN;
/**
 * 开始的角度
 */
private float start = 360;
/**
 * 旋转过的角度
 */
private List<startAndRoatData> haveRoats = new ArrayList<>();
/**
 *
 */
private String mTitle = "总消费";
/**
 *
 */
private String mSubTitle = "00";
/**
 *
 */
private String mSubTitleDot = "00";
/**
 * 是否在运行
 */
private boolean isRun = true;

private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

private Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/**
 * 整数部分
 */
private Paint textPaintSubTitle= new Paint(Paint.ANTI_ALIAS_FLAG);
/**
 * 小数部分
 */
private Paint textPaintSubTitleDot= new Paint(Paint.ANTI_ALIAS_FLAG);

@Override
protected void onDraw(Canvas canvas) {
 // reSetData();
 if (null == datas || datas.size() == 0)
  return;
 width = getWidth();
 mOutRoot = width / 2;
 mPaintWid = Util.dip2px(getContext(), 40);
 mIntRoot = mOutRoot - mPaintWid;

paint.setStyle(Paint.Style.STROKE);
 paint.setColor(Color.RED);
 paint.setStrokeWidth(mPaintWid);
 RectF rt = new RectF(mPaintWid / 2 + betweenSize, mPaintWid / 2 + betweenSize,
   width - mPaintWid / 2 - betweenSize, width - mPaintWid / 2 - betweenSize);
 RectF rt2 = new RectF(mPaintWid / 2, mPaintWid / 2, width - mPaintWid / 2, width - mPaintWid / 2);

int size = datas.size();
 float allValues = 0;
 for (int i = 0; i < datas.size(); i++) {
  allValues += datas.get(i).getValuse();
 }
 // allValues = allValues + emptysize * size;
 float sigleSize = (360 - emptysize * datas.size()) / (allValues * 1f);

float end = 0;
 haveRoats.clear();
 for (int i = 0; i < size; i++) {
  paint.setColor(getResources().getColor(datas.get(i).getColor()));
  end = datas.get(i).getValuse() * sigleSize;

if (!isRun && datas.get(i).getPostion() == currentDownPostion && datas.size()>1) {
   canvas.drawArc(rt2, start + 3, end - 6, false, paint);
   canvas.drawArc(rt, start + 3, end - 6, false, paint);
  } else {
   canvas.drawArc(rt, start, end, false, paint);
  }
  Log.i(TAG, "first=" + start % 360 + "==" + end + "postion=" + datas.get(i).getPostion());

haveRoats.add(new startAndRoatData(datas.get(i).getPostion(), start % 360, end));

start = start + end + emptysize;

}

textPaint.setStrokeWidth(Util.dip2px(getContext(), 1));
 /** 画图片 */
 for (int i = 0; i < haveRoats.size(); i++) {
  startAndRoatData startAndRoatData = haveRoats.get(i);

float x = 0;
  float y = 0;

if (!isRun && currentDownPostion == haveRoats.get(i).getPostion() && datas.size()>1) {

x = (float) (Math
     .cos(Math.PI / 180 * (startAndRoatData.getStartAng() + startAndRoatData.getRoatAng() / 2))
     * (mIntRoot + mPaintWid / 2) + mOutRoot);
   y = (float) (Math
     .sin(Math.PI / 180 * (startAndRoatData.getStartAng() + startAndRoatData.getRoatAng() / 2))
     * (mIntRoot + mPaintWid / 2) + mOutRoot);
  } else {
   x = (float) (Math
     .cos(Math.PI / 180 * (startAndRoatData.getStartAng() + startAndRoatData.getRoatAng() / 2))
     * (mIntRoot + mPaintWid / 2 - betweenSize) + mOutRoot);
   y = (float) (Math
     .sin(Math.PI / 180 * (startAndRoatData.getStartAng() + startAndRoatData.getRoatAng() / 2))
     * (mIntRoot + mPaintWid / 2 - betweenSize) + mOutRoot);
  }

Rect rect = new Rect((int) (x - mPaintWid / 3), (int) (y - mPaintWid / 3), (int) (x + mPaintWid / 3),
    (int) (y + mPaintWid / 3));

int width = BitmapFactory.decodeResource(getResources(), datas.get(i).getIcon()).getWidth();
  // L=n(圆心角度数)× π(圆周率)× r(半径)/180(角度制)
  if (startAndRoatData.getRoatAng() * Math.PI * (mIntRoot + mPaintWid / 2) / 180 > width) {
   canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), datas.get(i).getIcon()), null, rect,
     null);
  }
 }

textPaint.setStyle(Paint.Style.FILL);
 textPaint.setTextSize(Util.dip2px(getContext(), 14));
 /** 写文字 */
 canvas.drawText(mTitle, width / 2 - (textPaint.measureText(mTitle)) / 2,
   width / 2 - Util.dip2px(getContext(), 8), textPaint);

textPaintSubTitle.setTextSize(Util.dip2px(getContext(), 20));
 canvas.drawText(mSubTitle,
   width / 2 - (textPaintSubTitle.measureText(mSubTitle)) / 2 - (textPaintSubTitleDot.measureText("."+mSubTitleDot) / 2),
   width / 2 + Util.dip2px(getContext(), 15), textPaintSubTitle);

textPaintSubTitleDot.setTextSize(Util.dip2px(getContext(), 15));
 canvas.drawText("." + mSubTitleDot,
   width / 2 + textPaintSubTitle.measureText(mSubTitle) /2 - (textPaintSubTitleDot.measureText("." + mSubTitleDot))/2,
   width / 2 + Util.dip2px(getContext(), 15), textPaintSubTitleDot);
 //Toast.makeText(getContext(), "=="+textPaint.measureText(mSubTitle), Toast.LENGTH_SHORT).show();
 /** 测试基线 */
 /*
  * paint.setColor(Color.BLACK);
  * paint.setStrokeWidth(Util.dip2px(getContext(), 1));
  *
  * canvas.drawLine(0, width / 2, width, width / 2, paint);
  * canvas.drawLine(width / 2, 0, width / 2, width, paint);
  */
 /**
  * 初始化位置
  * */
 if (!initPostion) {
  initPostion = true;

startAndRoatData roatData = haveRoats.get(0);
  float currentCenterAng = roatData.getStartAng() + roatData.getRoatAng() / 2;
  if (currentCenterAng < 90) {
   starRoat(start, start + 90 - (roatData.getStartAng() + roatData.getRoatAng() / 2), false);
  } else if (currentCenterAng > 90 && currentCenterAng < 270) {
   starRoat(start, start - (currentCenterAng - 90), false);
  } else {
   starRoat(start, start + 360 + 90 - (roatData.getStartAng() + roatData.getRoatAng() / 2), false);
  }
  currentDownPostion = roatData.getPostion();
  isRun = false;
  invalidate();
 }

}

/**
 * 设置显示金额
 *
 * @param number
 */
public void setNumber(String number) {
 if (TextUtils.isEmpty(number)) {
  number = "0.00";
 }
 if (number.contains(".")) {
  String[] split = number.split("\\.");
  mSubTitle = split[0];
  mSubTitleDot = split[1];
 } else {
  mSubTitle = number;
  mSubTitleDot = "00";
 }
 if (mSubTitleDot.length() > 2) {
  mSubTitleDot = mSubTitleDot.substring(0, 2);
 }
}

private int Lxy2;

@Override
public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {
 case MotionEvent.ACTION_DOWN:
  float x = event.getX();
  float y = event.getY();
  double atan = Math.atan((x - mOutRoot) / (mOutRoot - y));
  double currntAngle = (atan / Math.PI * 180);
  double clickAngle = 0;
  Lxy2 = (int) Math.pow(x - mOutRoot, 2) + (int) Math.pow(mOutRoot - y, 2);
  if (Math.pow(mIntRoot, 2) < Lxy2 && Lxy2 < Math.pow(mOutRoot, 2)) {

if (x > width / 2 && y > width / 2) {
    /** currntAngle第四象限是负数 */
    // starRoat(start, (float) (start - currntAngle), true);
    clickAngle = currntAngle +90;

} else if (x > width / 2 && y < width / 2) {
    /** currntAngle第一象限是负数 */
    //starRoat(start, (float) (start + 180 - currntAngle), true);
    clickAngle = currntAngle +270;
   } else if (x < width / 2 && y < width / 2) {
    /** currntAngle第二象限是正数 */
    //starRoat(start, (float) (start - (180 - Math.abs(currntAngle))), true);
    clickAngle = currntAngle +270;
   } else {
    /** currntAngle第三象限是正数 */
    //starRoat(start, (float) (start - Math.abs(currntAngle)), true);
    clickAngle = currntAngle +90;
   }

int i = clickDownPostion(clickAngle);
   startAndRoatData roatData = haveRoats.get(i);
   currentDownPostion = roatData.getPostion();
   float currentCenterAng = roatData.getStartAng() + roatData.getRoatAng() / 2;
   if (currentCenterAng < 90) {
    starRoat(start, start + 90 - (roatData.getStartAng() + roatData.getRoatAng() / 2), true);
   } else if (currentCenterAng > 90 && currentCenterAng < 270) {
    starRoat(start, start - (currentCenterAng - 90), true);
   } else {
    starRoat(start, start + 360 + 90 - (roatData.getStartAng() + roatData.getRoatAng() / 2), true);
   }

}

return true;
 }

return super.onTouchEvent(event);
}

private int clickDownPostion(double clickAngle) {
 for (int i = 0; i < haveRoats.size(); i++) {
  startAndRoatData data = haveRoats.get(i);
  if ((data.getStartAng() < clickAngle && data.getStartAng() + data.getRoatAng() > clickAngle)
    || (data.getStartAng() + data.getRoatAng() > 360
      && ((data.getStartAng() + data.getRoatAng()) % 360) > clickAngle)) {
   return i;
  }
 }
 return 0;
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void starRoat(final float star, final float end, boolean isSmooth) {
 ValueAnimator valueAnimator = ValueAnimator.ofFloat(star, end);
 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
   float animatedValue = (float) animation.getAnimatedValue();
   start = animatedValue;
   isRun = true;
   invalidate();
  }
 });
 valueAnimator.setDuration(isSmooth ? (long) (700) : 10);
 valueAnimator.setInterpolator(new AccelerateInterpolator());
 valueAnimator.start();
 valueAnimator.addListener(new Animator.AnimatorListener() {
  @Override
  public void onAnimationStart(Animator animation) {

}

@Override
  public void onAnimationEnd(Animator animation) {

if (currentDownPostion == -1) {
    start++;
    starRoat(start, start++, false);
   } else {
    isRun = false;
    invalidate();//画突出部分
    mCallBack.currentPostion(currentDownPostion);
   }
  }

@Override
  public void onAnimationCancel(Animator animation) {

}

@Override
  public void onAnimationRepeat(Animator animation) {

}
 });
}

private List<PieData> datas = new ArrayList<>();

public void reSetData(List<PieData> data) {
 datas.clear();
 datas.addAll(data);
 float all =0;
 for (PieData da : datas) {
  all += da.getValuse();
 }
 if (all < 360) {
  for (PieData da : datas) {
   da.setValuse(da.getValuse() * 200);
  }
 }
 for (PieData da : datas) {
  all += da.getValuse();
 }
 /**强制设置最低值*/
 for (PieData da : datas) {
  if (da.getValuse() / all < 0.03) {
   da.setValuse((float) (all * 0.03));
  }
 }

invalidate();

}

/**
 * 判断当前选择的所在区间
 *
 * @return
 */
private int findCurrentDownPostion() {
 if (haveRoats == null || haveRoats.size() <= 0) {
  return 1;
 }

for (int i = 0; i < haveRoats.size(); i++) {

float startAng = haveRoats.get(i).getStartAng();
  float roatAng = haveRoats.get(i).getRoatAng();
  //Utility.Logi(TAG, "currentpostion=sstar=" + startAng + "===rroat=" + roatAng);
  if (startAng < 90 && (startAng <= 90 && startAng + roatAng > 90)) {
   // Utility.Logi(TAG, "currentpostion=" + haveRoats.get(i).getPostion());
   return haveRoats.get(i).getPostion();
  } else if (startAng > 90 && startAng - 360 + roatAng > 90) {
   //Utility.Logi(TAG, "currentpostion=" + haveRoats.get(i).getPostion());
   return haveRoats.get(i).getPostion();
  }
 }
 return -1;
}

public void setCallBack(SelectPieCallBack callBack) {
 this.mCallBack = callBack;
}

public interface SelectPieCallBack {
 void currentPostion(int postion);
}

public static class PieData {

public PieData(int postion, float valuse, int color, int icon) {
  this.postion = postion;
  this.valuse = valuse;
  this.color = color;
  this.icon = icon;
 }

private int postion;

private float valuse;

private int color;

private int icon;

public int getPostion() {
  return postion;
 }

public void setPostion(int postion) {
  this.postion = postion;
 }

public float getValuse() {
  return valuse;
 }

public void setValuse(float valuse) {
  this.valuse = valuse;
 }

public int getColor() {
  return color;
 }

public void setColor(int color) {
  this.color = color;
 }

public int getIcon() {
  return icon;
 }

public void setIcon(int icon) {
  this.icon = icon;
 }
}

class startAndRoatData {

private int postion;

private float startAng;

private float roatAng;

public startAndRoatData(int postion, float startAng, float roatAng) {
  this.postion = postion;
  this.startAng = startAng;
  this.roatAng = roatAng;
 }

public int getPostion() {
  return postion;
 }

public void setPostion(int postion) {
  this.postion = postion;
 }

public float getStartAng() {
  return startAng;
 }

public void setStartAng(float startAng) {
  this.startAng = startAng;
 }

public float getRoatAng() {
  return roatAng;
 }

public void setRoatAng(float roatAng) {
  this.roatAng = roatAng;
 }

@Override
 public String toString() {
  return "startAndRoatData{" + "postion=" + postion + ", startAng=" + startAng + ", roatAng=" + roatAng + '}';
 }
}
}

用法如下:


SelectPieView mPie = (SelectPieView) findViewById(R.id.pie);
mPie.setCallBack(new SelectPieView.SelectPieCallBack() {
@Override
public void currentPostion(int postion) {
 Toast.makeText(CustomViewActivity.this, "postion="+postion, Toast.LENGTH_SHORT).show();
}
});
ArrayList<SelectPieView.PieData> datas = new ArrayList<>();
datas.add(new SelectPieView.PieData(1, 200.3f, R.color.read_color, R.drawable.arrow));
datas.add(new SelectPieView.PieData(2, 200.3f, R.color.hx_red, R.drawable.arrow));
datas.add(new SelectPieView.PieData(3, 200.3f, R.color.text_blue, R.drawable.arrow));
mPie.reSetData(datas);
mPie.setNumber("333.33");

来源:https://blog.csdn.net/qq_15311755/article/details/54344509

标签:Android,支付宝,记账
0
投稿

猜你喜欢

  • SpringBoot如何集成PageHelper分页功能

    2022-10-22 03:18:34
  • 浅谈Java中Collections.sort对List排序的两种方法

    2021-11-18 11:20:22
  • java 中HashCode重复的可能性

    2021-09-13 17:38:05
  • 浅谈MyBatis3 DynamicSql风格语法使用指南

    2023-11-25 13:05:06
  • Spring和SpringBoot之间的区别

    2022-09-28 11:47:38
  • Spring boot2.0 日志集成方法分享(1)

    2023-05-12 20:10:25
  • Java流程控制顺序结构原理解析

    2022-09-13 14:14:03
  • IntelliJ IDEA 2020.1.2激活工具下载及破解方法免费可用至2089年(强烈推荐)

    2023-07-29 09:22:11
  • Flutter自动路由插件auto_route使用详解

    2022-04-25 12:39:52
  • 轻松学习C#的异常处理

    2022-09-14 22:10:20
  • SpringBoot实现单文件上传

    2023-10-01 21:43:42
  • SpringBoot实现文件上传与下载功能的示例代码

    2021-11-10 09:15:32
  • Unity实现VR中在黑板上写字效果

    2021-08-04 20:11:11
  • C# 如何解析获取Url参数值

    2022-07-03 01:00:52
  • Java SpringMVC异步处理详解

    2021-08-10 15:03:58
  • Java面向对象之内部类案例讲解

    2021-09-16 13:28:19
  • TCP/IP协议中三次握手四次挥手的原理及流程分析

    2022-02-04 18:27:03
  • SpringCloud之Feign示例详解

    2023-03-16 06:14:32
  • Android 游戏开发中绘制游戏触摸轨迹的曲线图

    2023-02-26 08:50:30
  • c#中oracle的to_date函数使用方法

    2021-09-06 10:21:17
  • asp之家 软件编程 m.aspxhome.com