模仿水波纹,涟漪效果,可用于设备查找之类的特效
Demo下载:我的Github RippleView
其实这是一个很简单的自定义View,只需要一个类,然后对外提供状态回调接口和设置属性的方法即可。
下面要说设计思路了。
1,自定义一个View。
2,在onDraw方法里画圆,初始化画笔,半径多少,要画几个圆,实心圆还是空心圆,这些都要想好。
3,通过ValueAnimator 动画每一贞的回调改变圆半径,调用postInvalidate方法不断重绘,就能产生水波纹效果了。
4,设置状态监听器,设置注入方法,在该使用的地方回调一把出去。
5,设置圆的属性参数的方法。
6,在外面使用。
水波纹自定义View,设计思路就是酱子。
接下来看代码详细的分析上述所说的步骤。
1,自定义一个View。
public class RippleView extends View {
public RippleView(Context context) {
super(context);
init();
}
public RippleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RippleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
}
2,在onDraw方法里画圆,初始化画笔,半径多少,要画几个圆,实心圆还是空心圆,这些都要想好。
初始化画笔,半径。注意mChangeRadius为动画开始后不断改变的半径值,为了不断画更大的圆。
private void init() {
mRadius = dip2px(NORMAL_RADIUS);
mChangeRadius = mRadius;
//初始化实心内圆画笔
mInPaint.setColor(getResources().getColor(R.color.white10));
mInPaint.setAntiAlias(true);
mInPaint.setStyle(Paint.Style.FILL);
//初始化空心内圆画笔
mInStrokePaint.setColor(getResources().getColor(R.color.white50));
mInStrokePaint.setAntiAlias(true);
mInStrokePaint.setStyle(Paint.Style.STROKE);
mInStrokePaint.setStrokeWidth(dip2px(mStrokeWidth));
//初始化空心外圆画笔
mOutStrokePaint.setColor(getResources().getColor(R.color.white50));
mOutStrokePaint.setAntiAlias(true);
mOutStrokePaint.setStyle(Paint.Style.STROKE);
mOutStrokePaint.setStrokeWidth(dip2px(mStrokeWidth));
}
初始化圆心
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//初始化圆心
mCx = getMeasuredWidth() / 2;
mCy = getMeasuredHeight() / 2;
}
画圆。这里水波纹的圆画了三个。开始先画一个,等第一个半径变为初始值1.5倍时画第二个圆,2倍画第三个圆。注意圆半径的值计算。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画半径变化的外圆
canvas.drawCircle(mCx, mCy, mChangeRadius, mOutStrokePaint);
if(mChangeRadius >= mRadius * 1.5) {
canvas.drawCircle(mCx, mCy, mChangeRadius - (mRadius / 2) , mOutStrokePaint);
}
if(mChangeRadius >= mRadius * 2) {
canvas.drawCircle(mCx, mCy, mChangeRadius - (mRadius), mOutStrokePaint);
}
//画实心内圆
canvas.drawCircle(mCx, mCy, mRadius, mInPaint);
//画空心内圆
canvas.drawCircle(mCx, mCy, mRadius, mInStrokePaint);
}
3,通过ValueAnimator 动画每一贞的回调改变圆半径,调用postInvalidate方法不断重绘,就能产生水波纹效果了。
动画值的变化区域这里设置为:
mValueAnimator.setIntValues(mRadius, (int) (mCx > mCy ? mCx * 1.4 : mCy * 1.4));
设置开启水波纹动画和关闭水波纹动画的方法。
/** 开启水波纹 */
public void startRipple() {
if (mValueAnimator == null) {
mValueAnimator = new ValueAnimator();
mValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mValueAnimator.setIntValues(mRadius, (int) (mCx > mCy ? mCx * 1.4 : mCy * 1.4));
mValueAnimator.setDuration(mDuration);
mValueAnimator.setRepeatCount(mRepeatCount);
mValueAnimator.addUpdateListener(this);
mValueAnimator.addListener(this);
mValueAnimator.start();
} else {
if (!mValueAnimator.isRunning()) {
mValueAnimator.start();
}
}
}
/** 关闭水波纹 */
public void stopRipple() {
if (mValueAnimator != null) {
mValueAnimator.end();
}
}
处理每一贞动画的逻辑。计算出最新的半径值给圆,然后不断重绘。
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mChangeRadius = (int) animation.getAnimatedValue();
postInvalidate();
if (mRippleStateListener != null) {
mRippleStateListener.onRippleUpdate(animation);
}
}
设置状态监听器,设置注入方法,在该使用的地方回调一把出去。
/** 对外提供状态信息的接口 */
public interface RippleStateListener {
/** 动画开始 */
void startRipple();
/** 动画结束 */
void stopRipple();
/** 每一贞动画回调 */
void onRippleUpdate(ValueAnimator animation);
}
/** 水波纹状态接口对象注入 */
public void setRippleStateListener(RippleStateListener listener) {
mRippleStateListener = listener;
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mChangeRadius = (int) animation.getAnimatedValue();
postInvalidate();
if (mRippleStateListener != null) {
mRippleStateListener.onRippleUpdate(animation);
}
}
@Override
public void onAnimationStart(Animator animation) {
if (mRippleStateListener != null) {
mRippleStateListener.startRipple();
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (mRippleStateListener != null) {
mRippleStateListener.stopRipple();
}
//动画结束,初始变化的半径
mChangeRadius = mRadius;
}
5,设置圆的属性参数的方法。
/** 设置圆半径 */
public void setRadius(int radius) {
mRadius = radius;
mChangeRadius = radius;
}
/** 设置圆边线宽度 */
public void setStrokeWidth(int strokeWidth) {
mStrokeWidth = strokeWidth;
}
/** 设置动画时间 */
public void setDuration(int duration) {
mDuration = duration;
}
/** 设置动画次数 */
public void setRepeatCount(int repeatCount) {
mRepeatCount = repeatCount;
}
/** 设置圆心 */
public void setCirclePoint(float x ,float y) {
mCx = x;
mCy = y;
}
/** 设置空心外圆颜色 */
public void setOutStrokePaintColor(int color) {
mOutStrokePaint.setColor(color);
}
/** 设置空心内圆颜色 */
public void setInStrokePaintColor(int color) {
mInStrokePaint.setColor(color);
}
/** 设置实心内圆颜色 */
public void setInPaintColor(int color) {
mInPaint.setColor(color);
}
6,在外面使用。
mRippleView = (RippleView) findViewById(R.id.root_rv);
mRippleView.setRippleStateListener(this);
public void start(View v) {
mRippleView.startRipple();
}
public void stop(View v) {
mRippleView.stopRipple();
}
@Override
public void startRipple() {
mTextView.setText("0%");
}
@Override
public void stopRipple() {
}
@Override
public void onRippleUpdate(ValueAnimator animation) {
float fraction = animation.getAnimatedFraction();
int value = (int) (fraction * 100);
mTextView.setText(String.valueOf(value) + "%");
}
涟漪,水波纹自定义就这样分析完了。
再来看一次效果图:
就到这里了,小程序一枚。
Demo下载:我的Github RippleView
2016年7月02日 18:00:21