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");
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
 赞 (0)
                        
