Android实现点击Button产生水波纹效果

先上图,看看接下来我要向大家介绍的是个什么东西,如下图:

接下来要介绍的就是如何实现上述图中的波纹效果,这种效果如果大家没有体验过的话,可以看看百度手机卫士或者360手机卫士,里面的按钮点击效果都是这样的,另外Android 5.0以上的版本也出现了这种效果。不多说,下面聊聊具体的怎么实现。

首先大家看到的是三个button,水波纹的出现给我们的错觉是直接将波纹绘制在button上面的,但是这样能做到吗?首先button自己有background和src,如果把半透明的水波纹当作background或者src绘制到button上面,肯定是会损失button原有的样式的。可能有朋友猜想那就把水波纹绘制在屏幕上呗,恭喜这位朋友答对了,至少我是这么干的,具体思路就是,我们自己实现一个layout,在layout中捕捉事件,并对事件进行相应的处理,在down事件中寻找当前用户点击的是哪个view,找出view所在的矩形区域,将一个透明的圆环绘制到这个矩形区域,在up事件中,延时分发view的onclick事件。

  • 1、自己实现一个layout:
  • 2、重写layout的dispatchTouchEvent方法,在down事件中找出被点击的view。
  public View findTargetView(float x, float y, View anchorView) {
    ArrayList<View> touchablesView = anchorView.getTouchables();
    View targetView = null;
    for (View child : touchablesView) {
      RectF rectF = getViewRectF(child);
      if (rectF.contains(x, y) && child.isClickable()) {
        // 这说明被点击的view找到了
        targetView = child;
        break;
      }
    }
    return targetView;
  }

接着找出view所在的矩形区域,因为要将波纹绘制到该区域:

  public RectF getViewRectF(View view) {
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    int childLeft = location[0];
    int childTop = location[1];
    int childRight = childLeft + view.getMeasuredWidth();
    int childBottom = childTop + view.getMeasuredHeight();
    return new RectF(childLeft, childTop, childRight, childBottom);
  }

矩形区域找到之后,这个区域就是我们要绘制的博波纹所在地,上面也说过了,波纹其实就是圆环,绘制圆的画是需要知道圆心坐标和圆的半径,圆心坐标肯定就是down时候的x和y了,但是半径怎么计算合适?大家看到上面的图知道如果view的宽度大于高度,点击view的左下角或者右下角,那么半径基本上就是等于view的宽度,点击view的上部或者下部分,半径就是在0和view的高度之间,具体的计算方式看下图:

那么根据上图,半径的计算方式就应该是:

  float left = circleCenterX - targetTouchRectF.left;
  float right = targetTouchRectF.right - circleCenterX;
  float top = circleCenterY - targetTouchRectF.top;
  float bottom = targetTouchRectF.bottom - circleCenterY;
  // 计算出最大的值则为半径
  rawRadius = Math.max(bottom, Math.max(Math.max(left, right), top));

半径算出来了,虽说圆心就是down时的x和y,但是有个地方还是需要注意的,在绘制圆环的时候提供的圆心坐标的x和y是在本文中是相对于layout的,所以在计算y的时候是需要进行一定处理的:

  /**
   * 获取圆环的中心坐标
   */
  public float[] getCircleCenterPostion(float x,float y){
    int[] location = new int[2];
    float[] mDownPositon = new float[2];
    getLocationOnScreen(location );
    mDownPositon[0] = x;
    mDownPositon[1] = y -location[1];
    return mDownPositon;
  }

圆心坐标和半径都计算好了,记下来就可以绘制圆形波纹了,那么在哪里绘制这个波纹比较合适呢?有朋友立马就说肯定是在onDraw方法里面绘制了,那么恭喜你在我看来你是答错了,我们的layout中是很有很多childview的,而layout是个viewGroup,viewGroup在绘制的时候,是先绘制自身的背景,再绘制自身,再绘制childview,如果在onDraw中绘制波纹,也就意味者后面绘制出来的childView会将我们的波纹遮盖,所以我们就应该等到childview绘制完毕后再来绘制波纹,这样可以保证childview在最顶层。
重写dispatchDraw方法:

  @Override
  protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
    /**
     * 绘制完子元素后开始绘制波纹
     */
    if (mTargetTouchView != null) {
      RectF clipRectF = clipRectF(mTargetTouchView);
      canvas.save();
      // 为了不让绘制的圆环超出所要绘制的范围
      canvas.clipRect(clipRectF);
      if(drawedRadius < rawRadius){
        drawedRadius += rawRadius / drawingRadiusDegrees;
        canvas.drawCircle(mDownPositon[0], mDownPositon[1], drawedRadius, mHalfTransPaint);
        postInvalidateDelayed(INVALID_DURATION);
      }else{
        canvas.drawCircle(mDownPositon[0], mDownPositon[1], rawRadius, mTransPaint);
        post(delayedRunnable);
      }
      canvas.restore();
    }
  }

在分发绘制事件中大家可以看到,波纹是一段一段的绘制,形如下图:

而这一段段的波纹正是通过绘制一个个的圆环实现的,所以在没绘制完毕一个圆环的时候,都需要延时重新绘制下一个圆环。
通过上面波纹效果基本上完成了,但是按钮是有点击事件的,像360手机卫士或者百度手机卫士等都是等波纹效果播放完毕后才会响应点击事件,所以我们这里也要对这个点击事件进行延时响应。
在up事件中,记录此次事件的event,并且返回true,表示消费此次的事件,然后再圆环绘制完毕后,再利用找到的view去分发这个event:

  if (ev.getAction() == MotionEvent.ACTION_UP) {
      // 需要让波纹绘制完毕后再执行在up中执行的方法
//     if(drawedRadius==0){
//       return false;
//     }
//     long totalTime = (long) (INVALID_DURATION * (drawingRadiusDegrees+5));
//     // 离波纹结束的时间
//     long time = (long) (totalTime - drawedRadius*totalTime / rawRadius);
      delayedRunnable.event = ev;
      return true;
  }

  class postUpEventDelayed implements Runnable{
    private MotionEvent event;
    @Override
    public void run() {
      if(mTargetTouchView!=null && mTargetTouchView.isClickable()
          && event!=null){
        mTargetTouchView.dispatchTouchEvent(event);// 分发
      }
    }
  }

在dispatchDraw方法中,判断如果绘制完毕就post(delayedRunnable);执行childView的事件延时分发。

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

(0)

相关推荐

  • Android仿水波纹流量球进度条控制器

    仿水波纹流球进度条控制器,Android实现高端大气的主流特效,供大家参考,具体内容如下 效果图: CircleView 这里主要是实现中心圆以及水波特效 package com.lgl.circleview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.gra

  • Android实现兼容的水波纹效果

    先看看效果图 其实,要实现这一效果很简单,只要分drawable和drawablev21两个文件夹就好了. 普通情况下的selector: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@c

  • Android实现水波纹效果

    一.效果 点击开始: 点击停止: 二.在MainActivity中 import android.graphics.Paint; import android.os.Bundle; import android.support.v4.view.animation.LinearOutSlowInInterpolator; import android.support.v7.app.AppCompatActivity; import android.view.View; import android

  • Android项目实战手把手教你画圆形水波纹loadingview

    本文实例讲解的是如何画一个满满圆形水波纹loadingview,这类效果应用场景很多,比如内存占用百分比之类的,分享给大家供大家参考,具体内容如下 效果图如下: 预备的知识: 1.贝塞尔曲线    如果你不了解,可以来这里进行基础知识储备:神奇的贝塞尔曲线 2.Paint.setXfermode()  以及PorterDuffXfermode 千万不要被这个b的名字吓到,不熟悉看到可能会认为很难记,其实 只要站在巨人的丁丁上 还是很简单的. 好了 废话不多说 ,跟我一步步来做一个炫酷的view吧

  • Android特效之水波纹的实现

    前言 水波纹特效,想必大家或多或少见过,在我的印象中,大致有如下几种: 支付宝 "咻咻咻" 式 流量球 "荡漾" 式 真实的水波纹效果,基于Bitmap处理式 话不多说,先来看看效果: 填充式水波纹,间距相等 非填充式水波纹,间距相等 非填充式水波纹,间距不断变大 填充式水波纹,间距不断变小 想必大家已经知道基本的原理了,就是用Canvas来画嘛,但可不是简单的画哦,请往下看. 分析 这种类型的水波纹,其实无非就是画圆而已,在给定的矩形中,一个个圆由最小半径扩大到最

  • Android自定义WaveProgressView实现水波纹加载需求

    先看效果图: 你可以定义成你项目的logo图片,可以设置水波颜色.波长.波宽.字体大小.颜色.进度条的最大值,当前进度值,还可以设置波纹震动的快慢.当设置一个进度不变的时候,打开时还有一个动画填满的效果(比如第二个流量显示,这里图片没有截出这个效果). 源码地址 1. 如何使用 1.1 在布局文件中 添加自定义控件: <cn.fanrunqi.waveprogressview.WaveProgressView android:id="@+id/waveProgressbar" a

  • Android实现自定义华丽的水波纹效果

    先来看看效果 实现效果 模拟水波纹的效果:点击屏幕就有圆环出现,半径从小到大,透明度从大到小(0为透明) 实现思路 1.自定义类继承View. 2.定义每个圆环的实体类 Wave,并初始化绘制圆环的画笔的数据. 3.重写onTouchEvent方法,down时,获得坐标点,做为圆环圆心. 4.发送handler信息,对数据进行修改,刷新页面. 5.重写onDraw方法,绘制一个圆环. 1. 自定义类继承View 新建WaterWaveView2类继承View public class Water

  • Android 自定义view实现水波纹动画效果

    在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了,可千万别说不行,爷们儿怎么能说不行呢: 好了,为了让大家都能给妹纸们想要的,后面会逐渐分享一些比较比较不错的效果,目的只有一个,通过自定义view实现我们所能实现的动效: 今天主要分享水波纹效果: 1.标准正余弦水波纹: 2.非标准圆形液柱水波纹: 虽说都是水波纹,但两者在实现上差异是比较大的,一个

  • Android自定义View 实现水波纹动画引导效果

    一.实现效果图 二.实现代码 1.自定义view package com.czhappy.showintroduce.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Pat

  • Android自定义view实现水波纹进度球效果

    今天我们要实现的这个view没有太多交互性的view,所以就继承view. 自定义view的套路,套路很深 1.获取我们自定义属性attrs(可省略) 2.重写onMeasure方法,计算控件的宽和高 3.重写onDraw方法,绘制我们的控件 这么看来,自定义view的套路很清晰嘛. 我们看下今天的效果图,其中一个是放慢的效果(时间调的长) 我们按照套路来. 一.自定义属性 <declare-styleable name="WaveProgressView"> <at

随机推荐