1、先上一波效果图,是会动的哈,我这里上传了一张静态图片,可设置波纹个数、波峰高度、透明度、颜色等等属性,看大家个人需求。图中是3条水波纹,使用方法特别简单,直接xml中调用就可以。接下来上代码

2、用到的类有:

3、调用方式:

4、实现步骤

第一步:创建  MultiWaveHeader  类

public class MultiWaveHeader extends ViewGroup {protected Path mPath;protected ShapeType mShape = ShapeType.Rect;protected Paint mPaint = new Paint();protected Matrix mMatrix = new Matrix();protected List<Wave> mltWave = new ArrayList<>();protected float mCornerRadius;protected int mWaveHeight;protected int mCloseColor;protected int mStartColor;protected int mGradientAngle;protected boolean mIsRunning;protected boolean mEnableFullScreen;protected float mVelocity;protected float mColorAlpha;protected float mProgress;protected float mCurProgress;protected long mLastTime = 0;protected ValueAnimator reboundAnimator;public MultiWaveHeader(Context context) {this(context, null, 0);}public MultiWaveHeader(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public MultiWaveHeader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mPaint.setAntiAlias(true);TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MultiWaveHeader);mWaveHeight = ta.getDimensionPixelOffset(R.styleable.MultiWaveHeader_mwhWaveHeight, Util.dp2px(50));mStartColor = ta.getColor(R.styleable.MultiWaveHeader_mwhStartColor, 0xFF056CD0);mCloseColor = ta.getColor(R.styleable.MultiWaveHeader_mwhCloseColor, 0xFF31AFFE);mColorAlpha = ta.getFloat(R.styleable.MultiWaveHeader_mwhColorAlpha, 0.45f);mVelocity = ta.getFloat(R.styleable.MultiWaveHeader_mwhVelocity, 1f);mGradientAngle = ta.getInt(R.styleable.MultiWaveHeader_mwhGradientAngle, 45);mIsRunning = ta.getBoolean(R.styleable.MultiWaveHeader_mwhIsRunning, true);mEnableFullScreen = ta.getBoolean(R.styleable.MultiWaveHeader_mwhEnableFullScreen, false);mCornerRadius = ta.getDimensionPixelOffset(R.styleable.MultiWaveHeader_mwhCornerRadius, Util.dp2px(25));mShape = ShapeType.values()[ta.getInt(R.styleable.MultiWaveHeader_mwhShape, mShape.ordinal())];mProgress = mCurProgress = ta.getFloat(R.styleable.MultiWaveHeader_mwhProgress, 1f);if (ta.hasValue(R.styleable.MultiWaveHeader_mwhWaves)) {setTag(ta.getString(R.styleable.MultiWaveHeader_mwhWaves));} else if (getTag() == null) {setTag("70,25,1.4,1.4,-26\n" +"100,5,1.4,1.2,15\n" +"420,0,1.15,1,-10\n" +"520,10,1.7,1.5,20\n" +"220,0,1,1,-15");}ta.recycle();}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {if (mltWave.isEmpty()) {updateWavePath();updateWavePath(r - l, b - t);}}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);updateShapePath();updateWavePath(w, h);updateLinearGradient(w, h);}@Overrideprotected void dispatchDraw(Canvas canvas) {super.dispatchDraw(canvas);if (mltWave.size() > 0) {if (mPath != null) {canvas.save();canvas.clipPath(mPath);}View thisView = this;int height = thisView.getHeight();long thisTime = System.currentTimeMillis();for (Wave wave : mltWave) {mMatrix.reset();canvas.save();if (mIsRunning && mLastTime > 0 && wave.velocity != 0) {float offsetX = (wave.offsetX - (wave.velocity * mVelocity * (thisTime - mLastTime) / 1000f));if (-wave.velocity > 0) {offsetX %= (float) wave.width / 2;} else {while (offsetX < 0) {offsetX += ((float) wave.width / 2);}}wave.offsetX = offsetX;mMatrix.setTranslate(offsetX, (1 - mCurProgress) * height);//wave.offsetX =canvas.translate(-offsetX, -wave.offsetY - (1 - mCurProgress) * height);} else {mMatrix.setTranslate(wave.offsetX, (1 - mCurProgress) * height);canvas.translate(-wave.offsetX, -wave.offsetY - (1 - mCurProgress) * height);}mPaint.getShader().setLocalMatrix(mMatrix);canvas.drawPath(wave.path, mPaint);canvas.restore();}mLastTime = thisTime;if (mPath != null) {canvas.restore();}if (mIsRunning) {invalidate();}}}private void updateLinearGradient(int width, int height) {int startColor = ColorUtils.setAlphaComponent(mStartColor, (int) (mColorAlpha * 255));int closeColor = ColorUtils.setAlphaComponent(mCloseColor, (int) (mColorAlpha * 255));//noinspection UnnecessaryLocalVariabledouble w = width;double h = height * mCurProgress;double r = Math.sqrt(w * w + h * h) / 2;double y = r * Math.sin(2 * Math.PI * mGradientAngle / 360);double x = r * Math.cos(2 * Math.PI * mGradientAngle / 360);mPaint.setShader(new LinearGradient((int) (w / 2 - x), (int) (h / 2 - y), (int) (w / 2 + x), (int) (h / 2 + y), startColor, closeColor, Shader.TileMode.CLAMP));}protected void updateShapePath() {View thisView = this;int w = thisView.getWidth();int h = thisView.getHeight();if (w > 0 && h > 0 && mShape != null && mShape != ShapeType.Rect) {mPath = new Path();switch (mShape) {case RoundRect:mPath.addRoundRect(new RectF(0, 0, w, h), mCornerRadius, mCornerRadius, Path.Direction.CW);break;case Oval:mPath.addOval(new RectF(0, 0, w, h), Path.Direction.CW);break;}} else {mPath = null;}}protected void updateWavePath() {mltWave.clear();if (getTag() instanceof String) {String[] waves = getTag().toString().split("\\s+");if ("-1".equals(getTag())) {waves = "70,25,1.4,1.4,-26\n100,5,1.4,1.2,15\n420,0,1.15,1,-10\n520,10,1.7,1.5,20\n220,0,1,1,-15".split("\\s+");} else if ("-2".equals(getTag())) {waves = "0,0,1,0.5,90\n90,0,1,0.5,90".split("\\s+");}for (String wave : waves) {String[] args = wave.split("\\s*,\\s*");if (args.length == 5) {mltWave.add(new Wave(Util.dp2px(parseFloat(args[0])), Util.dp2px(parseFloat(args[1])), Util.dp2px(parseFloat(args[4])), parseFloat(args[2]), parseFloat(args[3]), mWaveHeight / 2));}}} else {mltWave.add(new Wave(Util.dp2px(50), Util.dp2px(0), Util.dp2px(5), 1.7f, 2f, mWaveHeight / 2));}}protected void updateWavePath(int w, int h) {for (Wave wave : mltWave) {wave.updateWavePath(w, h, mWaveHeight / 2, mEnableFullScreen, mCurProgress);}}/*** 执行回弹动画** @param progress     目标值* @param interpolator 加速器* @param duration     时长*/protected void animProgress(float progress, Interpolator interpolator, int duration) {if (mCurProgress != progress) {if (reboundAnimator != null) {reboundAnimator.cancel();}reboundAnimator = ValueAnimator.ofFloat(mCurProgress, progress);reboundAnimator.setDuration(duration);reboundAnimator.setInterpolator(interpolator);reboundAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {reboundAnimator = null;}});reboundAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {updateProgress((float) animation.getAnimatedValue());}});reboundAnimator.start();}}protected void updateProgress(float progress) {View thisView = this;mCurProgress = progress;updateLinearGradient(thisView.getWidth(), thisView.getHeight());if (mEnableFullScreen) {for (Wave wave : mltWave) {wave.updateWavePath(thisView.getWidth(), thisView.getHeight(), mCurProgress);}}if (!mIsRunning) {invalidate();}}//<editor-fold desc="method api">public void setWaves(String waves) {setTag(waves);if (mLastTime > 0) {View thisView = this;updateWavePath();updateWavePath(thisView.getWidth(), thisView.getHeight());}}public int getWaveHeight() {return mWaveHeight;}public void setWaveHeight(int waveHeight) {this.mWaveHeight = Util.dp2px(waveHeight);if (!mltWave.isEmpty()) {View thisView = this;updateWavePath(thisView.getWidth(), thisView.getHeight());}}public float getVelocity() {return mVelocity;}public void setVelocity(float velocity) {this.mVelocity = velocity;}public float getProgress() {return mProgress;}public void setProgress(float progress) {this.mProgress = progress;if (!mIsRunning) {updateProgress(progress);} else {animProgress(progress, new DecelerateInterpolator(), 300);}}public void setProgress(float progress, Interpolator interpolator, int duration) {this.mProgress = progress;animProgress(progress, new DecelerateInterpolator(), duration);}public int getGradientAngle() {return mGradientAngle;}public void setGradientAngle(int angle) {this.mGradientAngle = angle;if (!mltWave.isEmpty()) {View thisView = this;updateLinearGradient(thisView.getWidth(), thisView.getHeight());}}public int getStartColor() {return mStartColor;}public void setStartColor(int color) {this.mStartColor = color;if (!mltWave.isEmpty()) {View thisView = this;updateLinearGradient(thisView.getWidth(), thisView.getHeight());}}public void setStartColorId(@ColorRes int colorId) {final View thisView = this;setStartColor(Util.getColor(thisView.getContext(), colorId));}public int getCloseColor() {return mCloseColor;}public void setCloseColor(int color) {this.mCloseColor = color;if (!mltWave.isEmpty()) {View thisView = this;updateLinearGradient(thisView.getWidth(), thisView.getHeight());}}public void setCloseColorId(@ColorRes int colorId) {final View thisView = this;setCloseColor(Util.getColor(thisView.getContext(), colorId));}public float getColorAlpha() {return mColorAlpha;}public void setColorAlpha(float alpha) {this.mColorAlpha = alpha;if (!mltWave.isEmpty()) {View thisView = this;updateLinearGradient(thisView.getWidth(), thisView.getHeight());}}public void start() {if (!mIsRunning) {mIsRunning = true;mLastTime = System.currentTimeMillis();invalidate();}}public void stop() {mIsRunning = false;}public boolean isRunning() {return mIsRunning;}public void setEnableFullScreen(boolean fullScreen) {this.mEnableFullScreen = fullScreen;}public boolean isEnableFullScreen() {return mEnableFullScreen;}public void setShape(ShapeType shape) {this.mShape = shape;updateShapePath();}public ShapeType getShape() {return mShape;}
}

第二步:创建  ShapeType  类

public enum ShapeType {Rect,RoundRect,Oval,
}

第三步:创建  Util 类

public class Util {/*** 获取颜色* @param context 上下文* @param colorId 颜色ID* @return 颜色*/@ColorIntpublic static int getColor(@NonNull Context context, @ColorRes int colorId) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {return context.getColor(colorId);}//noinspection deprecationreturn context.getResources().getColor(colorId);}/*** dp转px* @param dpVal dp 值* @return px*/public static int dp2px(float dpVal) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpVal, Resources.getSystem().getDisplayMetrics());}
}

第四步:创建  Wave 类

public class Wave {Path path;          //水波路径int width;          //画布宽度(2倍波长)int wave;           //波幅(振幅)float offsetX;        //水波的水平偏移量float offsetY;        //水波的竖直偏移量float velocity;       //水波移动速度(像素/秒)private float scaleX;       //水平拉伸比例private float scaleY;       //竖直拉伸比例private int curWave;int startColor;     //开始颜色int closeColor;     //结束颜色float alpha;        //颜色透明度/*** 通过参数构造一个水波对象* @param offsetX   水平偏移量* @param offsetY   竖直偏移量* @param velocity  移动速度(像素/秒)* @param scaleX    水平拉伸量* @param scaleY    竖直拉伸量* @param wave      波幅(波宽度)*/Wave(/*Context context, */int offsetX, int offsetY, int velocity, float scaleX, float scaleY, int wave) {
//        super(context);this.wave = wave;           //波幅(波宽)this.scaleX = scaleX;       //水平拉伸量this.scaleY = scaleY;       //竖直拉伸量this.offsetX = offsetX;     //水平偏移量this.offsetY = offsetY;     //竖直偏移量this.velocity = velocity;   //移动速度(像素/秒)this.path = new Path();}protected void updateWavePath(int w, int h, int waveHeight, boolean fullScreen, float progress) {this.wave = waveHeight;this.width = (int) (2* scaleX * w);  //画布宽度(2倍波长)this.path = buildWavePath(width, h, fullScreen, progress);}protected void updateWavePath(int w, int h, float progress) {int wave = (int) (scaleY * this.wave);//计算拉伸之后的波幅float maxWave = h * Math.max(0, (1 - progress));if (wave > maxWave) {wave = (int)maxWave;}if (curWave != wave) {this.width = (int) (2 * scaleX * w);  //画布宽度(2倍波长)this.path = buildWavePath(width, h, true, progress);}}protected Path buildWavePath(int width, int height, boolean fullScreen, float progress) {int DP = Util.dp2px(1);//一个dp在当前设备表示的像素量(水波的绘制精度设为一个dp单位)if (DP < 1) {DP = 1;}int wave = (int) (scaleY * this.wave);//计算拉伸之后的波幅if (fullScreen) {float maxWave = height * Math.max(0, (1 - progress));if (wave > maxWave) {wave = (int) maxWave;}}this.curWave = wave;//        Path path = new Path();path.reset();path.moveTo(0, 0);path.lineTo(0, height - wave);if (wave > 0) {for (int x = DP; x < width; x += DP) {path.lineTo(x, height - wave - wave * (float) Math.sin(4.0 * Math.PI * x / width));}}path.lineTo(width, height - wave);path.lineTo(width, 0);path.close();return path;}
}

接下来就可以实现效果了。不记得是转载自哪位博主了,如果找到原博主文章,可以@我加上转载地址,在此只当做笔记使用,有幸的话,帮助解决遇到相同问题的小伙伴。

自定义水波纹效果,可设置波纹条数和波纹颜色,使用简单相关推荐

  1. oracle 设置查询条数,SQL、MySQL、Oracle、 Sqlite、Informix数据库查询指定条数数据的方法...

    SQL查询前10条的方法为: select top X * from table_name --查询前X条记录,可以改成需要的数字,比如前10条. select top X * from table_ ...

  2. 5.21 使用波纹效果命令给卡通人物设计波浪发型 [Illustrator CC教程]

    原文:http://coolketang.com/staticDesign/5a97b8c49f5454403c508313.html 1. 本节课将为您演示波纹工具的使用.首先选择文档中卡通人物的头 ...

  3. R语言head函数和tail函数获取dataframe、列表list、向量vector的头部和尾部数据:tail提取数据对象的尾部数据、head提取数据对象的头部数据、默认6条数据、自定义设置返回条数

    R语言head函数和tail函数获取dataframe.列表list.向量vector的头部和尾部数据:tail提取数据对象的尾部数据.head提取数据对象的头部数据.默认6条数据.自定义设置返回条数 ...

  4. QCustomplot中色谱图(QCPColorMap)设置色条(QCPColorScale)

    在.h文件中包含 #include "qcustomplot.h" void SetGraph_Img(QCustomPlot *p_imag); //设置谱图图纸QCPColor ...

  5. ruoyi框架分页总条数total返回错误解决方案

    ruoyi框架分页总条数total返回错误解决方案 原因:因为自己重新定义了分页方法,如: 就会出现总数返回数据错误问题 总数会变成当前页条数的 这是分页的核心,这里传过来的list 没有 insta ...

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

    在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了, ...

  7. 自定义view实现水波纹效果

    水波纹效果: 1.标准正余弦水波纹: 2.非标准圆形液柱水波纹: 虽说都是水波纹,但两者在实现上差异是比较大的,一个通过正余弦函数模拟水波纹效果,另外一个会运用到图像的混合模式(PorterDuffX ...

  8. Android点击水波纹扩散效果整理(附带一个自定义的水波纹效果控件)

    很久很久没有写博客了,说来也有点惭愧.正好最近整理自己的项目工程目录,看到一些值得分享的控件,准备在之后的几篇博客中准备把它们陆续搬运上来. 这篇博客准备整理一下Android Material De ...

  9. android 立体 流量球,Android自定义View——实现水波纹效果类似剩余流量球

    Android自定义View--实现水波纹效果类似剩余流量球 三个点   pre   ber   block   span   初始化   move   理解最近突然手痒就想搞个贝塞尔曲线做个水波纹效 ...

最新文章

  1. Xamarin XAML语言教程模板视图TemplatedView(二)
  2. 图解ecshop之批量上传与批量处理
  3. 去除桌面图标蓝底的方法步骤
  4. 服务器账号密码更改,如何更改服务器用户名和密码
  5. 【CTF解题】BCTF2018-houseofatum-Writeup题解
  6. Influxdb安装、启动influxdb控制台、常用命令、Influx命令使用、Influx-sql使用举例、Influxdb的数据格式、Influxdb客户端工具
  7. SAP Spartacus里解析route参数的逻辑
  8. Spring的两种任务调度Scheduled和Async
  9. 计算机键盘prtscr,键盘上的SCR是什么意思(电脑截图的快捷方式都有哪些)
  10. 【深度优先搜索】计蒜客:方程的解数
  11. Python3中Dict不能在循环中删除元素
  12. matlab求积分 没有解,MATLAB 求积分时无法输出数值解,一直是积分表达式
  13. begin tran,commit tran和rollback tran的用法
  14. STM32F446RET6产品描述
  15. Qt Design Studio 1.4正式发布
  16. Android面试题【高级工程师版】
  17. SolidWorks渲染图
  18. The DELETE statement conflicted with the REFERENCE constraint
  19. Raki的读paper小记:OFA: UNIFYING ARCHITECTURES, TASKS, AND MODALITIES THROUGH A SIMPLE Seq2Seq FRAMEWORK
  20. Neo4j 图数据库高级应用系列 / 服务器扩展指南 APOC 8.5 - 图生成 / 随机图

热门文章

  1. html语言右对齐,在HTML中右对齐块元素
  2. 计算机技术的应用 课件,计算机技术及应用基础――第二章ppt课件
  3. html怎么建立段落,HTML 段落
  4. 雷军1994年写的诗一样的代码,我把它运行起来了!
  5. 21年编程,那些我踩过的坑!
  6. mysql主从同步slave_MySQL主从复制(Master-Slave)实践
  7. JAVA中的onkey_onKeyListener无法在虚拟键盘上工作
  8. 单片机控制两个步进电机画圆_51单片机控制两个步进电机
  9. linux mysql odbc驱动安装_mysql odb驱动_Mysql的odbc driver安装配置(Linux)
  10. class路径快捷 xml配置_SpringBoot 配置文件详解(告别XML)-class文件