自定义水波纹效果,可设置波纹条数和波纹颜色,使用简单
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;}
}
接下来就可以实现效果了。不记得是转载自哪位博主了,如果找到原博主文章,可以@我加上转载地址,在此只当做笔记使用,有幸的话,帮助解决遇到相同问题的小伙伴。
自定义水波纹效果,可设置波纹条数和波纹颜色,使用简单相关推荐
- oracle 设置查询条数,SQL、MySQL、Oracle、 Sqlite、Informix数据库查询指定条数数据的方法...
SQL查询前10条的方法为: select top X * from table_name --查询前X条记录,可以改成需要的数字,比如前10条. select top X * from table_ ...
- 5.21 使用波纹效果命令给卡通人物设计波浪发型 [Illustrator CC教程]
原文:http://coolketang.com/staticDesign/5a97b8c49f5454403c508313.html 1. 本节课将为您演示波纹工具的使用.首先选择文档中卡通人物的头 ...
- R语言head函数和tail函数获取dataframe、列表list、向量vector的头部和尾部数据:tail提取数据对象的尾部数据、head提取数据对象的头部数据、默认6条数据、自定义设置返回条数
R语言head函数和tail函数获取dataframe.列表list.向量vector的头部和尾部数据:tail提取数据对象的尾部数据.head提取数据对象的头部数据.默认6条数据.自定义设置返回条数 ...
- QCustomplot中色谱图(QCPColorMap)设置色条(QCPColorScale)
在.h文件中包含 #include "qcustomplot.h" void SetGraph_Img(QCustomPlot *p_imag); //设置谱图图纸QCPColor ...
- ruoyi框架分页总条数total返回错误解决方案
ruoyi框架分页总条数total返回错误解决方案 原因:因为自己重新定义了分页方法,如: 就会出现总数返回数据错误问题 总数会变成当前页条数的 这是分页的核心,这里传过来的list 没有 insta ...
- Android 之自定义view实现水波纹效果
在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了, ...
- 自定义view实现水波纹效果
水波纹效果: 1.标准正余弦水波纹: 2.非标准圆形液柱水波纹: 虽说都是水波纹,但两者在实现上差异是比较大的,一个通过正余弦函数模拟水波纹效果,另外一个会运用到图像的混合模式(PorterDuffX ...
- Android点击水波纹扩散效果整理(附带一个自定义的水波纹效果控件)
很久很久没有写博客了,说来也有点惭愧.正好最近整理自己的项目工程目录,看到一些值得分享的控件,准备在之后的几篇博客中准备把它们陆续搬运上来. 这篇博客准备整理一下Android Material De ...
- android 立体 流量球,Android自定义View——实现水波纹效果类似剩余流量球
Android自定义View--实现水波纹效果类似剩余流量球 三个点 pre ber block span 初始化 move 理解最近突然手痒就想搞个贝塞尔曲线做个水波纹效 ...
最新文章
- Xamarin XAML语言教程模板视图TemplatedView(二)
- 图解ecshop之批量上传与批量处理
- 去除桌面图标蓝底的方法步骤
- 服务器账号密码更改,如何更改服务器用户名和密码
- 【CTF解题】BCTF2018-houseofatum-Writeup题解
- Influxdb安装、启动influxdb控制台、常用命令、Influx命令使用、Influx-sql使用举例、Influxdb的数据格式、Influxdb客户端工具
- SAP Spartacus里解析route参数的逻辑
- Spring的两种任务调度Scheduled和Async
- 计算机键盘prtscr,键盘上的SCR是什么意思(电脑截图的快捷方式都有哪些)
- 【深度优先搜索】计蒜客:方程的解数
- Python3中Dict不能在循环中删除元素
- matlab求积分 没有解,MATLAB 求积分时无法输出数值解,一直是积分表达式
- begin tran,commit tran和rollback tran的用法
- STM32F446RET6产品描述
- Qt Design Studio 1.4正式发布
- Android面试题【高级工程师版】
- SolidWorks渲染图
- The DELETE statement conflicted with the REFERENCE constraint
- Raki的读paper小记:OFA: UNIFYING ARCHITECTURES, TASKS, AND MODALITIES THROUGH A SIMPLE Seq2Seq FRAMEWORK
- Neo4j 图数据库高级应用系列 / 服务器扩展指南 APOC 8.5 - 图生成 / 随机图
热门文章
- html语言右对齐,在HTML中右对齐块元素
- 计算机技术的应用 课件,计算机技术及应用基础――第二章ppt课件
- html怎么建立段落,HTML 段落
- 雷军1994年写的诗一样的代码,我把它运行起来了!
- 21年编程,那些我踩过的坑!
- mysql主从同步slave_MySQL主从复制(Master-Slave)实践
- JAVA中的onkey_onKeyListener无法在虚拟键盘上工作
- 单片机控制两个步进电机画圆_51单片机控制两个步进电机
- linux mysql odbc驱动安装_mysql odb驱动_Mysql的odbc driver安装配置(Linux)
- class路径快捷 xml配置_SpringBoot 配置文件详解(告别XML)-class文件