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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值