Android 5.0 实现水波扩散效果
程序员文章站
2022-06-23 14:54:08
本文实例为大家分享了android 5.0 实现水波扩散效果的具体代码,供大家参考,具体内容如下
该效果是通过自定义界面来实现的
1、首先自定义属性,attrs.xml...
本文实例为大家分享了android 5.0 实现水波扩散效果的具体代码,供大家参考,具体内容如下
该效果是通过自定义界面来实现的
1、首先自定义属性,attrs.xml代码如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="rippleview"> <attr name="ripplecolor" format="color" /> <attr name="ripplealpha" format="float" /> <attr name="maskalpha" format="float" /> <attr name="rippletime" format="integer" /> </declare-styleable> </resources>
其中属性ripplecolor为水波动画的颜色,ripplealpha为其透明度,rippletime为动画持续时间,maskalpha为触摸遮掩层的透明度。
2、自定义rippleview类继承relativelayout布局,也可以由需求所定继承于其它类,实现水波扩散效果主要的有两点:水波扩散的绘制和动画
1)水波的绘制其实就是绘制一个圆形
canvas.drawcircle(mdownx, mdowny, mradius, mripplepaint);
2)动画效果就是该圆形的绘制从小到大的过程,而该圆形到最大时的半径长度就是当前所在布局的对角线长度:
@override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); // 获取最大半径 mmaxradius = (float) math.sqrt(w * w + h * h); }
动画效果用属性动画objectanimator来实现(objectanimator是android3.0后出现的)如下
mrippleanim = objectanimator.offloat(this, "radius", 0, mmaxradius); mrippleanim.setinterpolator(new acceleratedecelerateinterpolator()); mrippleanim.setduration(mrippletime);
其中的radius为自定义的属性,在动画执行时会回调对应的方法,只需要在该方法中更新圆形的半径就行了
public void setradius(final float radius) { mradius = radius; invalidate(); }
rippleview完整代码如下:
public class rippleview extends relativelayout { private int mripplecolor;// 水波颜色 private float mmaskalpha;// 遮掩透明度 private float mripplealpha;// 水波透明度 private int mrippletime;// 水波动画时间 private objectanimator mrippleanim;// 显示水波动画 private float mradius;// 当前的半径 private float mmaxradius;// 水波最大半径 private float mdownx; // 记录手指按下的位置 private float mdowny; private boolean mismask; private boolean misanimating;// 是否正在播放动画 private rectf mrect; private path mpath; private paint mmaskpaint; private paint mripplepaint; public rippleview(context context) { this(context, null); } public rippleview(context context, attributeset attrs) { this(context, attrs, 0); } public rippleview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(); // 获取自定义属性 typedarray ta = context.obtainstyledattributes(attrs, r.styleable.rippleview); mripplecolor = ta.getcolor(r.styleable.rippleview_ripplecolor, mripplecolor); mmaskalpha = ta.getfloat(r.styleable.rippleview_maskalpha, mmaskalpha); mripplealpha = ta.getfloat(r.styleable.rippleview_ripplealpha, mripplealpha); mrippletime = ta.getint(r.styleable.rippleview_rippletime, mrippletime); ta.recycle(); initlast(); } // 初始化方法 private void init() { mripplecolor = color.black; mmaskalpha = 0.4f; mripplealpha = 0.8f; mrippletime = 800; mpath = new path(); mmaskpaint = new paint(paint.anti_alias_flag); mripplepaint = new paint(paint.anti_alias_flag); } // 初始化 private void initlast() { mmaskpaint.setcolor(mripplecolor); mripplepaint.setcolor(mripplecolor); mmaskpaint.setalpha((int) (mmaskalpha * 255)); mripplepaint.setalpha((int) (mripplealpha * 255)); } // 初始化动画 private void initanim() { mrippleanim = objectanimator.offloat(this, "radius", 0, mmaxradius); mrippleanim.setinterpolator(new acceleratedecelerateinterpolator()); mrippleanim.setduration(mrippletime); mrippleanim.addlistener(new animator.animatorlistener() { @override public void onanimationstart(animator animator) { misanimating = true; } @override public void onanimationend(animator animator) { setradius(0); mismask = false; misanimating = false; } @override public void onanimationcancel(animator animator) { } @override public void onanimationrepeat(animator animator) { } }); } @override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); // 获取最大半径 mmaxradius = (float) math.sqrt(w * w + h * h); // 获取该类布局范围 mrect = new rectf(0f, 0f, getmeasuredwidth() * 1.0f, getmeasuredheight() * 1.0f); // 初始化动画 initanim(); } @override public boolean ontouchevent(motionevent event) { // 按下事件 if (event.getaction() == motionevent.action_down) { mismask = true; invalidate(); } else if (event.getaction() == motionevent.action_move) { invalidate(); } // 抬起事件 else if (event.getaction() == motionevent.action_up) { mdownx = event.getx(); mdowny = event.gety(); if (misanimating) { mrippleanim.cancel(); } boolean isinview = mrect.contains(mdownx, mdowny); if (isinview) { mrippleanim.start(); } else { mismask = false; invalidate(); } } return true; } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); // 绘制遮掩 if (mismask) { canvas.save(canvas.clip_save_flag); mpath.reset(); mpath.addrect(mrect, path.direction.cw); canvas.clippath(mpath); canvas.drawrect(mrect, mmaskpaint); canvas.restore(); } // 绘制水波 canvas.save(canvas.clip_save_flag); mpath.reset(); mpath.addcircle(mdownx, mdowny, mradius, path.direction.cw); canvas.clippath(mpath); canvas.drawcircle(mdownx, mdowny, mradius, mripplepaint); canvas.restore(); } // 属性动画回调的方法 public void setradius(final float radius) { mradius = radius; invalidate(); } }
界面布局代码
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:ripple="http://schemas.android.com/apk/res/com.example.rippleview" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000000" > <com.example.rippleview.rippleview android:layout_width="match_parent" android:layout_height="100dp" android:layout_centerinparent="true" android:background="#ffffff" android:clickable="true" ripple:ripplecolor="#ababab" > <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerinparent="true" android:text="click me" android:textsize="18sp" /> </com.example.rippleview.rippleview> </relativelayout>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读