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"); 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#nhooo.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。