自定义点击产生涟漪效果

自定义点击产生涟漪效果

      下面是效果图
      
1、本文以TextView为例,自定义一个RippleTextView和RippleDarwable。在RippleTextView构造方法中进行重绘
public RippleTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mRippleDrawable = new RippleDrawable(context);
        mRippleDrawable.setCallback(this);          //设置刷新接口,view中已经实现
        mRippleDrawable.setRippleColor(Color.GRAY); //设置涟漪的颜色
}

重写onSizeChanged方法,设置drawable绘制和刷新的区域
mRippleDrawable.setBounds(0, 0, getWidth(), getHeight()); 

重写verifyDrawable方法,用来验证
protected boolean verifyDrawable(Drawable who) {
        return who == mRippleDrawable || super.verifyDrawable(who);//验证drawable
}

重写onDraw方法,重写onTouchEvent方法,必须返回true不然后续动作执行会出问题。
public boolean onTouchEvent(MotionEvent event) {
        mRippleDrawable.onTouch(event);
        super.onTouchEvent(event);
        return true;		
}
自定义RippleTextView就完成了。

2、现在开始自定义RippleDarwable
 2.1在构造方法中创建Paint,设置一系列参数优化画面
 mPaint.setAntiAlias(true);          //抗锯齿
 mPaint.setDither(true);             //防止颜色过度抖动
 mPaint.setStyle(Paint.Style.FILL);  //设置画笔为填充方式
 2.2设置画笔的颜色,透明度。不过这些也可以不用写,毕竟用户设置基本上不上
public void setRippleColor(int color) {
        mRippleColor = color;
        onColorOrAlphaChange();
}

@Override
public void setAlpha(int i) {
        mAlpha = i;
        onColorOrAlphaChange();
}

private void onColorOrAlphaChange() {
        mPaint.setColor(mRippleColor);      //先设置画笔颜色(包含透明度)
        if (mAlpha != 255) {
            int pAlpha = Color.alpha(mRippleColor);
            mPaint.setAlpha((int) (pAlpha * (mAlpha / 255f)));  //根据drawable的透明度设置画笔颜色的透明度
        }
}

2.3重写onBoundsChange方法,获取控件的中心点坐标以及做大半径
protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        mCenterPointX = bounds.centerX();
        mCenterPointY = bounds.centerY();

        float maxRadius = Math.max(mCenterPointX, mCenterPointY);
        mStartRadius = 0;
        mEndRadius = maxRadius * 0.8f;
}

2.4重写onDarw方法
public void draw(Canvas canvas) {
        int preAlpha = mPaint.getAlpha();
        int bgAlpha = (int) (preAlpha*(mBgAlpha/255f));
        int maxCircleAlpha = getCircleAlpha(preAlpha,bgAlpha);
        int circleAlpha = (int) (maxCircleAlpha*(mCircleAlpha/255f));

        mPaint.setAlpha(bgAlpha);
        canvas.drawColor(mPaint.getColor());        //绘制背景颜色

        mPaint.setAlpha(circleAlpha);               //设置画笔的透明度
        canvas.drawCircle(mRipplePointX, mRipplePointY, mRippleRadius, mPaint); //画一个圆

        mPaint.setAlpha(preAlpha);
}

2.5控件的监听
public void onTouch(MotionEvent event) {
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            onTouchRelease = false;
            mDonePointX = event.getX();
            mDonePointY = event.getY();
            startEnterRunnable();
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_UP:
            Log.e(TAG, "onTouch: ACTION_UP");
            onTouchRelease = true;
            if (mEnterDone)
                startExitRunnable();
            break;
    }
}

2.6动画的逻辑
//启动进入动画
private void startEnterRunnable() {
    mCircleAlpha = 255;
    mEnterDone = false;
    mProgress = 0;
    unscheduleSelf(mEnterRunnable);
    unscheduleSelf(mExitRunnable);
    scheduleSelf(mEnterRunnable, SystemClock.uptimeMillis());
}

private Runnable mEnterRunnable = new Runnable() {
    @Override
    public void run() {
        mProgress = mProgress + mEnterIncrement;
        if (mProgress > 1) {
            onEnterDone();
            onEnterProgress(1);
            return;
        }

        float interpolation = mEnterInterpolator.getInterpolation(mProgress);
        onEnterProgress(interpolation);
        scheduleSelf(mEnterRunnable, SystemClock.uptimeMillis() + 16);
    }
};

private void onEnterDone() {
    mEnterDone = true;
    if (onTouchRelease)
        startExitRunnable();
}

private void onEnterProgress(float progress) {
    mRippleRadius = getProgressValue(mStartRadius, mEndRadius, progress);
    mRipplePointX = getProgressValue(mDonePointX, mCenterPointX, progress);
    mRipplePointY = getProgressValue(mDonePointY, mCenterPointY, progress);

    mBgAlpha = (int) getProgressValue(0, MAX_BG_ALPHA, progress);
    invalidateSelf();           //刷新界面
}

//启动退出动画
private void startExitRunnable() {
    mExitProgress = 0;
    unscheduleSelf(mEnterRunnable);
    unscheduleSelf(mExitRunnable);
    scheduleSelf(mExitRunnable, SystemClock.uptimeMillis());
}

private Runnable mExitRunnable = new Runnable() {
    @Override
    public void run() {
        if (!mEnterDone)return;  //判断进入动画是否进行中

        mExitProgress = mExitProgress + mExitIncrement;
        if (mExitProgress > 1) {
            onExitProgress(1);      //当mExitProgress > 1时,onExitProgress方法没有执行,所以在此处进行调用
            return;
        }

        float interpolation = mExitInterpolator.getInterpolation(mExitProgress);
        onExitProgress(interpolation);
        scheduleSelf(mExitRunnable, SystemClock.uptimeMillis() + 16);
    }
};

private void onExitProgress(float progress) {
    mBgAlpha = (int) getProgressValue(MAX_BG_ALPHA, 0, progress);
    mCircleAlpha = (int) getProgressValue(MAX_CIRCLE_ALPHA,0,progress);       //设置圆形的透明度,以达到变淡到消失过程
    invalidateSelf();           //刷新界面
}

private float getProgressValue(float start, float end, float progress) {
    return start + (end - start) * progress;
}

在draw方法中反向获取透明度,我们在知道两个透明度的时候反向推出第三个透明度。中学经常有这样的数学题目
/**
     * 反向获取透明度算法
     * @param preAlpha
     * @param bgAlpha
     * @return
     */
    private int getCircleAlpha(int preAlpha,int bgAlpha) {
        int dAlpha = preAlpha - bgAlpha;
        return (int) (dAlpha*255f/(255f-bgAlpha));
    }

大体上就是这样的,有兴趣试试吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值