美文网首页
Android--水波纹进度条

Android--水波纹进度条

作者: aruba | 来源:发表于2020-01-21 17:29 被阅读0次
    BezierProgressView
    实现方法是结合贝塞尔曲线和Xfermode,核心是利用path的offset()方法,不断偏移path
    /**
     * 水波纹进度条
     */
    public class BezierProgressView extends View {
        private float progress;
        private float maxProgress;
        private int radius;
        private int circleColor;
        private int waveColor;
        private int textColor;
        private int textSize;
        private Paint roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private Paint wavePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    
        int width, height;
        float centerX, centerY;
        //背景圆的缓冲
        private Bitmap roundBitmap;
        //需要和水波纹做Xfermode处理的缓冲
        private Bitmap xfermodeDstBitmap;
        private Canvas XfermodeCanvas;
    
        private float blurRadius = 15;
    
        private Path wavePath = new Path();
        private LinearGradient linearGradient;
        private float offset = 0;
        //水波纹速度
        private float speed = 3;
    
        public BezierProgressView(Context context) {
            this(context, null);
        }
    
        public BezierProgressView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public BezierProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            setLayerType(LAYER_TYPE_SOFTWARE, null);
    
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.BezierProgressView);
            progress = typedArray.getFloat(R.styleable.BezierProgressView_progress, 0);
            maxProgress = typedArray.getFloat(R.styleable.BezierProgressView_maxProgress, 100);
            radius = typedArray.getInt(R.styleable.BezierProgressView_radius, 100);
            circleColor = typedArray.getColor(R.styleable.BezierProgressView_circleColor, Color.BLACK);
            waveColor = typedArray.getColor(R.styleable.BezierProgressView_waveColor, Color.BLUE);
            textColor = typedArray.getColor(R.styleable.BezierProgressView_textColor, Color.BLACK);
            textSize = typedArray.getDimensionPixelSize(R.styleable.BezierProgressView_textSize, dpToPx(getContext(), 16));
    
            roundPaint.setColor(circleColor);
            roundPaint.setStyle(Paint.Style.FILL);
    
            wavePaint.setColor(waveColor);
            wavePaint.setDither(true);
    
            textPaint.setColor(textColor);
            textPaint.setTextSize(textSize);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            drawRound(canvas);
            if (progress > 0) {
                drawWave(canvas);
                offset -= speed;
                if (offset <= -width) {
                    offset = 0;
                }
                invalidate();
            }
            drawText(canvas);
        }
    
        //画圆
        private void drawRound(Canvas canvas) {
            if (roundBitmap != null) {//画缓冲BlurMaskFilter的圆
                canvas.drawBitmap(roundBitmap, 0, 0, wavePaint);
                return;
            }
    
            width = height = (int) (radius * 2 + blurRadius * 4);
            centerX = width / 2.0f;
            centerY = height / 2.0f;
    
            roundBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            xfermodeDstBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            XfermodeCanvas = new Canvas(xfermodeDstBitmap);
    
            //画BlurMaskFilter的圆
            BlurMaskFilter maskFilter = new BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.OUTER);
            roundPaint.setMaskFilter(maskFilter);
            Canvas roundCanvas = new Canvas(roundBitmap);
            roundCanvas.drawCircle(centerX, centerY, radius, roundPaint);
    
            //画Xfermode的圆
            wavePaint.setColor(Color.WHITE);
            XfermodeCanvas.drawCircle(centerX, centerY, radius, wavePaint);
    
            canvas.drawBitmap(roundBitmap, 0, 0, wavePaint);
    
            //初始化shader
            linearGradient = new LinearGradient(0, height, 0, -height, new int[]{waveColor, Color.TRANSPARENT}, null, Shader.TileMode.CLAMP);
        }
    
        private void drawWave(Canvas canvas) {
            float ratio = 1 - progress / maxProgress;
    
            //水波纹Y坐标
            float waveY = height * ratio;
            wavePath.reset();
            wavePath.moveTo(0, waveY);
            wavePath.quadTo(centerX / 2, waveY + 20, centerX, waveY);
            wavePath.quadTo(centerX + (width - centerX) / 2, waveY - 20, width, waveY);
    
            wavePath.quadTo(centerX * 2 + (width - centerX) / 2, waveY + 20, centerX * 3, waveY);
            wavePath.quadTo(centerX * 3 + (width - centerX) / 2, waveY - 20, centerX * 4, waveY);
    
            //往下画,形成矩形
            wavePath.lineTo(centerX * 4, height);
            wavePath.lineTo(0, height);
            wavePath.lineTo(0, waveY);
    
            int layerCount = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, ALL_SAVE_FLAG);
            wavePaint.setColor(waveColor);
            canvas.drawBitmap(xfermodeDstBitmap, 0, 0, wavePaint);
            wavePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            wavePath.offset(offset, 0);
            wavePaint.setShader(linearGradient);
            canvas.drawPath(wavePath, wavePaint);
            wavePaint.setShader(null);
            wavePaint.setXfermode(null);
            canvas.restoreToCount(layerCount);
        }
    
        private void drawText(Canvas canvas) {
            Paint.FontMetrics m = new Paint.FontMetrics();
            textPaint.getFontMetrics(m);
            int baseLine = (int) (height / 2 - (m.top + m.bottom) / 2);
    
            String text = (int) (progress / maxProgress * 100) + "%";
            canvas.drawText(text, width / 2f - textPaint.measureText(text) / 2, baseLine, textPaint);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                setProgress(progress + 10);
            }
            return super.onTouchEvent(event);
        }
    
        public void setProgress(float progress) {
            this.progress = progress > maxProgress ? maxProgress : progress;
            postInvalidate();
        }
    
        public int dpToPx(Context context, int size) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (size * scale + 0.5f);
        }
    
    }
    
    去掉Xfermode的实际效果是这样的
    去掉Xfermode效果.gif
    项目地址:https://gitee.com/aruba/CanvasApplication.git

    相关文章

      网友评论

          本文标题:Android--水波纹进度条

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