自定义view实现水波纹效果

今天看到一篇自定view 实现水波纹效果 觉得真心不错 学习之后再次写下笔记和心得.但是感觉原作者写得有些晦涩难懂,也许是本人愚笨 所以重写此作者教程.原作者博文大家可以去看下,感觉他在自定义view方面非常厉害,本文是基于此作者原文重新改写,拥有大量像相似部分

先看下效果吧:

1. 效果1:

2. 效果2


我先们来学习效果1:

效果1实现本质:用一张波形图和一个圆形图的图片,然后圆形图在波形图上方,然后使用安卓的图片遮罩模式desIn(不懂?那么先记住有这样一个遮罩模式).(只显示上部图像和下部图像公共部分的下半部分),是不是很难懂?那么我在说清一点并且配图.假设圆形图在波形图上面,那么只会显示两者相交部分的波形图

下面是解释效果图(正方形蓝色图片在黄色圆形上面):

学习此模式具体地址学习安卓图片遮罩模式

所用到波形图:

所用到圆形图:

这次的实现我们都选择继承view,在实现的过程中我们需要关注如下几个方法:

1.onMeasure():最先回调,用于控件的测量;

2.onSizeChanged():在onMeasure后面回调,可以拿到view的宽高等数据,在横竖屏切换时也会回调;

3.onDraw():真正的绘制部分,绘制的代码都写到这里面;

先来看看我们定义的变量:


    //波形图
    Bitmap waveBitmap;

    //圆形遮罩图
    Bitmap circleBitmap;

    //波形图src
    Rect waveSrcRect;
    //波形图dst
    Rect waveDstRect;

    //圆形遮罩src
    Rect circleSrcRect;

    //圆形遮罩dst
    Rect circleDstRect;

    //画笔
    Paint mpaint;

    //图片遮罩模式
    PorterDuffXfermode mode;

    //控件的宽
    int viewWidth;
    //控件的高
    int viewHeight;

    //图片过滤器
    PaintFlagsDrawFilter paintFlagsDrawFilter ;

    //每次移动的距离
    int speek = 10 ;

    //当前移动距离
    int nowOffSet;

介绍一个方法:

 void android.graphics.Canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

此方法的参数:

参数1:你的图片

参数2:矩形 .也就是说此矩形决定你画出图片参数1 的哪个位置,比如说你的矩形是设定是Rect rect= new Rect(0,0,图片宽,图片高) 那么将会画出图片全部

参数3:矩形.决定你图片缩放比例和在view中的位置.假设你的矩形Rect rect= new Rect(0,0,100,100) 那么你将在自定义view中(0,0)点到(100,100)绘画此图片并且如果图片大于(小于)此矩形那么按比例缩小(放大)

来看看 初始化方法

//初始化
    private void init() {

        mpaint = new Paint();
        //处理图片抖动
        mpaint.setDither(true);
        //抗锯齿
        mpaint.setAntiAlias(true);
        //设置图片过滤波
        mpaint.setFilterBitmap(true);
        //设置图片遮罩模式
        mode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);

        //给画布直接设定参数
        paintFlagsDrawFilter = new PaintFlagsDrawFilter(0, Paint.DITHER_FLAG|Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);

        //初始化图片
        //使用drawable获取的方式,全局只会生成一份,并且系统会进行管理,
        //而BitmapFactory.decode()出来的则decode多少次生成多少张,务必自己进行recycle;

        //获取波形图
        waveBitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.wave_2000)).getBitmap();

        //获取圆形遮罩图
        circleBitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.circle_500)).getBitmap();

        //不断刷新波形图距离 读者可以先不看这部分内容  因为需要结合其他方法
        new Thread(){
            public void run() {
                while (true) {
                    try {
                        //移动波形图
                        nowOffSet=nowOffSet+speek;
                        //如果移动波形图的末尾那么重新来
                        if (nowOffSet>=waveBitmap.getWidth()) {
                            nowOffSet=0;
                        }
                        sleep(30);
                        postInvalidate();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

            };
        }.start();

    }

以下获取view的宽高并设置对应的波形图和圆形图矩形(会在onMesure回调后执行)

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //获取view宽高
        viewWidth = w;
        viewHeight = h ;

        //波形图的矩阵初始化
        waveSrcRect = new Rect();
        waveDstRect = new Rect(0,0,w,h);

        //圆球矩阵初始化
        circleSrcRect = new Rect(0,0,circleBitmap.getWidth(),circleBitmap.getHeight());

        circleDstRect = new Rect(0,0,viewWidth,viewHeight);

    }

那么最后来看看绘画部分吧

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //给图片直接设置过滤效果
        canvas.setDrawFilter(paintFlagsDrawFilter);
        //给图片上色
        canvas.drawColor(Color.TRANSPARENT);
        //添加图层 注意!!!!!使用图片遮罩模式会影响全部此图层(也就是说在canvas.restoreToCount 所有图都会受到影响)
        int saveLayer = canvas.saveLayer(0,0, viewWidth,viewHeight,null, Canvas.ALL_SAVE_FLAG);
        //画波形图部分 矩形
        waveSrcRect.set(nowOffSet, 0, nowOffSet+viewWidth/2, viewHeight);
        //画矩形
        canvas.drawBitmap(waveBitmap,waveSrcRect,waveDstRect,mpaint);
        //设置图片遮罩模式
        mpaint.setXfermode(mode);
        //画遮罩
        canvas.drawBitmap(circleBitmap, circleSrcRect, circleDstRect,mpaint);
        //还原画笔模式
        mpaint.setXfermode(null);
        //将图层放上
        canvas.restoreToCount(saveLayer);
    }

最后看下完整的代码

package com.fmy.shuibo1;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.icu.text.TimeZoneFormat.ParseOption;
import android.util.AttributeSet;
import android.view.View;

public class MySinUi extends View{

    //波形图
    Bitmap waveBitmap;

    //圆形遮罩图
    Bitmap circleBitmap;

    //波形图src
    Rect waveSrcRect;
    //波形图dst
    Rect waveDstRect;

    //圆形遮罩src
    Rect circleSrcRect;

    //圆形遮罩dst
    Rect circleDstRect;

    //画笔
    Paint mpaint;

    //图片遮罩模式
    PorterDuffXfermode mode;

    //控件的宽
    int viewWidth;
    //控件的高
    int viewHeight;

    //图片过滤器
    PaintFlagsDrawFilter paintFlagsDrawFilter ;

    //每次移动的距离
    int speek = 10 ;

    //当前移动距离
    int nowOffSet;

    public MySinUi(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();

    }

    //初始化
    private void init() {

        mpaint = new Paint();
        //处理图片抖动
        mpaint.setDither(true);
        //抗锯齿
        mpaint.setAntiAlias(true);
        //设置图片过滤波
        mpaint.setFilterBitmap(true);
        //设置图片遮罩模式
        mode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);

        //给画布直接设定参数
        paintFlagsDrawFilter = new PaintFlagsDrawFilter(0, Paint.DITHER_FLAG|Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);

        //初始化图片
        //使用drawable获取的方式,全局只会生成一份,并且系统会进行管理,
        //而BitmapFactory.decode()出来的则decode多少次生成多少张,务必自己进行recycle;

        //获取波形图
        waveBitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.wave_2000)).getBitmap();

        //获取圆形遮罩图
        circleBitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.circle_500)).getBitmap();

        //不断刷新波形图距离 读者可以先不看这部分内容  因为需要结合其他方法
        new Thread(){
            public void run() {
                while (true) {
                    try {
                        //移动波形图
                        nowOffSet=nowOffSet+speek;
                        //如果移动波形图的末尾那么重新来
                        if (nowOffSet>=waveBitmap.getWidth()) {
                            nowOffSet=0;
                        }
                        sleep(30);
                        postInvalidate();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

            };
        }.start();

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //给图片直接设置过滤效果
        canvas.setDrawFilter(paintFlagsDrawFilter);
        //给图片上色
        canvas.drawColor(Color.TRANSPARENT);
        //添加图层 注意!!!!!使用图片遮罩模式会影响全部此图层(也就是说在canvas.restoreToCount 所有图都会受到影响)
        int saveLayer = canvas.saveLayer(0,0, viewWidth,viewHeight,null, Canvas.ALL_SAVE_FLAG);
        //画波形图部分 矩形
        waveSrcRect.set(nowOffSet, 0, nowOffSet+viewWidth/2, viewHeight);
        //画矩形
        canvas.drawBitmap(waveBitmap,waveSrcRect,waveDstRect,mpaint);
        //设置图片遮罩模式
        mpaint.setXfermode(mode);
        //画遮罩
        canvas.drawBitmap(circleBitmap, circleSrcRect, circleDstRect,mpaint);
        //还原画笔模式
        mpaint.setXfermode(null);
        //将图层放上
        canvas.restoreToCount(saveLayer);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //获取view宽高
        viewWidth = w;
        viewHeight = h ;

        //波形图的矩阵初始化
        waveSrcRect = new Rect();
        waveDstRect = new Rect(0,0,w,h);

        //圆球矩阵初始化
        circleSrcRect = new Rect(0,0,circleBitmap.getWidth(),circleBitmap.getHeight());

        circleDstRect = new Rect(0,0,viewWidth,viewHeight);

    }
}

学习效果2:

此方法实现原理:运用三角函数画出两个不同速率正弦函数图

我们先来复习三角函数吧

正余弦函数方程为:

y = Asin(wx+b)+h ,这个公式里:w影响周期,A影响振幅,h影响y位置,b为初相;

w:周期就是一个完整正弦曲线图此数值越大sin的周期越小 (cos越大)

如下图:

(原作者说我们画一个以自定义view的宽度为周期的图:意思是说你view的宽度正好可以画一个上面的图.)

A:振幅两个山峰最大的高度.如果A越大两个山峰越高和越低

h:你正弦曲线和y轴相交点.(影响正弦图初始高度的位置)

b:初相会让你图片向x轴平移

具体大家可以百度学习,我们在学编程,不是数学



为什么要两个正弦图画?好看…..

先来看看变量:

// 波纹颜色
    private static final int WAVE_PAINT_COLOR = 0x880000aa;

    // 第一个波纹移动的速度
    private int oneSeep = 7;

    // 第二个波纹移动的速度
    private int twoSeep = 10;

    // 第一个波纹移动速度的像素值
    private int oneSeepPxil;
    // 第二个波纹移动速度的像素值
    private int twoSeepPxil;

    // 存放原始波纹的每个y坐标点
    private float wave[];

    // 存放第一个波纹的每一个y坐标点
    private float oneWave[];

    // 存放第二个波纹的每一个y坐标点
    private float twoWave[];

    // 第一个波纹当前移动的距离
    private int oneNowOffSet;
    // 第二个波纹当前移动的
    private int twoNowOffSet;

    // 振幅高度
    private int amplitude = 20;

    // 画笔
    private Paint mPaint;

    // 创建画布过滤
    private DrawFilter mDrawFilter;

    // view的宽度
    private int viewWidth;

    // view高度
    private int viewHeight;

画初始的波形图并且保存到数组中

// 大小改变
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 获取view的宽高
        viewHeight = h;
        viewWidth = w;

        // 初始化保存波形图的数组
        wave = new float[w];
        oneWave = new float[w];
        twoWave = new float[w];

        // 设置波形图周期
        float zq = (float) (Math.PI * 2 / w);

        // 设置波形图的周期
        for (int i = 0; i < viewWidth; i++) {
            wave[i] = (float) (amplitude * Math.sin(zq * i));
        }

    }

初始化各种

// 初始化
    private void init() {
        // 创建画笔
        mPaint = new Paint();
        // 设置画笔颜色
        mPaint.setColor(WAVE_PAINT_COLOR);
        // 设置绘画风格为实线
        mPaint.setStyle(Style.FILL);
        // 抗锯齿
        mPaint.setAntiAlias(true);
        // 设置图片过滤波和抗锯齿
        mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

        // 第一个波的像素移动值 换算成手机像素值让其在各个手机移动速度差不多
        oneSeepPxil = dpChangPx(oneSeep);

        // 第二个波的像素移动值
        twoSeepPxil = dpChangPx(twoSeep);
    }
// 绘画方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.setDrawFilter(mDrawFilter);

        oneNowOffSet =oneNowOffSet+oneSeepPxil;

        twoNowOffSet = twoNowOffSet+twoSeepPxil;

        if (oneNowOffSet>=viewWidth) {
            oneNowOffSet = 0;
        }
        if (twoNowOffSet>=viewWidth) {
            twoNowOffSet = 0;
        }
        //此方法会让两个保存波形图的 数组更新 头到NowOffSet变成尾部,尾部的变成头部实现动态移动
        reSet();

        Log.e("fmy", Arrays.toString(twoWave));

        for (int i = 0; i < viewWidth; i++) {

            canvas.drawLine(i, viewHeight, i, viewHeight-400-oneWave[i], mPaint);
            canvas.drawLine(i, viewHeight, i, viewHeight-400-twoWave[i], mPaint);
        }

        postInvalidate();
    }

来看看能让两个数组重置的


    public void reSet() {
        // one是指 走到此处的波纹的位置 (这个理解方法看个人了)
        int one = viewWidth - oneNowOffSet;
        // 把未走过的波纹放到最前面 进行重新拼接
        System.arraycopy(wave, oneNowOffSet, oneWave, 0, one);
        // 把已走波纹放到最后
        System.arraycopy(wave, 0, oneWave, one, oneNowOffSet);

        // one是指 走到此处的波纹的位置 (这个理解方法看个人了)
        int two = viewWidth - twoNowOffSet;
        // 把未走过的波纹放到最前面 进行重新拼接
        System.arraycopy(wave, twoNowOffSet, twoWave, 0, two);
        // 把已走波纹放到最后
        System.arraycopy(wave, 0, twoWave, two, twoNowOffSet);

    }

最后大家看下完整代码

package com.exam1ple.myshuibo2;

import java.util.Arrays;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DrawFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.icu.text.TimeZoneFormat.ParseOption;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;

public class MyUi2 extends View {

    // 波纹颜色
    private static final int WAVE_PAINT_COLOR = 0x880000aa;

    // 第一个波纹移动的速度
    private int oneSeep = 7;

    // 第二个波纹移动的速度
    private int twoSeep = 10;

    // 第一个波纹移动速度的像素值
    private int oneSeepPxil;
    // 第二个波纹移动速度的像素值
    private int twoSeepPxil;

    // 存放原始波纹的每个y坐标点
    private float wave[];

    // 存放第一个波纹的每一个y坐标点
    private float oneWave[];

    // 存放第二个波纹的每一个y坐标点
    private float twoWave[];

    // 第一个波纹当前移动的距离
    private int oneNowOffSet;
    // 第二个波纹当前移动的
    private int twoNowOffSet;

    // 振幅高度
    private int amplitude = 20;

    // 画笔
    private Paint mPaint;

    // 创建画布过滤
    private DrawFilter mDrawFilter;

    // view的宽度
    private int viewWidth;

    // view高度
    private int viewHeight;

    // xml布局构造方法
    public MyUi2(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    // 初始化
    private void init() {
        // 创建画笔
        mPaint = new Paint();
        // 设置画笔颜色
        mPaint.setColor(WAVE_PAINT_COLOR);
        // 设置绘画风格为实线
        mPaint.setStyle(Style.FILL);
        // 抗锯齿
        mPaint.setAntiAlias(true);
        // 设置图片过滤波和抗锯齿
        mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

        // 第一个波的像素移动值 换算成手机像素值让其在各个手机移动速度差不多
        oneSeepPxil = dpChangPx(oneSeep);

        // 第二个波的像素移动值
        twoSeepPxil = dpChangPx(twoSeep);
    }

    // 绘画方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.setDrawFilter(mDrawFilter);

        oneNowOffSet =oneNowOffSet+oneSeepPxil;

        twoNowOffSet = twoNowOffSet+twoSeepPxil;

        if (oneNowOffSet>=viewWidth) {
            oneNowOffSet = 0;
        }
        if (twoNowOffSet>=viewWidth) {
            twoNowOffSet = 0;
        }
        reSet();

        Log.e("fmy", Arrays.toString(twoWave));

        for (int i = 0; i < viewWidth; i++) {

            canvas.drawLine(i, viewHeight, i, viewHeight-400-oneWave[i], mPaint);
            canvas.drawLine(i, viewHeight, i, viewHeight-400-twoWave[i], mPaint);
        }

        postInvalidate();
    }

    public void reSet() {
        // one是指 走到此处的波纹的位置 (这个理解方法看个人了)
        int one = viewWidth - oneNowOffSet;
        // 把未走过的波纹放到最前面 进行重新拼接
        System.arraycopy(wave, oneNowOffSet, oneWave, 0, one);
        // 把已走波纹放到最后
        System.arraycopy(wave, 0, oneWave, one, oneNowOffSet);

        // one是指 走到此处的波纹的位置 (这个理解方法看个人了)
        int two = viewWidth - twoNowOffSet;
        // 把未走过的波纹放到最前面 进行重新拼接
        System.arraycopy(wave, twoNowOffSet, twoWave, 0, two);
        // 把已走波纹放到最后
        System.arraycopy(wave, 0, twoWave, two, twoNowOffSet);

    }

    // 大小改变
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 获取view的宽高
        viewHeight = h;
        viewWidth = w;

        // 初始化保存波形图的数组
        wave = new float[w];
        oneWave = new float[w];
        twoWave = new float[w];

        // 设置波形图周期
        float zq = (float) (Math.PI * 2 / w);

        // 设置波形图的周期
        for (int i = 0; i < viewWidth; i++) {
            wave[i] = (float) (amplitude * Math.sin(zq * i));
        }

    }

    // dp换算成px 为了让移动速度在各个分辨率的手机的都差不多
    public int dpChangPx(int dp) {
        DisplayMetrics metrics = new DisplayMetrics();
        ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);
        return (int) (metrics.density * dp + 0.5f);
    }

}

以上源代码:`

源码奉上各位

时间: 2024-10-30 21:23:58

自定义view实现水波纹效果的相关文章

Android 自定义view实现水波纹效果

http://blog.csdn.net/tianjian4592/article/details/44222565 在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了,可千万别说不行,爷们儿怎么能说不行呢: 好了,为了让大家都能给妹纸们想要的,后面会逐渐分享一些比较比较不错的效果,目的只有一个,通过自定义view实现我们所能实现的动效: 今天主要分

Android自定义View——实现水波纹效果类似剩余流量球

最近突然手痒就想搞个贝塞尔曲线做个水波纹效果玩玩,终于功夫不负有心人最后实现了想要的效果,一起来看下吧: 效果图镇楼 一:先一步一步来分解一下实现的过程 需要绘制一个正弦曲线(sin)或者余弦曲线(cos) 通过水平平移曲线来的到像水波波动的效果 水平移动的同时还需要有水位上涨,也就是向上平移 裁剪画布为圆形,在圆形区域绘制曲线 通过上面4步就可以实现了 二:现在就来实现第一步,绘制一个sin曲线:这里画了一张图来帮助理解,在PhotoShop中我们绘制一个贝塞尔曲线可以清楚的看到它的控制点如图

[转]Android自定义控件系列五:自定义绚丽水波纹效果

出处:http://www.2cto.com/kf/201411/353169.html 今天我们来利用Android自定义控件实现一个比较有趣的效果:滑动水波纹.先来看看最终效果图: 图一 效果还是很炫的:饭要一口口吃,路要一步步走,这里我们将整个过程分成几步来实现 一.实现单击出现水波纹单圈效果: 图二 照例来说,还是一个自定义控件,这里我们直接让这个控件撑满整个屏幕(对自定义控件不熟悉的可以参看我之前的一篇文章:Android自定义控件系列二:自定义开关按钮(一)).观察这个效果,发现应该

Android自定义控件系列五:自定义绚丽水波纹效果

尊重原创!转载请注明出处:http://blog.csdn.net/cyp331203/article/details/41114551 今天我们来利用Android自定义控件实现一个比较有趣的效果:滑动水波纹.先来看看最终效果图: 图一 效果还是很炫的:饭要一口口吃,路要一步步走,这里我们将整个过程分成几步来实现 一.实现单击出现水波纹单圈效果: 图二 照例来说,还是一个自定义控件,这里我们直接让这个控件撑满整个屏幕(对自定义控件不熟悉的可以参看我之前的一篇文章:Android自定义控件系列二

自定义控件三部曲之绘图篇(六)——Path之贝赛尔曲线和手势轨迹、水波纹效果

前言:好想义无反顾地追逐梦想 相关文章:<Android自定义控件三部曲文章索引> 从这篇开始,我将延续androidGraphics系列文章把图片相关的知识给大家讲完,这一篇先稍微进阶一下,给大家把<android Graphics(二):路径及文字>略去的quadTo(二阶贝塞尔)函数,给大家补充一下. 本篇最终将以两个例子给大家演示贝塞尔曲线的强大用途: 1.手势轨迹 利用贝塞尔曲线,我们能实现平滑的手势轨迹效果 2.水波纹效果 电池充电时,有些手机会显示水波纹效果,就是这样

Android Ripple 按钮水波纹效果(二)优化

上一篇中我们讲了自定义ripple 水波纹效果,先来回顾一下效果吧! 看了以后感觉没甚么问题,我一开始也觉得很满意了,那好,我们拿Android 5.0自带的效果来对比一下 发现了不同之处没?点击中间的时候是看不出什么区别,但是点击两边的时候,就很明显了,我们自定义的效果,波纹向两边同速度的扩散,所以就会出现,如果点击点不在中心的时候,距离短的一边波纹先到达,而距离长的一边后到达,不能同时到达边缘!而系统自带的则不存在这种情况,所以这是一个优化点;另一个优化点是:我们自定义的效果,在波纹全部覆盖

Android自定义控件-Path之贝赛尔曲线和手势轨迹、水波纹效果

从这篇开始,我将延续androidGraphics系列文章把图片相关的知识给大家讲完,这一篇先稍微进阶一下,给大家把<android Graphics(二):路径及文字>略去的quadTo(二阶贝塞尔)函数,给大家补充一下. 本篇最终将以两个例子给大家演示贝塞尔曲线的强大用途: 1.手势轨迹 利用贝塞尔曲线,我们能实现平滑的手势轨迹效果 2.水波纹效果 电池充电时,有些手机会显示水波纹效果,就是这样做出来的. 废话不多说,开整吧 一.概述 在<android Graphics(二):路径

浅谈实现点击出现水波纹效果

在项目中想着在点击控件的同时实现一种最近流行的水波纹效果(其实用安卓5.0的直接就有了). 其实步骤很简单: 1.自定义view,继承LinearLayout, public class RevealLayout extends LinearLayout implements Runnable { private static final String TAG = "DxRevealLayout"; private static final boolean DEBUG = true;

css 滚动视差 之 水波纹效果

核心属性: background-attachment 这个属性就牛逼了, 它可以定义背景图片是相对视口固定, 还是随着视口滚动, 加上这个属性网页瞬间就从屌丝变成 高大上. 我们来看个例子: html: <div class="attach view"></div> <div class="text view">I WANT FLY</div> <div class="attach view"