android 水波纹效果button_Android Ripple 按钮水波纹效果(二)优化

上1篇中我们讲了自定义ripple 水波纹效果,先来回顾1下效果吧!

bfd88962d74edcee84460258e37698c2.gif

看了以后感觉没什么问题,我1开始也觉得很满意了,那好,我们拿Android 5.0自带的效果来对照1下

7a69e7b7a7d0f492f18cddcdbf4b92a3.gif

发现了不同的地方没?点击中间的时候是看不出甚么区分,但是点击两边的时候,就很明显了,我们自定义的效果,波纹向两边同速度的分散,所以就会出现,如果点击点不在中心的时候,距离短的1边波纹先到达,而距离长的1边后到达,不能同时到达边沿!而系统自带的则不存在这类情况,所以这是1个优化点;另外一个优化点是:我们自定义的效果,在波纹全部覆盖以后,按钮的选中效果没了。

有两处需要优化的

1、实现不论是否点击中间点都能实现波纹同步到达边沿

2、当手指未松开时,选中效果不消失

实现:

第2点好实现,我们主要讲1下第1点,

第1点我们视察系统的效果,看似两边速度不1致致使的,其实我们知道实现原理的话,很容易想到,它是不断改变圆的圆心来实现,我们上1篇中的实现方法是圆形固定,就是在我们手指按下的位置,而不断改变半径来实现,

很明显,这里也需要改变半径来实现,我记得我们上1篇中半径的最大值是需要计算,而这类效果是不需要计算的,由于其最大值是固定的,就是按钮对角线的1半!

肯定了半径的最大值,我们还需要肯定圆心X、Y的偏移量,相当于步长吧,其圆心从按下的点到按钮正中间的时间因该是和半径从0到最大值的时间保持1致,所以我们可以通过1下代码来获得圆心的偏移量和最大半径。

/*最大半径*/

mRadius = (float) Math.sqrt(mRect.width() / 2 * mRect.width() / 2 + mRect.height() / 2 * mRect.height() / 2);

/*半径的偏移量*/

mStepRadius = mRadius / mCycle;

/*圆心X的偏移量*/

mStepOriginX = (mRect.width() / 2 - mInitX) / mCycle;

/*圆心Y的偏移量*/

mStepOriginY = (mRect.height() / 2 - mInitY) / mCycle;

全部实现代码

package eyeclip.myapplication;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.Rect;

import android.support.v4.view.MotionEventCompat;

import android.support.v4.view.ViewCompat;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.widget.LinearLayout;

/**

* Created by moon.zhong on 2015/4/27.

*/

public class RippleLinearLayout extends LinearLayout {

/*起始点*/

private int mInitX;

private int mInitY;

private float mCurrentX;

private float mCurrentY;

/*高度和宽度*/

private int mWidth;

private int mHeight;

/*绘制的半径*/

private float mRadius;

private float mStepRadius;

private float mStepOriginX;

private float mStepOriginY;

private float mDrawRadius;

private boolean mDrawFinish;

private final int DURATION = 150;

private final int FREQUENCY = 10;

private float mCycle;

private final Rect mRect = new Rect();

private boolean mPressUp = false;

private Paint mRevealPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

public RippleLinearLayout(Context context) {

super(context);

initView(context);

}

public RippleLinearLayout(Context context, AttributeSet attrs) {

super(context, attrs);

initView(context);

}

public RippleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initView(context);

}

private void initView(Context context) {

mRevealPaint.setColor(0x25000000);

mCycle = DURATION / FREQUENCY;

final float density = getResources().getDisplayMetrics().density ;

mCycle = (density*mCycle);

mDrawFinish = true;

}

@Override

protected void onDraw(Canvas canvas) {

if (mDrawFinish) {

super.onDraw(canvas);

return;

}

canvas.drawColor(0x15000000);

super.onDraw(canvas);

if (mStepRadius == 0) {

return;

}

mDrawRadius = mDrawRadius + mStepRadius;

mCurrentX = mCurrentX + mStepOriginX;

mCurrentY = mCurrentY + mStepOriginY;

if (mDrawRadius > mRadius) {

mDrawRadius = 0;

canvas.drawCircle(mRect.width() / 2, mRect.height() / 2, mRadius, mRevealPaint);

mDrawFinish = true;

if (mPressUp)

invalidate();

return;

}

canvas.drawCircle(mCurrentX, mCurrentY, mDrawRadius, mRevealPaint);

ViewCompat.postInvalidateOnAnimation(this);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

mRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());

}

private void updateDrawData() {

// int radiusLeftTop = (int) Math.sqrt((mRect.left - mInitX) * (mRect.left - mInitX) +

// (mRect.top - mInitY) * (mRect.top - mInitY));

// int radiusRightTop = (int) Math.sqrt((mRect.right - mInitX) * (mRect.right - mInitX) +

// (mRect.top - mInitY) * (mRect.top - mInitY));

// int radiusLeftBottom = (int) Math.sqrt((mRect.left - mInitX) * (mRect.left - mInitX) +

// (mRect.bottom - mInitY) * (mRect.bottom - mInitY));

// int radiusRightBottom = (int) Math.sqrt((mRect.right - mInitX) * (mRect.right - mInitX) +

// (mRect.bottom - mInitY) * (mRect.bottom - mInitY));

// mRadius = getMax(radiusLeftTop, radiusRightTop, radiusLeftBottom, radiusRightBottom);

/*最大半径*/

mRadius = (float) Math.sqrt(mRect.width() / 2 * mRect.width() / 2 + mRect.height() / 2 * mRect.height() / 2);

;

/*半径的偏移量*/

mStepRadius = mRadius / mCycle;

/*圆心X的偏移量*/

mStepOriginX = (mRect.width() / 2 - mInitX) / mCycle;

/*圆心Y的偏移量*/

mStepOriginY = (mRect.height() / 2 - mInitY) / mCycle;

mCurrentX = mInitX;

mCurrentY = mInitY;

}

@Override

public boolean onTouchEvent(MotionEvent event) {

final int action = MotionEventCompat.getActionMasked(event);

switch (action) {

case MotionEvent.ACTION_DOWN: {

mPressUp = false;

mDrawFinish = false;

int index = MotionEventCompat.getActionIndex(event);

int eventId = MotionEventCompat.getPointerId(event, index);

if (eventId != -1) {

mInitX = (int) MotionEventCompat.getX(event, index);

mInitY = (int) MotionEventCompat.getY(event, index);

updateDrawData();

invalidate();

}

break;

}

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_UP:

mStepRadius = (int) (5 * mStepRadius);

mStepOriginX = (int) (5 * mStepOriginX);

mStepOriginY = (int) (5 * mStepOriginY);

mPressUp = true;

invalidate();

break;

}

return super.onTouchEvent(event);

}

private int getMax(int... radius) {

if (radius.length == 0) {

return 0;

}

int max = radius[0];

for (int m : radius) {

if (m > max) {

max = m;

}

}

return max;

}

@Override

public boolean performClick() {

postDelayed(new Runnable() {

@Override

public void run() {

RippleLinearLayout.super.performClick();

}

}, 150);

return true;

}

}

效果图对照

173c4c8599417fe0572b02a005169d49.gif

这篇主要是对上1篇的内容进行优化,固然你觉得不优化也行!

demo下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值