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)