• Android5.0以上的项目都会有的按钮点击特效--水波纹


    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <shape xmlns:android="http://schemas.android.com/apk/res/android">  
    3.     <solid android:color="@color/colorPrimary"/>  
    4.     <corners android:radius="10dp" />  
    5.     <padding android:left="20dp" android:top="20dp"  
    6.         android:right="20dp" android:bottom="20dp" />  
    7. </shape>  
    8.  

      原创 2016年01月06日 14:09:40

      下面是点击的效果

      这里写图片描述

      话说这种效果应该怎样实现呢,目前我是专门针对5.0以上系统建立一个文件夹drawable-v21,里面放置带有水波纹特效的点击效果: 
      写一个ripple标签,这个就是水波纹特效

      <?xml version="1.0" encoding="utf-8"?>
      <ripple xmlns:android="http://schemas.android.com/apk/res/android"
          android:color="#FF9e9e9e">
          <item android:drawable="@drawable/bg_nomal"/>
      </ripple>
      • 1
      • 2
      • 3
      • 4
      • 5

      color是点击水波纹的颜色,一般推荐FF9e9e9e; 
      如果这个点击效果需要默认的图片,就是drawable的内容了,这时color的颜色最好是drawable中颜色的加深色;

      对于5.0以下的版本就是设置一个相同的名字的点击效果就OK了,这样就可以在android5.0以上的按钮上添加酷炫的水波纹点击效果了

      1. import android.content.Context;  
      2. import android.content.res.TypedArray;  
      3. import android.graphics.Bitmap;  
      4. import android.graphics.Canvas;  
      5. import android.graphics.Color;  
      6. import android.graphics.Paint;  
      7. import android.graphics.PorterDuff;  
      8. import android.graphics.PorterDuffXfermode;  
      9. import android.graphics.Rect;  
      10. import android.os.Build;  
      11. import android.os.Handler;  
      12. import android.util.AttributeSet;  
      13. import android.view.GestureDetector;  
      14. import android.view.MotionEvent;  
      15. import android.view.animation.Animation;  
      16. import android.view.animation.ScaleAnimation;  
      17. import android.widget.AdapterView;  
      18. import android.widget.RelativeLayout;  
      19.   
      20. /**  
      21.  * Created by Administrator on 2016/5/3.  
      22.  */  
      23. public class RippleView extends RelativeLayout{  
      24.   
      25.     private int WIDTH;  
      26.     private int HEIGHT;  
      27.     private int frameRate = 10;  
      28.     private int rippleDuration = 400;  
      29.     private int rippleAlpha = 90;  
      30.     private Handler canvasHandler;  
      31.     private float radiusMax = 0;  
      32.     private boolean animationRunning = false;  
      33.     private int timer = 0;  
      34.     private int timerEmpty = 0;  
      35.     private int durationEmpty = -1;  
      36.     private float x = -1;  
      37.     private float y = -1;  
      38.     private int zoomDuration;  
      39.     private float zoomScale;  
      40.     private ScaleAnimation scaleAnimation;  
      41.     private Boolean hasToZoom;  
      42.     private Boolean isCentered;  
      43.     private Integer rippleType;  
      44.     private Paint paint;  
      45.     private Bitmap originBitmap;  
      46.     private int rippleColor;  
      47.     private int ripplePadding;  
      48.     private GestureDetector gestureDetector;  
      49.     private final Runnable runnable = new Runnable() {  
      50.         @Override  
      51.         public void run() {  
      52.             invalidate();  
      53.         }  
      54.     };  
      55.   
      56.     private OnRippleCompleteListener onCompletionListener;  
      57.   
      58.     public RippleView(Context context) {  
      59.         super(context);  
      60.     }  
      61.   
      62.     public RippleView(Context context, AttributeSet attrs) {  
      63.         super(context, attrs);  
      64.         init(context, attrs);  
      65.     }  
      66.   
      67.     public RippleView(Context context, AttributeSet attrs, int defStyle) {  
      68.         super(context, attrs, defStyle);  
      69.         init(context, attrs);  
      70.     }  
      71.   
      72.     /**  
      73.      * Method that initializes all fields and sets listeners  
      74.      *  
      75.      * @param context Context used to create this view  
      76.      * @param attrs Attribute used to initialize fields  
      77.      */  
      78.     private void init(final Context context, final AttributeSet attrs) {  
      79.         if (isInEditMode())  
      80.             return;  
      81.   
      82.         final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleView);  
      83.         rippleColor = typedArray.getColor(R.styleable.RippleView_rv_color, getResources().getColor(R.color.rippelColor));  
      84.         rippleType = typedArray.getInt(R.styleable.RippleView_rv_type, 0);  
      85.         hasToZoom = typedArray.getBoolean(R.styleable.RippleView_rv_zoom, false);  
      86.         isCentered = typedArray.getBoolean(R.styleable.RippleView_rv_centered, false);  
      87.         rippleDuration = typedArray.getInteger(R.styleable.RippleView_rv_rippleDuration, rippleDuration);  
      88.         frameRate = typedArray.getInteger(R.styleable.RippleView_rv_framerate, frameRate);  
      89.         rippleAlpha = typedArray.getInteger(R.styleable.RippleView_rv_alpha, rippleAlpha);  
      90.         ripplePadding = typedArray.getDimensionPixelSize(R.styleable.RippleView_rv_ripplePadding, 0);  
      91.         canvasHandler = new Handler();  
      92.         zoomScale = typedArray.getFloat(R.styleable.RippleView_rv_zoomScale, 1.03f);  
      93.         zoomDuration = typedArray.getInt(R.styleable.RippleView_rv_zoomDuration, 200);  
      94.         typedArray.recycle();  
      95.         paint = new Paint();  
      96.         paint.setAntiAlias(true);  
      97.         paint.setStyle(Paint.Style.FILL_AND_STROKE);  
      98.         paint.setColor(rippleColor);  
      99.         paint.setAlpha(rippleAlpha);  
      100.         this.setWillNotDraw(false);  
      101.   
      102.         gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {  
      103.             @Override  
      104.             public void onLongPress(MotionEvent event) {  
      105.                 super.onLongPress(event);  
      106.                 animateRipple(event);  
      107.                 sendClickEvent(true);  
      108.             }  
      109.   
      110.             @Override  
      111.             public boolean onSingleTapConfirmed(MotionEvent e) {  
      112.                 return true;  
      113.             }  
      114.   
      115.             @Override  
      116.             public boolean onSingleTapUp(MotionEvent e) {  
      117.                 return true;  
      118.             }  
      119.         });  
      120.   
      121.         this.setDrawingCacheEnabled(true);  
      122.         this.setClickable(true);  
      123.     }  
      124.   
      125.     @Override  
      126.     public void draw(Canvas canvas) {  
      127.         super.draw(canvas);  
      128.         if (animationRunning) {  
      129.             canvas.save();  
      130.             if (rippleDuration <= timer * frameRate) {  
      131.                 animationRunning = false;  
      132.                 timer = 0;  
      133.                 durationEmpty = -1;  
      134.                 timerEmpty = 0;  
      135.                 // There is problem on Android M where canvas.restore() seems to be called automatically  
      136.                 // For now, don't call canvas.restore() manually on Android M (API 23)  
      137.                 if(Build.VERSION.SDK_INT != 23) {  
      138.                     canvas.restore();  
      139.                 }  
      140.                 invalidate();  
      141.                 if (onCompletionListener != null) onCompletionListener.onComplete(this);  
      142.                 return;  
      143.             } else  
      144.                 canvasHandler.postDelayed(runnable, frameRate);  
      145.   
      146.             if (timer == 0)  
      147.                 canvas.save();  
      148.   
      149.   
      150.             canvas.drawCircle(x, y, (radiusMax * (((float) timer * frameRate) / rippleDuration)), paint);  
      151.   
      152.             paint.setColor(Color.parseColor("#ffff4444"));  
      153.   
      154.             if (rippleType == 1 && originBitmap != null && (((float) timer * frameRate) / rippleDuration) > 0.4f) {  
      155.                 if (durationEmpty == -1)  
      156.                     durationEmpty = rippleDuration - timer * frameRate;  
      157.   
      158.                 timerEmpty++;  
      159.                 final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * frameRate) / (durationEmpty))));  
      160.                 canvas.drawBitmap(tmpBitmap, 0, 0, paint);  
      161.                 tmpBitmap.recycle();  
      162.             }  
      163.   
      164.             paint.setColor(rippleColor);  
      165.   
      166.             if (rippleType == 1) {  
      167.                 if ((((float) timer * frameRate) / rippleDuration) > 0.6f)  
      168.                     paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timerEmpty * frameRate) / (durationEmpty)))));  
      169.                 else  
      170.                     paint.setAlpha(rippleAlpha);  
      171.             }  
      172.             else  
      173.                 paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timer * frameRate) / rippleDuration))));  
      174.   
      175.             timer++;  
      176.         }  
      177.     }  
      178.   
      179.     @Override  
      180.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
      181.         super.onSizeChanged(w, h, oldw, oldh);  
      182.         WIDTH = w;  
      183.         HEIGHT = h;  
      184.   
      185.         scaleAnimation = new ScaleAnimation(1.0f, zoomScale, 1.0f, zoomScale, w / 2, h / 2);  
      186.         scaleAnimation.setDuration(zoomDuration);  
      187.         scaleAnimation.setRepeatMode(Animation.REVERSE);  
      188.         scaleAnimation.setRepeatCount(1);  
      189.     }  
      190.   
      191.     /**  
      192.      * Launch Ripple animation for the current view with a MotionEvent  
      193.      *  
      194.      * @param event MotionEvent registered by the Ripple gesture listener  
      195.      */  
      196.     public void animateRipple(MotionEvent event) {  
      197.         createAnimation(event.getX(), event.getY());  
      198.     }  
      199.   
      200.     /**  
      201.      * Launch Ripple animation for the current view centered at x and y position  
      202.      *  
      203.      * @param x Horizontal position of the ripple center  
      204.      * @param y Vertical position of the ripple center  
      205.      */  
      206.     public void animateRipple(final float x, final float y) {  
      207.         createAnimation(x, y);  
      208.     }  
      209.   
      210.     /**  
      211.      * Create Ripple animation centered at x, y  
      212.      *  
      213.      * @param x Horizontal position of the ripple center  
      214.      * @param y Vertical position of the ripple center  
      215.      */  
      216.     private void createAnimation(final float x, final float y) {  
      217.         if (this.isEnabled() && !animationRunning) {  
      218.             if (hasToZoom)  
      219.                 this.startAnimation(scaleAnimation);  
      220.   
      221.             radiusMax = Math.max(WIDTH, HEIGHT);  
      222.   
      223.             if (rippleType != 2)  
      224.                 radiusMax /= 2;  
      225.   
      226.             radiusMax -ripplePadding;  
      227.   
      228.             if (isCentered || rippleType == 1) {  
      229.                 this.x = getMeasuredWidth() / 2;  
      230.                 this.y = getMeasuredHeight() / 2;  
      231.             } else {  
      232.                 this.x = x;  
      233.                 this.y = y;  
      234.             }  
      235.   
      236.             animationRunning = true;  
      237.   
      238.             if (rippleType == 1 && originBitmap == null)  
      239.                 originBitmap = getDrawingCache(true);  
      240.   
      241.             invalidate();  
      242.         }  
      243.     }  
      244.   
      245.     @Override  
      246.     public boolean onTouchEvent(MotionEvent event) {  
      247.         if (gestureDetector.onTouchEvent(event)) {  
      248.             animateRipple(event);  
      249.             sendClickEvent(false);  
      250.         }  
      251.         return super.onTouchEvent(event);  
      252.     }  
      253.   
      254.     @Override  
      255.     public boolean onInterceptTouchEvent(MotionEvent event) {  
      256.         this.onTouchEvent(event);  
      257.         return super.onInterceptTouchEvent(event);  
      258.     }  
      259.   
      260.     /**  
      261.      * Send a click event if parent view is a Listview instance  
      262.      *  
      263.      * @param isLongClick Is the event a long click ?  
      264.      */  
      265.     private void sendClickEvent(final Boolean isLongClick) {  
      266.         if (getParent() instanceof AdapterView) {  
      267.             final AdapterView adapterView = (AdapterView) getParent();  
      268.             final int position = adapterView.getPositionForView(this);  
      269.             final long id = adapterView.getItemIdAtPosition(position);  
      270.             if (isLongClick) {  
      271.                 if (adapterView.getOnItemLongClickListener() != null)  
      272.                     adapterView.getOnItemLongClickListener().onItemLongClick(adapterView, this, position, id);  
      273.             } else {  
      274.                 if (adapterView.getOnItemClickListener() != null)  
      275.                     adapterView.getOnItemClickListener().onItemClick(adapterView, this, position, id);  
      276.             }  
      277.         }  
      278.     }  
      279.   
      280.     private Bitmap getCircleBitmap(final int radius) {  
      281.         final Bitmap output = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);  
      282.         final Canvas canvas = new Canvas(output);  
      283.         final Paint paint = new Paint();  
      284.         final Rect rect = new Rect((int)(x - radius), (int)(y - radius), (int)(x + radius), (int)(y + radius));  
      285.   
      286.         paint.setAntiAlias(true);  
      287.         canvas.drawARGB(0, 0, 0, 0);  
      288.         canvas.drawCircle(x, y, radius, paint);  
      289.   
      290.         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));  
      291.         canvas.drawBitmap(originBitmap, rect, rect, paint);  
      292.   
      293.         return output;  
      294.     }  
      295.   
      296.     /**  
      297.      * Set Ripple color, default is #FFFFFF  
      298.      *  
      299.      * @param rippleColor New color resource  
      300.      */  
      301.      
      302.     public void setRippleColor(int rippleColor) {  
      303.         this.rippleColor = getResources().getColor(rippleColor);  
      304.     }  
      305.   
      306.     public int getRippleColor() {  
      307.         return rippleColor;  
      308.     }  
      309.   
      310.     public RippleType getRippleType()  
      311.     {  
      312.         return RippleType.values()[rippleType];  
      313.     }  
      314.   
      315.     /**  
      316.      * Set Ripple type, default is RippleType.SIMPLE  
      317.      *  
      318.      * @param rippleType New Ripple type for next animation  
      319.      */  
      320.     public void setRippleType(final RippleType rippleType)  
      321.     {  
      322.         this.rippleType = rippleType.ordinal();  
      323.     }  
      324.   
      325.     public Boolean isCentered()  
      326.     {  
      327.         return isCentered;  
      328.     }  
      329.   
      330.     /**  
      331.      * Set if ripple animation has to be centered in its parent view or not, default is False  
      332.      *  
      333.      * @param isCentered  
      334.      */  
      335.     public void setCentered(final Boolean isCentered)  
      336.     {  
      337.         this.isCentered = isCentered;  
      338.     }  
      339.   
      340.     public int getRipplePadding()  
      341.     {  
      342.         return ripplePadding;  
      343.     }  
      344.   
      345.     /**  
      346.      * Set Ripple padding if you want to avoid some graphic glitch  
      347.      *  
      348.      * @param ripplePadding New Ripple padding in pixel, default is 0px  
      349.      */  
      350.     public void setRipplePadding(int ripplePadding)  
      351.     {  
      352.         this.ripplePadding = ripplePadding;  
      353.     }  
      354.   
      355.     public Boolean isZooming()  
      356.     {  
      357.         return hasToZoom;  
      358.     }  
      359.   
      360.     /**  
      361.      * At the end of Ripple effect, the child views has to zoom  
      362.      *  
      363.      * @param hasToZoom Do the child views have to zoom ? default is False  
      364.      */  
      365.     public void setZooming(Boolean hasToZoom)  
      366.     {  
      367.         this.hasToZoom = hasToZoom;  
      368.     }  
      369.   
      370.     public float getZoomScale()  
      371.     {  
      372.         return zoomScale;  
      373.     }  
      374.   
      375.     /**  
      376.      * Scale of the end animation  
      377.      *  
      378.      * @param zoomScale Value of scale animation, default is 1.03f  
      379.      */  
      380.     public void setZoomScale(float zoomScale)  
      381.     {  
      382.         this.zoomScale = zoomScale;  
      383.     }  
      384.   
      385.     public int getZoomDuration()  
      386.     {  
      387.         return zoomDuration;  
      388.     }  
      389.   
      390.     /**  
      391.      * Duration of the ending animation in ms  
      392.      *  
      393.      * @param zoomDuration Duration, default is 200ms  
      394.      */  
      395.     public void setZoomDuration(int zoomDuration)  
      396.     {  
      397.         this.zoomDuration = zoomDuration;  
      398.     }  
      399.   
      400.     public int getRippleDuration()  
      401.     {  
      402.         return rippleDuration;  
      403.     }  
      404.   
      405.     /**  
      406.      * Duration of the Ripple animation in ms  
      407.      *  
      408.      * @param rippleDuration Duration, default is 400ms  
      409.      */  
      410.     public void setRippleDuration(int rippleDuration)  
      411.     {  
      412.         this.rippleDuration = rippleDuration;  
      413.     }  
      414.   
      415.     public int getFrameRate()  
      416.     {  
      417.         return frameRate;  
      418.     }  
      419.   
      420.     /**  
      421.      * Set framerate for Ripple animation  
      422.      *  
      423.      * @param frameRate New framerate value, default is 10  
      424.      */  
      425.     public void setFrameRate(int frameRate)  
      426.     {  
      427.         this.frameRate = frameRate;  
      428.     }  
      429.   
      430.     public int getRippleAlpha()  
      431.     {  
      432.         return rippleAlpha;  
      433.     }  
      434.   
      435.     /**  
      436.      * Set alpha for ripple effect color  
      437.      *  
      438.      * @param rippleAlpha Alpha value between 0 and 255, default is 90  
      439.      */  
      440.     public void setRippleAlpha(int rippleAlpha)  
      441.     {  
      442.         this.rippleAlpha = rippleAlpha;  
      443.     }  
      444.   
      445.     public void setOnRippleCompleteListener(OnRippleCompleteListener listener) {  
      446.         this.onCompletionListener = listener;  
      447.     }  
      448.   
      449.     /**  
      450.      * Defines a callback called at the end of the Ripple effect  
      451.      */  
      452.     public interface OnRippleCompleteListener {  
      453.         void onComplete(RippleView rippleView);  
      454.     }  
      455.   
      456.     public enum RippleType {  
      457.         SIMPLE(0),  
      458.         DOUBLE(1),  
      459.         RECTANGLE(2);  
      460.   
      461.         int type;  
      462.   
      463.         RippleType(int type)  
      464.         {  
      465.             this.type = type;  
      466.         }  
      467.     }  
      468. }  
    1.  
    2. import android.content.Context;  
    3. import android.content.res.TypedArray;  
    4. import android.graphics.Bitmap;  
    5. import android.graphics.Canvas;  
    6. import android.graphics.Color;  
    7. import android.graphics.Paint;  
    8. import android.graphics.PorterDuff;  
    9. import android.graphics.PorterDuffXfermode;  
    10. import android.graphics.Rect;  
    11. import android.os.Build;  
    12. import android.os.Handler;  
    13. import android.util.AttributeSet;  
    14. import android.view.GestureDetector;  
    15. import android.view.MotionEvent;  
    16. import android.view.animation.Animation;  
    17. import android.view.animation.ScaleAnimation;  
    18. import android.widget.AdapterView;  
    19. import android.widget.RelativeLayout;  
    20.   
    21. /**  
    22.  * Created by Administrator on 2016/5/3.  
    23.  */  
    24. public class RippleView extends RelativeLayout{  
    25.   
    26.     private int WIDTH;  
    27.     private int HEIGHT;  
    28.     private int frameRate = 10;  
    29.     private int rippleDuration = 400;  
    30.     private int rippleAlpha = 90;  
    31.     private Handler canvasHandler;  
    32.     private float radiusMax = 0;  
    33.     private boolean animationRunning = false;  
    34.     private int timer = 0;  
    35.     private int timerEmpty = 0;  
    36.     private int durationEmpty = -1;  
    37.     private float x = -1;  
    38.     private float y = -1;  
    39.     private int zoomDuration;  
    40.     private float zoomScale;  
    41.     private ScaleAnimation scaleAnimation;  
    42.     private Boolean hasToZoom;  
    43.     private Boolean isCentered;  
    44.     private Integer rippleType;  
    45.     private Paint paint;  
    46.     private Bitmap originBitmap;  
    47.     private int rippleColor;  
    48.     private int ripplePadding;  
    49.     private GestureDetector gestureDetector;  
    50.     private final Runnable runnable = new Runnable() {  
    51.         @Override  
    52.         public void run() {  
    53.             invalidate();  
    54.         }  
    55.     };  
    56.   
    57.     private OnRippleCompleteListener onCompletionListener;  
    58.   
    59.     public RippleView(Context context) {  
    60.         super(context);  
    61.     }  
    62.   
    63.     public RippleView(Context context, AttributeSet attrs) {  
    64.         super(context, attrs);  
    65.         init(context, attrs);  
    66.     }  
    67.   
    68.     public RippleView(Context context, AttributeSet attrs, int defStyle) {  
    69.         super(context, attrs, defStyle);  
    70.         init(context, attrs);  
    71.     }  
    72.   
    73.     /**  
    74.      * Method that initializes all fields and sets listeners  
    75.      *  
    76.      * @param context Context used to create this view  
    77.      * @param attrs Attribute used to initialize fields  
    78.      */  
    79.     private void init(final Context context, final AttributeSet attrs) {  
    80.         if (isInEditMode())  
    81.             return;  
    82.   
    83.         final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleView);  
    84.         rippleColor = typedArray.getColor(R.styleable.RippleView_rv_color, getResources().getColor(R.color.rippelColor));  
    85.         rippleType = typedArray.getInt(R.styleable.RippleView_rv_type, 0);  
    86.         hasToZoom = typedArray.getBoolean(R.styleable.RippleView_rv_zoom, false);  
    87.         isCentered = typedArray.getBoolean(R.styleable.RippleView_rv_centered, false);  
    88.         rippleDuration = typedArray.getInteger(R.styleable.RippleView_rv_rippleDuration, rippleDuration);  
    89.         frameRate = typedArray.getInteger(R.styleable.RippleView_rv_framerate, frameRate);  
    90.         rippleAlpha = typedArray.getInteger(R.styleable.RippleView_rv_alpha, rippleAlpha);  
    91.         ripplePadding = typedArray.getDimensionPixelSize(R.styleable.RippleView_rv_ripplePadding, 0);  
    92.         canvasHandler = new Handler();  
    93.         zoomScale = typedArray.getFloat(R.styleable.RippleView_rv_zoomScale, 1.03f);  
    94.         zoomDuration = typedArray.getInt(R.styleable.RippleView_rv_zoomDuration, 200);  
    95.         typedArray.recycle();  
    96.         paint = new Paint();  
    97.         paint.setAntiAlias(true);  
    98.         paint.setStyle(Paint.Style.FILL_AND_STROKE);  
    99.         paint.setColor(rippleColor);  
    100.         paint.setAlpha(rippleAlpha);  
    101.         this.setWillNotDraw(false);  
    102.   
    103.         gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {  
    104.             @Override  
    105.             public void onLongPress(MotionEvent event) {  
    106.                 super.onLongPress(event);  
    107.                 animateRipple(event);  
    108.                 sendClickEvent(true);  
    109.             }  
    110.   
    111.             @Override  
    112.             public boolean onSingleTapConfirmed(MotionEvent e) {  
    113.                 return true;  
    114.             }  
    115.   
    116.             @Override  
    117.             public boolean onSingleTapUp(MotionEvent e) {  
    118.                 return true;  
    119.             }  
    120.         });  
    121.   
    122.         this.setDrawingCacheEnabled(true);  
    123.         this.setClickable(true);  
    124.     }  
    125.   
    126.     @Override  
    127.     public void draw(Canvas canvas) {  
    128.         super.draw(canvas);  
    129.         if (animationRunning) {  
    130.             canvas.save();  
    131.             if (rippleDuration <= timer * frameRate) {  
    132.                 animationRunning = false;  
    133.                 timer = 0;  
    134.                 durationEmpty = -1;  
    135.                 timerEmpty = 0;  
    136.                 // There is problem on Android M where canvas.restore() seems to be called automatically  
    137.                 // For now, don't call canvas.restore() manually on Android M (API 23)  
    138.                 if(Build.VERSION.SDK_INT != 23) {  
    139.                     canvas.restore();  
    140.                 }  
    141.                 invalidate();  
    142.                 if (onCompletionListener != null) onCompletionListener.onComplete(this);  
    143.                 return;  
    144.             } else  
    145.                 canvasHandler.postDelayed(runnable, frameRate);  
    146.   
    147.             if (timer == 0)  
    148.                 canvas.save();  
    149.   
    150.   
    151.             canvas.drawCircle(x, y, (radiusMax * (((float) timer * frameRate) / rippleDuration)), paint);  
    152.   
    153.             paint.setColor(Color.parseColor("#ffff4444"));  
    154.   
    155.             if (rippleType == 1 && originBitmap != null && (((float) timer * frameRate) / rippleDuration) > 0.4f) {  
    156.                 if (durationEmpty == -1)  
    157.                     durationEmpty = rippleDuration - timer * frameRate;  
    158.   
    159.                 timerEmpty++;  
    160.                 final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * frameRate) / (durationEmpty))));  
    161.                 canvas.drawBitmap(tmpBitmap, 0, 0, paint);  
    162.                 tmpBitmap.recycle();  
    163.             }  
    164.   
    165.             paint.setColor(rippleColor);  
    166.   
    167.             if (rippleType == 1) {  
    168.                 if ((((float) timer * frameRate) / rippleDuration) > 0.6f)  
    169.                     paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timerEmpty * frameRate) / (durationEmpty)))));  
    170.                 else  
    171.                     paint.setAlpha(rippleAlpha);  
    172.             }  
    173.             else  
    174.                 paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timer * frameRate) / rippleDuration))));  
    175.   
    176.             timer++;  
    177.         }  
    178.     }  
    179.   
    180.     @Override  
    181.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
    182.         super.onSizeChanged(w, h, oldw, oldh);  
    183.         WIDTH = w;  
    184.         HEIGHT = h;  
    185.   
    186.         scaleAnimation = new ScaleAnimation(1.0f, zoomScale, 1.0f, zoomScale, w / 2, h / 2);  
    187.         scaleAnimation.setDuration(zoomDuration);  
    188.         scaleAnimation.setRepeatMode(Animation.REVERSE);  
    189.         scaleAnimation.setRepeatCount(1);  
    190.     }  
    191.   
    192.     /**  
    193.      * Launch Ripple animation for the current view with a MotionEvent  
    194.      *  
    195.      * @param event MotionEvent registered by the Ripple gesture listener  
    196.      */  
    197.     public void animateRipple(MotionEvent event) {  
    198.         createAnimation(event.getX(), event.getY());  
    199.     }  
    200.   
    201.     /**  
    202.      * Launch Ripple animation for the current view centered at x and y position  
    203.      *  
    204.      * @param x Horizontal position of the ripple center  
    205.      * @param y Vertical position of the ripple center  
    206.      */  
    207.     public void animateRipple(final float x, final float y) {  
    208.         createAnimation(x, y);  
    209.     }  
    210.   
    211.     /**  
    212.      * Create Ripple animation centered at x, y  
    213.      *  
    214.      * @param x Horizontal position of the ripple center  
    215.      * @param y Vertical position of the ripple center  
    216.      */  
    217.     private void createAnimation(final float x, final float y) {  
    218.         if (this.isEnabled() && !animationRunning) {  
    219.             if (hasToZoom)  
    220.                 this.startAnimation(scaleAnimation);  
    221.   
    222.             radiusMax = Math.max(WIDTH, HEIGHT);  
    223.   
    224.             if (rippleType != 2)  
    225.                 radiusMax /= 2;  
    226.   
    227.             radiusMax -ripplePadding;  
    228.   
    229.             if (isCentered || rippleType == 1) {  
    230.                 this.x = getMeasuredWidth() / 2;  
    231.                 this.y = getMeasuredHeight() / 2;  
    232.             } else {  
    233.                 this.x = x;  
    234.                 this.y = y;  
    235.             }  
    236.   
    237.             animationRunning = true;  
    238.   
    239.             if (rippleType == 1 && originBitmap == null)  
    240.                 originBitmap = getDrawingCache(true);  
    241.   
    242.             invalidate();  
    243.         }  
    244.     }  
    245.   
    246.     @Override  
    247.     public boolean onTouchEvent(MotionEvent event) {  
    248.         if (gestureDetector.onTouchEvent(event)) {  
    249.             animateRipple(event);  
    250.             sendClickEvent(false);  
    251.         }  
    252.         return super.onTouchEvent(event);  
    253.     }  
    254.   
    255.     @Override  
    256.     public boolean onInterceptTouchEvent(MotionEvent event) {  
    257.         this.onTouchEvent(event);  
    258.         return super.onInterceptTouchEvent(event);  
    259.     }  
    260.   
    261.     /**  
    262.      * Send a click event if parent view is a Listview instance  
    263.      *  
    264.      * @param isLongClick Is the event a long click ?  
    265.      */  
    266.     private void sendClickEvent(final Boolean isLongClick) {  
    267.         if (getParent() instanceof AdapterView) {  
    268.             final AdapterView adapterView = (AdapterView) getParent();  
    269.             final int position = adapterView.getPositionForView(this);  
    270.             final long id = adapterView.getItemIdAtPosition(position);  
    271.             if (isLongClick) {  
    272.                 if (adapterView.getOnItemLongClickListener() != null)  
    273.                     adapterView.getOnItemLongClickListener().onItemLongClick(adapterView, this, position, id);  
    274.             } else {  
    275.                 if (adapterView.getOnItemClickListener() != null)  
    276.                     adapterView.getOnItemClickListener().onItemClick(adapterView, this, position, id);  
    277.             }  
    278.         }  
    279.     }  
    280.   
    281.     private Bitmap getCircleBitmap(final int radius) {  
    282.         final Bitmap output = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);  
    283.         final Canvas canvas = new Canvas(output);  
    284.         final Paint paint = new Paint();  
    285.         final Rect rect = new Rect((int)(x - radius), (int)(y - radius), (int)(x + radius), (int)(y + radius));  
    286.   
    287.         paint.setAntiAlias(true);  
    288.         canvas.drawARGB(0, 0, 0, 0);  
    289.         canvas.drawCircle(x, y, radius, paint);  
    290.   
    291.         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));  
    292.         canvas.drawBitmap(originBitmap, rect, rect, paint);  
    293.   
    294.         return output;  
    295.     }  
    296.   
    297.     /**  
    298.      * Set Ripple color, default is #FFFFFF  
    299.      *  
    300.      * @param rippleColor New color resource  
    301.      */  
    302.      
    303.     public void setRippleColor(int rippleColor) {  
    304.         this.rippleColor = getResources().getColor(rippleColor);  
    305.     }  
    306.   
    307.     public int getRippleColor() {  
    308.         return rippleColor;  
    309.     }  
    310.   
    311.     public RippleType getRippleType()  
    312.     {  
    313.         return RippleType.values()[rippleType];  
    314.     }  
    315.   
    316.     /**  
    317.      * Set Ripple type, default is RippleType.SIMPLE  
    318.      *  
    319.      * @param rippleType New Ripple type for next animation  
    320.      */  
    321.     public void setRippleType(final RippleType rippleType)  
    322.     {  
    323.         this.rippleType = rippleType.ordinal();  
    324.     }  
    325.   
    326.     public Boolean isCentered()  
    327.     {  
    328.         return isCentered;  
    329.     }  
    330.   
    331.     /**  
    332.      * Set if ripple animation has to be centered in its parent view or not, default is False  
    333.      *  
    334.      * @param isCentered  
    335.      */  
    336.     public void setCentered(final Boolean isCentered)  
    337.     {  
    338.         this.isCentered = isCentered;  
    339.     }  
    340.   
    341.     public int getRipplePadding()  
    342.     {  
    343.         return ripplePadding;  
    344.     }  
    345.   
    346.     /**  
    347.      * Set Ripple padding if you want to avoid some graphic glitch  
    348.      *  
    349.      * @param ripplePadding New Ripple padding in pixel, default is 0px  
    350.      */  
    351.     public void setRipplePadding(int ripplePadding)  
    352.     {  
    353.         this.ripplePadding = ripplePadding;  
    354.     }  
    355.   
    356.     public Boolean isZooming()  
    357.     {  
    358.         return hasToZoom;  
    359.     }  
    360.   
    361.     /**  
    362.      * At the end of Ripple effect, the child views has to zoom  
    363.      *  
    364.      * @param hasToZoom Do the child views have to zoom ? default is False  
    365.      */  
    366.     public void setZooming(Boolean hasToZoom)  
    367.     {  
    368.         this.hasToZoom = hasToZoom;  
    369.     }  
    370.   
    371.     public float getZoomScale()  
    372.     {  
    373.         return zoomScale;  
    374.     }  
    375.   
    376.     /**  
    377.      * Scale of the end animation  
    378.      *  
    379.      * @param zoomScale Value of scale animation, default is 1.03f  
    380.      */  
    381.     public void setZoomScale(float zoomScale)  
    382.     {  
    383.         this.zoomScale = zoomScale;  
    384.     }  
    385.   
    386.     public int getZoomDuration()  
    387.     {  
    388.         return zoomDuration;  
    389.     }  
    390.   
    391.     /**  
    392.      * Duration of the ending animation in ms  
    393.      *  
    394.      * @param zoomDuration Duration, default is 200ms  
    395.      */  
    396.     public void setZoomDuration(int zoomDuration)  
    397.     {  
    398.         this.zoomDuration = zoomDuration;  
    399.     }  
    400.   
    401.     public int getRippleDuration()  
    402.     {  
    403.         return rippleDuration;  
    404.     }  
    405.   
    406.     /**  
    407.      * Duration of the Ripple animation in ms  
    408.      *  
    409.      * @param rippleDuration Duration, default is 400ms  
    410.      */  
    411.     public void setRippleDuration(int rippleDuration)  
    412.     {  
    413.         this.rippleDuration = rippleDuration;  
    414.     }  
    415.   
    416.     public int getFrameRate()  
    417.     {  
    418.         return frameRate;  
    419.     }  
    420.   
    421.     /**  
    422.      * Set framerate for Ripple animation  
    423.      *  
    424.      * @param frameRate New framerate value, default is 10  
    425.      */  
    426.     public void setFrameRate(int frameRate)  
    427.     {  
    428.         this.frameRate = frameRate;  
    429.     }  
    430.   
    431.     public int getRippleAlpha()  
    432.     {  
    433.         return rippleAlpha;  
    434.     }  
    435.   
    436.     /**  
    437.      * Set alpha for ripple effect color  
    438.      *  
    439.      * @param rippleAlpha Alpha value between 0 and 255, default is 90  
    440.      */  
    441.     public void setRippleAlpha(int rippleAlpha)  
    442.     {  
    443.         this.rippleAlpha = rippleAlpha;  
    444.     }  
    445.   
    446.     public void setOnRippleCompleteListener(OnRippleCompleteListener listener) {  
    447.         this.onCompletionListener = listener;  
    448.     }  
    449.   
    450.     /**  
    451.      * Defines a callback called at the end of the Ripple effect  
    452.      */  
    453.     public interface OnRippleCompleteListener {  
    454.         void onComplete(RippleView rippleView);  
    455.     }  
    456.   
    457.     public enum RippleType {  
    458.         SIMPLE(0),  
    459.         DOUBLE(1),  
    460.         RECTANGLE(2);  
    461.   
    462.         int type;  
    463.   
    464.         RippleType(int type)  
    465.         {  
    466.             this.type = type;  
    467.         }  
    468.     }  
    469. }  
  • 相关阅读:
    【转载】警情通报为啥一定是"蓝底白字"?
    我的英语词汇本
    【转载】随便说说字符集和编码
    JavaScript入门笔记
    JavaScript代码规范及其他注意事项
    编程的部分基础知识
    vc++ 6.0相关
    vue 定位
    mpvue 搭建命令
    uni-app 漫长学习之路
  • 原文地址:https://www.cnblogs.com/totoo/p/ripple.html
Copyright © 2020-2023  润新知