Android仿支付寶賬單統(tǒng)計餅狀圖
仿支付寶統(tǒng)計餅狀圖,如下圖:

效果圖:

源代碼:
/*** 餅狀圖*/public class PieChartView extends View {private Paint paintChart, paintText, paintLine, paintMasking;private RectF mRectF = new RectF();//餅狀圖的數(shù)據(jù)(如:name、value數(shù)值、顏色等)private ListmPieDatas = new ArrayList<>(); //總數(shù),方便算百分比private float mSumValue;//半徑private int radius;//直徑private int diameter;//中心坐標(biāo)private int centerX, centerY;//間隔的距離private float space;private boolean showTip;private int tipSize;private boolean openAnimation;private ValueAnimator mAnimator;// 默認的動效周期 2sprivate int defaultDuration = 1000;//動畫的執(zhí)行的百分比mAnimatorValueprivate float mAnimatorValue = 1f;public PieChartView(Context context) {super(context);initAll();}public PieChartView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public PieChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PieChartView, defStyleAttr, 0);diameter = typedArray.getDimensionPixelSize(R.styleable.PieChartView_pie_size, 0);space = typedArray.getFloat(R.styleable.PieChartView_pie_space, 0f);openAnimation = typedArray.getBoolean(R.styleable.PieChartView_open_animation, false);showTip = typedArray.getBoolean(R.styleable.PieChartView_show_tip, false);tipSize = showTip?100:0;//如果顯示tip,則預(yù)留出tip控件的間距typedArray.recycle();initAll();}private void initAll() {initPain();if (openAnimation) {startAnimation();}}private void initPain() {paintChart = new Paint();paintChart.setAntiAlias(true);paintChart.setColor(Color.BLACK);paintMasking = new Paint();paintMasking.setColor(Color.WHITE);paintMasking.setStyle(Paint.Style.FILL);paintMasking.setAntiAlias(true);paintLine = new Paint();paintLine.setStyle(Paint.Style.STROKE);paintLine.setStrokeWidth(5);paintLine.setAntiAlias(true);paintText = new Paint();paintText.setColor(Color.BLACK);paintText.setStyle(Paint.Style.FILL);paintText.setStrokeWidth(20);paintText.setTextSize(30);}/*** 設(shè)置數(shù)據(jù)源* @param pieData 餅狀圖的數(shù)據(jù)*/public void setPieData(ListpieData) { if (pieData.size() > 0) {mPieDatas = pieData;if (mPieDatas.size() > 0) {int sumValue = 0;for (PieData data : mPieDatas) {sumValue += data.getValue();}mSumValue = sumValue;}}}@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//設(shè)置尺寸,沒有設(shè)置pie_size或者設(shè)置的size + 預(yù)留給tip控件的距離>=最小邊時不使用xml里設(shè)置的直徑尺寸if (diameter <= 0 || diameter+tipSize >= getWidth() || diameter+tipSize >= getHeight()) {diameter = (getWidth() > getHeight() ? getHeight() : getWidth()) - tipSize;}radius = diameter / 2;centerX = getWidth() / 2;centerY = getHeight() / 2;mRectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);}private float startAngle = -90;private float sweepAngle;@Override protected void onDraw(Canvas canvas) {super.onDraw(canvas);if (mPieDatas == null || mPieDatas.size() <= 0) {canvas.drawArc(mRectF, 0, 360, true, paintChart);canvas.drawCircle(centerX, centerY, radius / 2, paintMasking);return;}for (PieData data : mPieDatas) {paintChart.setColor(data.getColor());paintLine.setColor(data.getColor());sweepAngle = (data.getValue() / mSumValue) * 360f;canvas.drawArc(mRectF, startAngle, sweepAngle * mAnimatorValue - space, true, paintChart);if (showTip) {//是否畫標(biāo)簽說明的小部件drawTip(canvas, data);}startAngle += sweepAngle;}canvas.drawCircle(centerX, centerY, radius / 2, paintMasking);}/*** 畫tip控件*/private void drawTip(Canvas canvas, PieData data) {Path pathLine = new Path();PathMeasure measure = new PathMeasure();float textPadding = 10;float textHigh = (paintText.getFontMetrics().bottom - paintText.getFontMetrics().top) / 2;float padding = 20;float dotSize = 10;float dotX = (float) (centerX + (radius + padding) * Math.cos(Math.toRadians((startAngle + sweepAngle / 2))));float dotY = (float) (centerY + (radius + padding) * Math.sin(Math.toRadians((startAngle + sweepAngle / 2))));float lineX = (float) (centerX + (radius + padding * 2) * Math.cos(Math.toRadians((startAngle + sweepAngle / 2))));float lineY = (float) (centerY + (radius + padding * 2) * Math.sin(Math.toRadians((startAngle + sweepAngle / 2))));canvas.drawCircle(dotX, dotY, dotSize, paintChart);if (dotX > centerX) {//右側(cè)pathLine.moveTo(dotX, dotY);pathLine.lineTo(lineX, lineY);pathLine.lineTo(getRight(), lineY);measure.setPath(pathLine, false);Path dst = new Path();measure.getSegment(0, measure.getLength() * mAnimatorValue, dst, true);canvas.drawPath(dst, paintLine);if (mAnimatorValue == 1) {paintText.setTextAlign(Paint.Align.RIGHT);canvas.drawText((data.getValue() / mSumValue) * 100 + "%", getWidth() - textPadding, lineY - textPadding, paintText);canvas.drawText(data.getName(), getWidth() - textPadding, lineY + textHigh + textPadding, paintText);}} else {//左側(cè)measure = new PathMeasure();pathLine.moveTo(dotX, dotY);pathLine.lineTo(lineX, lineY);pathLine.lineTo(0, lineY);measure.setPath(pathLine, false);Path dst = new Path();measure.getSegment(0, measure.getLength() * mAnimatorValue, dst, true);canvas.drawPath(dst, paintLine);if (mAnimatorValue == 1) {paintText.setTextAlign(Paint.Align.LEFT);canvas.drawText((data.getValue() / mSumValue) * 100 + "%", 0 + textPadding, lineY - textPadding, paintText);canvas.drawText(data.getName(), 0 + textPadding, lineY + textHigh + textPadding, paintText);}}}/*** 開啟動畫*/private void startAnimation() {mAnimator = ValueAnimator.ofFloat(0, 1).setDuration(defaultDuration);mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Override public void onAnimationUpdate(ValueAnimator valueAnimator) {mAnimatorValue = (float) valueAnimator.getAnimatedValue();invalidate();}});mAnimator.start();??}}
attrs 屬性文件:
xml 布局文件:
android:id="@+id/pie_char"android:layout_width="match_parent"android:layout_height="200dp"app:pie_size="190dp"app:pie_space="2"app:show_tip="true"app:open_animation="true"android:visibility="visible"/>
評論
圖片
表情
