1.废话
来到公司的第一个任务,写出水波纹,仔细想想具体思路,点击一下就有水波 ,那也不能那里点击都有水波吧,那就继承一个相对布局呗,然后响应点击事件,绘画一个波纹,那就是动画了,OK,先去google,发现一个开源库 RippleView 最低兼容到2.3正好也是老大要求的兼容嘛。
效果图
github地址:https://github.com/traex/RippleEffect 作者没有做过多介绍事实是也没多少代码 github是AS构建的
2.作者思路呢:
① 继承相对布局,复写三个构造方法,实现init方法-获取属性,设置属性
属性分别是:
- app:rv_alpha [integer def:90 0-255] --> Alpha of the ripple
- app:rv_framerate [integer def:10] --> Frame rate of the ripple animation
- app:rv_rippleDuration [integer def:400] --> Duration of the ripple animation
- app:rv_ripplePadding [dimension def:0] --> Add a padding to the ripple
- app:rv_color [color def:@android:color/white] --> Color of the ripple
- app:rv_centered [boolean def:false] --> Center ripple in the child view
- app:rv_type [enum (simpleRipple, doubleRipple) def:simpleRipple] --> Simple or double ripple
- app:rv_zoom [boolean def:false] --> Enable zoom animation
- app:rv_zoomDuration [integer def:150] --> Duration of zoom animation
- app:rv_zoomScale [float def:1.03] --> Scale of zoom animation
源码还给了长按点击事件
② 自定义布局嘛,肯定还有OnD
raw 绘画
判断动画是否开始,未开始先设置一些参数,而且判断是否到达下一次刷新的时间,到了就刷新一些,执行一次绘画,同时绘画的时候还要判断一些类型,比如type 你在xml里面设置的
super.draw(canvas);
// 判断动画是否开始
if (animationRunning) {
//是否已经到达持续时间
if (rippleDuration <= timer * frameRate) {
animationRunning = false;
timer = 0;
durationEmpty = -1;
timerEmpty = 0;
canvas.restore();
invalidate();
if (onCompletionListener != null)
onCompletionListener.onComplete(this);
return;
} else
canvasHandler.postDelayed(runnable, frameRate);
if (timer == 0)
canvas.save();
// 画圆
canvas.drawCircle(x, y, (radiusMax * (((float) timer * frameRate) / rippleDuration)), paint);
//设置颜色
paint.setColor(Color.parseColor("#ffff4444"));
//判断是否是type1
if (rippleType == 1 && originBitmap != null && (((float) timer * frameRate) / rippleDuration) > 0.4f) {
if (durationEmpty == -1)
durationEmpty = rippleDuration - timer * frameRate;
timerEmpty++;
final Bitmap tmpBitmap = getCircleBitmap(
(int) ((radiusMax) * (((float) timerEmpty * frameRate) / (durationEmpty))));
canvas.drawBitmap(tmpBitmap, 0, 0, paint);
tmpBitmap.recycle();
}
paint.setColor(rippleColor);
if (rippleType == 1) {
if ((((float) timer * frameRate) / rippleDuration) > 0.6f)
paint.setAlpha((int) (rippleAlpha
- ((rippleAlpha) * (((float) timerEmpty * frameRate) / (durationEmpty)))));
else
paint.setAlpha(rippleAlpha);
} else
paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timer * frameRate) / rippleDuration))));
timer++;
}
3.大家都看到上面了,如果动画没开始是不会进行绘制的,所以要在touch时间中进行监控
@Override
public boolean onTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
animateRipple(event);
sendClickEvent(false);
}
return super.onTouchEvent(event);
}
animateRipple 开始波浪动画
private void createAnimation(final float x, final float y) {
// 有不有开始
if (this.isEnabled() && !animationRunning) {
//要不要进行缩放效果同时也是在xml里面设置的
if (hasToZoom)
this.startAnimation(scaleAnimation);
radiusMax = Math.max(WIDTH, HEIGHT);
if (rippleType != 2)
radiusMax /= 2;
radiusMax -= ripplePadding;
if (isCentered || rippleType == 1) {
this.x = getMeasuredWidth() / 2;
this.y = getMeasuredHeight() / 2;
} else {
this.x = x;
this.y = y;
}
animationRunning = true;
if (rippleType == 1 && originBitmap == null)
originBitmap = getDrawingCache(true);
invalidate();
}
}
4.其实还用了缓存的数据进行再次试用
private Bitmap getCircleBitmap(final int radius) {
final Bitmap output = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(),
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(output);
final Paint paint = new Paint();
final Rect rect = new Rect((int) (x - radius), (int) (y - radius), (int) (x + radius), (int) (y + radius));
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawCircle(x, y, radius, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(originBitmap, rect, rect, paint);
return output;
}