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

请尊重个人劳动成果,转载注明出处,谢谢!

http://blog.csdn.net/amazing7/article/details/51855165

先看效果图:

  你可以定义成你项目的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.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*3;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*3;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都在上面的地址中,如果有什么问题可以给我留言,谢谢!

  

时间: 2024-11-05 11:52:22

自定义WaveProgressView满足你所有水波纹加载需求的相关文章

三角函数之美-水波纹加载LoadingView

一.前言 学习是要总结的,最近几天学习了绘图相关的,但是使用的机会较少,现在又快要遗忘了,这次看了水波纹的绘制,觉得十分有意思,还是 把实现的方法记录下来.技术无他,为手熟尔,还是要多练习,空淡误国,实干兴邦,让我们看看今天的三角函数之美吧. 二.概述 肯定大家对中学学习的三角函数都不陌生吧,不过学习的sin.cos是超越函数一类函数,是初等函数的一种,借用维基百科的一张图: 一个完整的正弦函数应该是这样的:>y=Asin(ωx+φ)+h,A决定峰值,ω决定周期,φ表示初相位,h表示y轴的位置.

【Android自定义View实战】之仿百度加载动画,一种优雅的Loading方式

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53470872 本文出自[DylanAndroid的博客] Android自定义View实战之仿百度加载动画一种优雅的Loading方式 第一个仿百度加载动画用ObjectAnimator属性动画操作ImageView的属性方法实现 第二个仿百度加载动画第二种实现方式用ValueAnimator原生的ondraw方法实现 第三个扔球动画-水平旋转动画 第四个扔球动画-垂直旋转动

Android 自定义 ListView 上下拉动&ldquo;刷新最新&rdquo;和&ldquo;加载更多&rdquo;歌曲列表

本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码太多,点击此处下载,自己调试一下. 下载 Demo 环境 Windows 2008 R2 64 位 Eclipse ADT V22.6.2,Android 4.4.3 SAMSUNG GT-I9008L,Android OS 2.2.2 测试数据 本演示的歌曲信息,共有 20 条,包括歌手名.歌曲名.时长.缩

自定义(下拉刷新、上拉加载)帧动画

前些天搞了个系统的下拉刷新跟上拉加载,由于效果一般所以才会有了今天这篇博文 对于大多数的码农来说,能弄出些自己感兴趣的好东西还是比较开心的.-- package com.example.administrator.xlistview; import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.util.AttributeSet; import android

自定义ListView_下拉刷新上拉加载更多

自定义ListView实现下拉刷新和上拉自动加载 效果图: 下拉效果: 上拉效果: 实现原理:通过ListView的addFooter与addHeader方法,将下拉布局与上拉布局添加到ListView中,再通过设置padding属性,隐藏头部和脚部 监听onTouchEvent事件,根据手势滑动距离,动态更改下拉布局的padding,并动态更改头布局内控件效果 监听onScrollStateChanged,动态显示隐藏脚布局 设置回调,提供下拉刷新与加载更多的方法 PullListView.j

自定义RecyclerView实现下拉刷新,加载更多

RecyclerView出来的时间已经不短了,现在估计大部分的列表类的需求实现首选肯定是RecyclerView,基本上可以跟ListView说再见了.那么问题来了,一般情况下一个列表页面都会有下拉刷新和加载更多功能,RecyclerView本身并没有下拉刷新和加载更多功能,当然现在已经有很多优秀的开源的支持下拉刷新,加载更多功能的三方RecyclerView,可以直接拿过来用.但是...有时候光会用是不够的,还需要知道它们是这么实现的,实现的原理是什么.下面就来介绍一下RecyclerView

JVM自定义类加载器加载指定classPath下的所有class及jar

一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责JAVA_HOME/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作. 2.其他类加载器:由java实现,可以在方法区找到其Class对象.这里又细分为几个加载器 a).扩展类加载器(Extension ClassLoader):负责用于加载JAVA_HOM

深入解析 composer 的自动加载原理 (转)

深入解析 composer 的自动加载原理 转自:https://segmentfault.com/a/1190000014948542 前言 PHP 自5.3的版本之后,已经重焕新生,命名空间.性状(trait).闭包.接口.PSR 规范.以及 composer 的出现已经让 PHP 变成了一门现代化的脚本语言.PHP 的生态系统也一直在演进,而 composer 的出现更是彻底的改变了以往构建 PHP 应用的方式,我们可以根据 PHP 的应用需求混合搭配最合适的 PHP 组件.当然这也得益于

jvm系列(一):java类的加载机制

java类的加载机制 原文:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构.类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口. 类加载器并不需要等到某个