本文实例为大家分享了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");
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。