自定义流动的多波纹控件

1,安卓端的效果

2,在xml中的引用

<*****.WaveView.DoubleWaveView
    android:id="@+id/waveView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    DoubleWaveView:speedOne="8"
    DoubleWaveView:speedTwo="6"
    DoubleWaveView:speedTHREE="3"
    DoubleWaveView:speedFOUR="9"
    DoubleWaveView:peakValue="20dp"
    DoubleWaveView:waveHeight="@dimen/x40"
    DoubleWaveView:waveColor="@color/waveViewwhite"/>
对应的属性介绍:
peakValue 振幅 ,即对应的是A
waveHeight 波浪距离控件底部的高度。
speedOne 第一条波浪的移动速度
speedTwo 第二条波浪的移动速度
speedTHREE 第3条波浪的移动速度
speedFOUR 第4条波浪的移动速度
waveColor 水波的颜色

3,attrs下的属性

<attr name="peakValue" format="dimension"/>
<attr name="waveColor" format="color" />
<attr name="speedOne" format="integer" />
<attr name="speedTwo" format="integer" />
<attr name="speedTHREE" format="integer" />
<attr name="speedFOUR" format="integer" />
<attr name="waveHeight" format="dimension" />

<declare-styleable name="DoubleWaveView">
    <attr name="peakValue" />
    <attr name="waveColor" />
    <attr name="speedOne" />
    <attr name="speedTHREE" />
    <attr name="speedTwo" />
    <attr name="speedFOUR"></attr>
    <attr name="waveHeight" />

</declare-styleable>

4,activity中的引用

DoubleWaveView myBeiSaiErView = (DoubleWaveView)view.findViewById(R.id.waveView);
myBeiSaiErView.setAnim(true); //true 开启波动,false关闭

 

工具类

public class DoubleWaveView extends View {

    // y = A*sin(wx+b)+h

    private static  int WAVE_PAINT_COLOR = 0x881E90FF;//波纹颜色 半透明,以实现叠层效果
    private static  int STRETCH_FACTOR_A;//震幅(控制波浪高度)
    private static  int OFFSET_Y = 0;//正弦函数的Y偏移量

    private static  int WaveHeight = 0;//波浪高度(Y轴方向)
    private static  int TRANSLATE_X_SPEED_ONE ;    // 第一条水波的移动速度 单位dp
    private static  int TRANSLATE_X_SPEED_TWO ;    // 第二条水波的移动速度 单位dp
    private static  int TRANSLATE_X_SPEED_THREE;    // 第3条水波的移动速度 单位dp
    private static  int TRANSLATE_X_SPEED_FOUR; // 第4条水波的移动速度 单位dp


    private int mXOffsetSpeedOne;//单位 PX
    private int mXOffsetSpeedTwo;//单位 PX
    private int mXOffsetSpeedTHERR;//单位 PX
    private int mXOffsetSpeedFOUR;//单位 PX




    private float mCycleFactorW;//这里是指代表ω周期因素 最小正周期 T = 2π/|ω|
    private int mTotalWidth, mTotalHeight;//View 控件的宽高
    private float[] mYPositions;//原始波浪

    private int mXOneOffset;//第一条波浪的X轴 偏移量
    private int mXTwoOffset;//第二条波浪的X轴 偏移量
    private int mXThreeffset;//第3条波浪的X轴 偏移量
    private int mXFOURffset;//第4条波浪的X轴 偏移量



    private boolean isAnim = true; //控制是否停止平移动画,默认开启
    private Paint mWavePaint;//画笔
    private DrawFilter mDrawFilter;//过滤器 消除锯齿

    public DoubleWaveView(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public DoubleWaveView(Context context)
    {
        this(context, null);
    }

    public DoubleWaveView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        //获取自定义属性值
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DoubleWaveView, defStyle, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);

            if (attr == R.styleable.DoubleWaveView_peakValue) {//振幅默认是30dp
                STRETCH_FACTOR_A = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics()));

            } else if (attr == R.styleable.DoubleWaveView_waveColor) {
                WAVE_PAINT_COLOR = a.getColor(attr, 0x881E90FF);//默认是蓝色

            } else if (attr == R.styleable.DoubleWaveView_speedOne) {
                TRANSLATE_X_SPEED_ONE = a.getInteger(attr, 7);//默认是7//振幅默认是

            } else if (attr == R.styleable.DoubleWaveView_speedTwo) {
                TRANSLATE_X_SPEED_TWO = a.getInteger(attr, 10);//默认是5//振幅默认是

            } else if(attr == R.styleable.DoubleWaveView_speedTHREE){
                TRANSLATE_X_SPEED_THREE= a.getInteger(attr, 20);//默认是6//振幅默认是
            }else if(attr == R.styleable.DoubleWaveView_speedFOUR){
                TRANSLATE_X_SPEED_FOUR= a.getInteger(attr, 15);//默认是6//振幅默认是
            } else if (attr == R.styleable.DoubleWaveView_waveHeight) {
                WaveHeight = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics()));//默认100dp

            }
        }
        a.recycle();

        // 将dp转化为px,用于控制不同分辨率上移动速度基本一致
        mXOffsetSpeedOne = DensityUtil.dip2px(context, TRANSLATE_X_SPEED_ONE);
        mXOffsetSpeedTwo = DensityUtil.dip2px(context, TRANSLATE_X_SPEED_TWO);

        mXOffsetSpeedTHERR= DensityUtil.dip2px(context, TRANSLATE_X_SPEED_THREE);

        mXOffsetSpeedFOUR= DensityUtil.dip2px(context, TRANSLATE_X_SPEED_FOUR);

        // 初始绘制波纹的画笔
        mWavePaint = new Paint();
        // 去除画笔锯齿
        mWavePaint.setAntiAlias(true);
        // 设置风格为实线
        mWavePaint.setStyle(Paint.Style.FILL);
        // 设置画笔颜色
        mWavePaint.setColor(WAVE_PAINT_COLOR);
        mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //从canvas层面去除绘制时的锯齿
        canvas.setDrawFilter(mDrawFilter);
        for(int i=0,j=0,k=0,a=0,b=0;i<mTotalWidth;i++){

            if(i+mXOneOffset<mTotalWidth){//第一条波纹图形绘制
                canvas.drawLine(i,mTotalHeight-mYPositions[mXOneOffset+i]-WaveHeight,i,mTotalHeight,mWavePaint);
            }else {//大于周期值,则设置为j(与相位相关,已移动的X距离,最大值为一个周期,即控件的宽度)
                canvas.drawLine(i,mTotalHeight-mYPositions[j]-WaveHeight,i,mTotalHeight,mWavePaint);
                j++;
            }

            if(i+mXTwoOffset<mTotalWidth){//第二条波纹图形绘制
                canvas.drawLine(i,mTotalHeight-mYPositions[mXTwoOffset+i]-WaveHeight,i,mTotalHeight,mWavePaint);
            }else {//大于周期值,则设置为k(与相位相关,已移动的X距离)
                canvas.drawLine(i,mTotalHeight-mYPositions[k]-WaveHeight,i,mTotalHeight,mWavePaint);
                k++;
            }

            if(i+mXThreeffset<mTotalWidth){//第3条波纹图形绘制
                canvas.drawLine(i,mTotalHeight-mYPositions[mXThreeffset+i]-WaveHeight,i,mTotalHeight,mWavePaint);
            }else {//大于周期值,则设置为k(与相位相关,已移动的X距离)
                canvas.drawLine(i,mTotalHeight-mYPositions[a]-WaveHeight,i,mTotalHeight,mWavePaint);
                a++;
            }

            if(i+mXFOURffset<mTotalWidth){//第4条波纹图形绘制
                canvas.drawLine(i,mTotalHeight-mYPositions[mXFOURffset+i]-WaveHeight,i,mTotalHeight,mWavePaint);
            }else {//大于周期值,则设置为k(与相位相关,已移动的X距离)
                canvas.drawLine(i,mTotalHeight-mYPositions[b]-WaveHeight,i,mTotalHeight,mWavePaint);
                b++;
            }
        }

        // 改变两条波纹的移动点 +1
        mXOneOffset += mXOffsetSpeedOne;
        mXTwoOffset += mXOffsetSpeedTwo;
        mXThreeffset+=mXOffsetSpeedTHERR;
        mXFOURffset+=mXOffsetSpeedFOUR;

        // 如果已经移动到结尾处,则重头记录
        if (mXOneOffset >= mTotalWidth) {
            mXOneOffset = 0;
        }
        if (mXTwoOffset > mTotalWidth) {
            mXTwoOffset = 0;
        }
        if (mXThreeffset > mTotalWidth) {
            mXThreeffset = 0;
        }
        if (mXFOURffset > mTotalWidth) {
            mXFOURffset = 0;
        }

        // 引发view重绘,可以考虑延迟10-30ms重绘,空出时间绘制
        if (isAnim){
            new Thread(mRunnable).start();
        }
    }


    public void setAnim(Boolean isAnim){//是否启动动画
        if (!this.isAnim==isAnim){
            this.isAnim = isAnim;
            postInvalidate();
        }
    }

    private Runnable mRunnable = new Runnable() {

        @Override
        public void run() {
            {
                try {
                    //界面更新的频率,每20ms更新一次界面
                    Thread.sleep(20);
                    //通知系统更新界面,相当于调用了onDraw函数
                    postInvalidate();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 记录下控件设置的宽高
        mTotalWidth = w;
        mTotalHeight = h;
        // 一维数组, 用于保存原始波纹的y值
        mYPositions = new float[mTotalWidth];

        // 将Sin函数周期定为view总宽度, ω = 2π/T
        mCycleFactorW = (float) (2 * Math.PI / mTotalWidth);

        // 根据view总宽度得出所有对应的y值,即计算出正弦图形对应位置
        for (int i = 0; i < mTotalWidth; i++) {
            mYPositions[i] = (float) (STRETCH_FACTOR_A * Math.sin(mCycleFactorW * i) + OFFSET_Y);
        }
    }
}
public class DensityUtil {
    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }
}
该文章是在丶小嵩的基础上进行修改的,有记录一下,有需要的朋友可直接拿去用具体详情请参考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值