美文网首页
扇形进度条 可点击可滑动

扇形进度条 可点击可滑动

作者: azu_test | 来源:发表于2020-11-30 15:16 被阅读0次
    扇形进度条.png
    package com.wuyzh.test;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.RadialGradient;
    import android.graphics.RectF;
    import android.graphics.Shader;
    import android.graphics.Xfermode;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    /***
     * 1/4扇形进度条
     * */
    public class PieChartSeekBar extends View {
    
        //饼状图半径
        private float mRadius = DensityUtils.dip2px(getContext(), 320);
        private RectF mSectorRectF = new RectF();
        //扇形外圈宽度
        private float mRadiusOutlineWidth = 5f;
        private RectF mIncludeOutLineRectF = new RectF();
        //初始画弧所在的角度
        private float mCurrentDegree = 135f;
        //空白间隙占整个圆形的大小比例
        private double mSpacePercent = 0.002f;
        //每块扇形占整个圆的大小比例
        private double mSectorPercent;
        //扇形块个数
        private int mSize = 8;
        //当前进度
        private int mCurrentLevel = 4;
        //画笔
        private Paint mPaint;
        private Xfermode mDstOutXfermode;
        private PorterDuff.Mode mDstOutPorterDuffMode = PorterDuff.Mode.DST_OUT;
        private Xfermode mSrcOverXfermode;
        private PorterDuff.Mode mSrcOverPorterDuffMode = PorterDuff.Mode.SRC_OVER;
        //设置监听回调
        private OnPieChartSeekBarChangeListener  mOnPieChartSeekBarChangeListener;
        public PieChartSeekBar(Context context) {
            super(context);
            init();
        }
    
        public PieChartSeekBar(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public PieChartSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        //初始化画笔和效果动画
        private void init() {
            mDstOutXfermode = new PorterDuffXfermode(mDstOutPorterDuffMode);
            mSrcOverXfermode = new PorterDuffXfermode(mSrcOverPorterDuffMode);
            initRectF();
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setStyle(Paint.Style.FILL);
            mSectorPercent = (0.25 - (mSize-1)*mSpacePercent)/mSize;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            int saveCount = canvas.saveLayer(mIncludeOutLineRectF, mPaint, Canvas.ALL_SAVE_FLAG);
            mCurrentDegree = 135;
            float pieSweep;
            for (int i = 1; i <= mSize; i++){
                if (i <= mCurrentLevel){
                    //画外部进度指示线 颜色:0xFFcca267
                    pieSweep = (float) (mSectorPercent *360);
                    mPaint.setShader(null);
                    mPaint.setColor(0xFFcca267);
                    canvas.drawArc(mIncludeOutLineRectF, mCurrentDegree, pieSweep, true, mPaint);
    
                    //切掉内部圆
                    mPaint.setColor(Color.BLACK);
                    mPaint.setXfermode(mDstOutXfermode);
                    canvas.drawArc(mSectorRectF, mCurrentDegree-0.002f*360,  pieSweep+0.003f*360,true, mPaint);
                    mPaint.setXfermode(null);
    
                    //画扇形 颜色:0xFF02DAFD
                    RadialGradient gradient =new RadialGradient(mRadius,mRadius,mRadius-mRadiusOutlineWidth,new int[]{Color.TRANSPARENT,Color.TRANSPARENT,0xFF02DAFD},new float[]{0,(mRadius-100)/mRadius,1},Shader.TileMode.MIRROR);
                    mPaint.setShader(gradient);
                    mPaint.setXfermode(mSrcOverXfermode);
                    canvas.drawArc(mSectorRectF, mCurrentDegree, pieSweep, true, mPaint);
                    mPaint.setXfermode(null);
                    mCurrentDegree = mCurrentDegree + pieSweep;
                }else {
                    //画外部进度指示线  颜色:0xFF65fbe4
                    pieSweep = (float) (mSectorPercent *360);
                    mPaint.setShader(null);
                    mPaint.setColor(0xFF65fbe4);
                    canvas.drawArc(mIncludeOutLineRectF, mCurrentDegree, pieSweep, true, mPaint);
    
                    //切掉内部圆
                    mPaint.setColor(Color.BLACK);
                    mPaint.setXfermode(mDstOutXfermode);
                    canvas.drawArc(mSectorRectF, mCurrentDegree-0.002f*360,  pieSweep+0.003f*360,true, mPaint);
                    mPaint.setXfermode(null);
    
                    //画扇形  颜色:0xFFFFFFFF
                    RadialGradient gradient =new RadialGradient(mRadius,mRadius,mRadius-mRadiusOutlineWidth,new int[]{Color.TRANSPARENT,Color.TRANSPARENT,0xFFFFFFFF},new float[]{0,(mRadius-100)/mRadius,1},Shader.TileMode.MIRROR);
                    mPaint.setShader(gradient);
                    mPaint.setXfermode(mSrcOverXfermode);
                    canvas.drawArc(mSectorRectF, mCurrentDegree, pieSweep, true, mPaint);
                    mPaint.setXfermode(null);
                    mCurrentDegree = mCurrentDegree + pieSweep;
                }
                //画透明间隔
                if (i != mSize){
                    pieSweep = (float) (mSpacePercent * 360);
                    mPaint.setColor(Color.TRANSPARENT);
                    canvas.drawArc(mIncludeOutLineRectF, mCurrentDegree, pieSweep, true, mPaint);
                    mCurrentDegree = mCurrentDegree + pieSweep;
                }
            }
    
            //切掉内部圆
            mPaint.setShader(null);
            mPaint.setColor(Color.BLACK);
            mPaint.setXfermode(mDstOutXfermode);
            canvas.drawCircle(mRadius, mRadius,  mRadius-100, mPaint);
            mPaint.setXfermode(null);
            canvas.restoreToCount(saveCount);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int length = (int) (2 * mRadius);
            setMeasuredDimension(length, length);
        }
    
        /**
         * 初始化绘制弧形所在矩形的四点坐标
         **/
        private void initRectF() {
            mSectorRectF.left = 0 +mRadiusOutlineWidth;
            mSectorRectF.top = 0 + mRadiusOutlineWidth;
            mSectorRectF.right = 2 * mRadius - mRadiusOutlineWidth;
            mSectorRectF.bottom = 2 * mRadius - mRadiusOutlineWidth;
    
            mIncludeOutLineRectF.left = 0;
            mIncludeOutLineRectF.top = 0;
            mIncludeOutLineRectF.right = 2 * mRadius;
            mIncludeOutLineRectF.bottom = 2 * mRadius;
        }
    
        private int mTouchPosition;
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mTouchPosition = doOnSpecialTypeClick(event);
                    if (mTouchPosition == -1){
                        return false;
                    }else {
                        mCurrentLevel = mTouchPosition;
                        if (mOnPieChartSeekBarChangeListener != null){
                            mOnPieChartSeekBarChangeListener.onStartTrackingTouch(this);
                        }
                        invalidate();
                        return true;
                    }
                case MotionEvent.ACTION_MOVE:
                    mTouchPosition = doOnSpecialTypeClick(event);
                    if (mTouchPosition != -1){
                        mCurrentLevel = mTouchPosition;
                        if (mOnPieChartSeekBarChangeListener != null){
                            mOnPieChartSeekBarChangeListener.onProgressChanged(this,mCurrentLevel,true);
                        }
                        invalidate();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (mOnPieChartSeekBarChangeListener != null){
                        mOnPieChartSeekBarChangeListener.onStopTrackingTouch(this);
                    }
                    break;
            }
            return super.onTouchEvent(event);
        }
    
        public int getProgress(){
            return mCurrentLevel;
        }
    
        public void setProgress(int level){
            mCurrentLevel = level;
            if (mOnPieChartSeekBarChangeListener != null){
                mOnPieChartSeekBarChangeListener.onProgressChanged(this,mCurrentLevel,true);
            }
            invalidate();
        }
    
        private int doOnSpecialTypeClick(MotionEvent event) {
            float eventX = event.getX();
            float eventY = event.getY();
            double alfa = 0;
    
            //点击的位置到圆心距离的平方
            double distance = Math.pow(eventX - mRadius, 2) + Math.pow(eventY - mRadius, 2);
            //判断点击的坐标是否在环内
            if (distance < Math.pow(mRadius, 2) && distance > Math.pow(0.72 * mRadius, 2)) {
                int which = touchOnWhichPart(event);
                switch (which) {
                    case PART_ONE:
                        alfa = Math.atan2(eventX - mRadius, mRadius - eventY) * 180 / PI;
                        break;
                    case PART_TWO:
                        alfa = Math.atan2(eventY - mRadius, eventX - mRadius) * 180 / PI + 90;
                        break;
                    case PART_THREE:
                        alfa = Math.atan2(mRadius - eventX, eventY - mRadius) * 180 / PI + 180;
                        break;
                    case PART_FOUR:
                        alfa = Math.atan2(mRadius - eventY, mRadius - eventX) * 180 / PI + 270;
                        break;
                }
            }
    
            int position = (int) Math.ceil((alfa-225)/(90.0/mSize));
            if (0 <= position&& position <= mSize){
                return position;
            }else {
                return -1;
            }
        }
    
        /**
         *    4 |  1
         * -----|-----
         *    3 |  2
         * 圆被分成四等份,判断点击在园的哪一部分
         */
        private static final int PART_ONE = 1;
        private static final int PART_TWO = 2;
        private static final int PART_THREE = 3;
        private static final int PART_FOUR = 4;
        //圆周率
        private static final float PI = 3.1415f;
        private int touchOnWhichPart(MotionEvent event) {
            if (event.getX() > mRadius) {
                if (event.getY() > mRadius) return PART_TWO;
                else return PART_ONE;
            } else {
                if (event.getY() > mRadius) return PART_THREE;
                else return PART_FOUR;
            }
        }
    
        public void setOnPieChartSeekBarChangeListener(OnPieChartSeekBarChangeListener onPieChartSeekBarChangeListener){
            mOnPieChartSeekBarChangeListener = onPieChartSeekBarChangeListener;
        }
    
        public interface OnPieChartSeekBarChangeListener {
            void onProgressChanged(PieChartSeekBar pieChartSeekBar, int level, boolean isFromUser);
    
            void onStartTrackingTouch(PieChartSeekBar pieChartSeekBar);
    
            void onStopTrackingTouch(PieChartSeekBar pieChartSeekBar);
        }
    }
    

    自定义属性颜色啥的自己来吧。。。。
    使用

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/seat_set_background"
        tools:context=".MainActivity">
    
        <com.wuyazh.test.PieChartSeekBar
            android:id="@+id/pie_chart_seek_bar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"/>
    
    </RelativeLayout>
    ```![扇形进度条.png](https://img.haomeiwen.com/i11008949/a3fee86894cb4717.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    

    相关文章

      网友评论

          本文标题:扇形进度条 可点击可滑动

          本文链接:https://www.haomeiwen.com/subject/hkgrwktx.html