美文网首页
自定义WaveProgressView满足你所有水波纹加载需求

自定义WaveProgressView满足你所有水波纹加载需求

作者: leo567 | 来源:发表于2018-05-19 13:02 被阅读114次

    先看效果图:

    1.gif

    你可以定义成你项目的logo图片,可以设置水波颜色、波长、波宽、字体大小、颜色、进度条的最大值,当前进度值,还可以设置波纹震动的快慢。当设置一个进度不变的时候,打开时还有一个动画填满的效果(比如第二个流量显示,这里图片没有截出这个效果)。

    源码地址

    1. 如何使用

    1.1 在布局文件中

    添加自定义控件:

    <cn.fanrunqi.waveprogressview.WaveProgressView
        android:id="@+id/waveProgressbar"
        android:background="@drawable/circle"
        <!--android:background="@drawable/bg_a"-->
        android:layout_width="130dp"
        android:layout_height="130dp" />
    

    说明,这里的android:background定义的是控件的形状,比如上面的圆形和美女,你可用shape.xml定义形状图片。

    比如,这是一个圆

    <?xml version="1.0" encoding="utf-8"?>
    <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">
        <solid android:color="#DDDDDD"/>
        <size android:width="150dp"
              android:height="150dp"/>
    </shape>
    

    也可以直接给android:background设置一张图片,比如:

    1.jpg

    这里注意透明像素,还有为了图片缩放的时候不变形,建议背景(不管是图片还是图形)为正方形

    1.2 在代码中

    你可以选择进行如下设置:

    //设置当前进度值和当前显示的文字
    waveProgressbar.setCurrent(int currentProgress,String currentText); // 77, "788M/1024M"
    //设置进度条的最大值
    waveProgressbar.setMaxProgress(int maxProgress);
    //设置显示文字的大小和颜色
    waveProgressbar.setText(String mTextColor,int mTextSize);//"#FFFF00", 41
    //设置水波的颜色
    waveProgressbar.setWaveColor(String mWaveColor); //"#5b9ef4"
    //设置波浪的高度和波浪的宽度(均为一个波峰的大小)
    waveProgressbar.setWave(float mWaveHight,float mWaveWidth);
    //设置波浪的上下震动的速度(这里注意值越大,震动的越小)
    waveProgressbar.setmWaveSpeed(int mWaveSpeed);//The larger the value, the slower the vibration
    

    2. 代码实现

    这里实现主要用到的知识有 自定义view、PorterDuffXfermode和二阶贝塞尔曲线,不太清楚的可以在我博客找找,都有的。   
      首先自定义WaveProgressView继承View,在构造函数中获取布局文件中设置的背景,同时设置一个画波浪的画笔和画文字的画笔。

    private void Init() {
            /**
             * 获得背景
             */
            if(null==getBackground()){
                throw new IllegalArgumentException(String.format("background is null."));
            }else{
                backgroundBitmap = getBitmapFromDrawable(getBackground());
            }
            /**
             * 波浪画笔
             */
            mPath = new Path();
            mPathPaint = new Paint();
            mPathPaint.setAntiAlias(true);
            mPathPaint.setStyle(Paint.Style.FILL);
            /**
             * 进度画笔
             */
            mTextPaint = new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setTextAlign(Paint.Align.CENTER);
         //开始不断自我绘制,让波浪动起来
            handler.sendEmptyMessageDelayed(INVALIDATE,100);
        }
    

    复写onDraw方法,先把波浪画在画布上,然后画背景(给背景画笔设置PorterDuff.Mode.DST_ATOP模式:取上层非交集部分与下层交集部分 )。当然也可以是PorterDuff.Mode.SRC_ATOP,主要取决于你画的先后顺序。最后把文字画上去,形成一个最终Bitmap,最后把这个Bitmap画到onDraw的参数canvas上。

     Paint paint = new Paint();
            paint.setAntiAlias(true);
            Bitmap finalBmp = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
            /**
             * 产生一个同样大小的画布
             */
            Canvas canvas = new Canvas(finalBmp);
            /**
             * 绘制波浪
             */
            float CurMidY = height*(maxProgress-currentProgress)/maxProgress;
            if(CurY>CurMidY){
                CurY = CurY - (CurY-CurMidY)/10;
            }
            mPath.reset();
            mPath.moveTo(0-distance,CurY);
    
            int waveNum = width/((int)mWaveHalfWidth*4)+1;
            int multiplier = 0;
            for(int i =0;i<waveNum;i++){
             mPath.quadTo(mWaveHalfWidth*(multiplier+1)-distance,CurY-mWaveHight,mWaveHalfWidth*(multiplier+2)-distance,CurY);
             mPath.quadTo(mWaveHalfWidth*(multiplier+3)-distance,CurY+mWaveHight,mWaveHalfWidth*(multiplier+4)-distance,CurY);
             multiplier+=4;
            }
            distance +=mWaveHalfWidth/mWaveSpeed;
            distance = distance%(mWaveHalfWidth*4);
    
            mPath.lineTo(width,height);
            mPath.lineTo(0,height);
            mPath.close();
            canvas.drawPath(mPath, mPathPaint);
            /**
             * 对图片给进行缩放
             */
            int min = Math.min(width,height);
            backgroundBitmap = Bitmap.createScaledBitmap(backgroundBitmap,min,min,false);
            /**
             * 使用DST_ATOP,取上层非交集部分与下层交集部分 。
             */
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
            /**
             * 绘制图片
             */
            canvas.drawBitmap(backgroundBitmap,0,0,paint);
            /**
             * 绘制进度文字
             */
            canvas.drawText(currentText, width/2, height/2, mTextPaint);
            return finalBmp;
    

    这里的CurY是上次波浪中线的y轴坐标,CurMidY 是当前的Y轴坐标,每次波浪上升的时候为了不产生卡顿效果,把这1/100的上升分为10次来绘制。
      distance是x轴的偏移量,为了使水波动起来,每次绘制时都要向左进行一段偏移。

    distance +=mWaveHalfWidth/mWaveSpeed;
    distance = distance%(mWaveHalfWidth*4);
    

    每次偏移距离为 半波宽度/波浪震动速度,因为一个波是4个半波宽度形成一个循环,然后又回到最开始x位置开始循环位移。
      根据view的宽度计算出一共要绘制多少个波形出来,同时多加一个波为了向左平移。

    int waveNum = width/((int)mWaveHalfWidth*4)+1;
     int multiplier = 0;
        for(int i =0;i<waveNum;i++){
             mPath.quadTo(mWaveHalfWidth*(multiplier+1)-distance,CurY-mWaveHight,mWaveHalfWidth*(multiplier+2)-distance,CurY);
             mPath.quadTo(mWaveHalfWidth*(multiplier+3)-distance,CurY+mWaveHight,mWaveHalfWidth*(multiplier+4)-distance,CurY);
             multiplier+=4;
            }
    

    每次绘制以波形的左边点、波形的右边点、view的左下角、view的右下角、形成一个图片把它绘制到内存中新建的和view同大小的canvas上。

    mPath.reset();
    mPath.moveTo(0-distance,CurY);
    
    mPath.lineTo(width,height);
    mPath.lineTo(0,height);
    mPath.close();
    canvas.drawPath(mPath, mPathPaint);
    

    先对背景图形进行缩放再绘制到canvas上,这里的缩放是按最小边进行缩放。

    int min = Math.min(width,height);
    backgroundBitmap = Bitmap.createScaledBitmap(backgroundBitmap,min,min,false);
    

    最后把文字绘制上去,注意我们在初始化中设置了画笔,为了能通过代码设置文字的颜色,要把设置文字画笔颜色和大小放在onDraw方法中。

     mPathPaint.setColor(Color.parseColor(mWaveColor));
     mTextPaint.setColor(Color.parseColor(mTextColor));
     mTextPaint.setTextSize(mTextSize);
    
    canvas.drawText(currentText, width/2, height/2, mTextPaint);
    

    为了使波浪动起来,使用handler循环调用invalidate刷新界面。同时应该在构造函数打开handler循环。

    private static final int INVALIDATE = 0X777;
        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case INVALIDATE:
                        invalidate();
                        sendEmptyMessageDelayed(INVALIDATE,RefreshGap);
                        break;
                }
            }
        };
    

    最后就是一些相关属性设置的函数。

     /**
         * @param currentProgress  当前进度
         * @param currentText  当前显示的进度文字
         */
        public void setCurrent(int currentProgress,String currentText) {
            this.currentProgress = currentProgress;
            this.currentText = currentText;
        }
    
        /**
         * @param maxProgress 设置进度条的最大值,默认100
         */
        public void setMaxProgress(int maxProgress){
            this.maxProgress = maxProgress;
        }
    
        /**
         * @param mTextColor 文字的颜色
         * @param mTextSize 文字的大小
         */
        public void setText(String mTextColor,int mTextSize){
            this.mTextColor = mTextColor;
            this.mTextSize = mTextSize;
        }
        /**
         * @param mWaveHight  波峰的高度
         * @param mWaveWidth  一个波峰的宽度
         */
        public void setWave(float mWaveHight,float mWaveWidth){
            this.mWaveHight = mWaveHight;
            this.mWaveHalfWidth = mWaveWidth/2;
        }
    
        /**
         * @param mWaveColor 水的颜色
         */
        public void setWaveColor(String mWaveColor){
            this.mWaveColor = mWaveColor;
        }
        /**
         * 值越大震荡的越慢
         * @param mWaveSpeed
         */
        public void setmWaveSpeed(int mWaveSpeed){
          this.mWaveSpeed = mWaveSpeed;
        }
    

    实现还是比较简单的,源码和demo都在上面的地址中,如果有什么问题可以给我留言,谢谢!

    相关文章

      网友评论

          本文标题:自定义WaveProgressView满足你所有水波纹加载需求

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