前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 5.0 实现水波扩散效果

Android 5.0 实现水波扩散效果

作者头像
砸漏
发布2020-11-04 10:44:12
7160
发布2020-11-04 10:44:12
举报
文章被收录于专栏:恩蓝脚本

本文实例为大家分享了Android 5.0 实现水波扩散效果的具体代码,供大家参考,具体内容如下

该效果是通过自定义界面来实现的

1、首先自定义属性,attrs.xml代码如下:

代码语言:javascript
复制
<?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)水波的绘制其实就是绘制一个圆形

代码语言:javascript
复制
canvas.drawCircle(mDownX, mDownY, mRadius, mRipplePaint);

2)动画效果就是该圆形的绘制从小到大的过程,而该圆形到最大时的半径长度就是当前所在布局的对角线长度:

代码语言:javascript
复制
@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后出现的)如下

代码语言:javascript
复制
mRippleAnim = ObjectAnimator.ofFloat(this, "radius", 0, mMaxRadius);
mRippleAnim.setInterpolator(new AccelerateDecelerateInterpolator());
mRippleAnim.setDuration(mRippleTime);

其中的radius为自定义的属性,在动画执行时会回调对应的方法,只需要在该方法中更新圆形的半径就行了

代码语言:javascript
复制
public void setRadius(final float radius) {
 mRadius = radius;
 invalidate();
}

RippleView完整代码如下:

代码语言:javascript
复制
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();
}
}

界面布局代码

代码语言:javascript
复制
<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 

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档