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
    • 2800

    下面是点击的效果

    话说这种效果应该怎样实现呢,目前我是专门针对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. * Created by Administrator on 2016/5/3.
    21. */
    22. public class RippleView extends RelativeLayout{
    23. private int WIDTH;
    24. private int HEIGHT;
    25. private int frameRate = 10;
    26. private int rippleDuration = 400;
    27. private int rippleAlpha = 90;
    28. private Handler canvasHandler;
    29. private float radiusMax = 0;
    30. private boolean animationRunning = false;
    31. private int timer = 0;
    32. private int timerEmpty = 0;
    33. private int durationEmpty = -1;
    34. private float x = -1;
    35. private float y = -1;
    36. private int zoomDuration;
    37. private float zoomScale;
    38. private ScaleAnimation scaleAnimation;
    39. private Boolean hasToZoom;
    40. private Boolean isCentered;
    41. private Integer rippleType;
    42. private Paint paint;
    43. private Bitmap originBitmap;
    44. private int rippleColor;
    45. private int ripplePadding;
    46. private GestureDetector gestureDetector;
    47. private final Runnable runnable = new Runnable() {
    48. @Override
    49. public void run() {
    50. invalidate();
    51. }
    52. };
    53. private OnRippleCompleteListener onCompletionListener;
    54. public RippleView(Context context) {
    55. super(context);
    56. }
    57. public RippleView(Context context, AttributeSet attrs) {
    58. super(context, attrs);
    59. init(context, attrs);
    60. }
    61. public RippleView(Context context, AttributeSet attrs, int defStyle) {
    62. super(context, attrs, defStyle);
    63. init(context, attrs);
    64. }
    65. /**
    66. * Method that initializes all fields and sets listeners
    67. *
    68. * @param context Context used to create this view
    69. * @param attrs Attribute used to initialize fields
    70. */
    71. private void init(final Context context, final AttributeSet attrs) {
    72. if (isInEditMode())
    73. return;
    74. final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleView);
    75. rippleColor = typedArray.getColor(R.styleable.RippleView_rv_color, getResources().getColor(R.color.rippelColor));
    76. rippleType = typedArray.getInt(R.styleable.RippleView_rv_type, 0);
    77. hasToZoom = typedArray.getBoolean(R.styleable.RippleView_rv_zoom, false);
    78. isCentered = typedArray.getBoolean(R.styleable.RippleView_rv_centered, false);
    79. rippleDuration = typedArray.getInteger(R.styleable.RippleView_rv_rippleDuration, rippleDuration);
    80. frameRate = typedArray.getInteger(R.styleable.RippleView_rv_framerate, frameRate);
    81. rippleAlpha = typedArray.getInteger(R.styleable.RippleView_rv_alpha, rippleAlpha);
    82. ripplePadding = typedArray.getDimensionPixelSize(R.styleable.RippleView_rv_ripplePadding, 0);
    83. canvasHandler = new Handler();
    84. zoomScale = typedArray.getFloat(R.styleable.RippleView_rv_zoomScale, 1.03f);
    85. zoomDuration = typedArray.getInt(R.styleable.RippleView_rv_zoomDuration, 200);
    86. typedArray.recycle();
    87. paint = new Paint();
    88. paint.setAntiAlias(true);
    89. paint.setStyle(Paint.Style.FILL_AND_STROKE);
    90. paint.setColor(rippleColor);
    91. paint.setAlpha(rippleAlpha);
    92. this.setWillNotDraw(false);
    93. gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
    94. @Override
    95. public void onLongPress(MotionEvent event) {
    96. super.onLongPress(event);
    97. animateRipple(event);
    98. sendClickEvent(true);
    99. }
    100. @Override
    101. public boolean onSingleTapConfirmed(MotionEvent e) {
    102. return true;
    103. }
    104. @Override
    105. public boolean onSingleTapUp(MotionEvent e) {
    106. return true;
    107. }
    108. });
    109. this.setDrawingCacheEnabled(true);
    110. this.setClickable(true);
    111. }
    112. @Override
    113. public void draw(Canvas canvas) {
    114. super.draw(canvas);
    115. if (animationRunning) {
    116. canvas.save();
    117. if (rippleDuration <= timer * frameRate) {
    118. animationRunning = false;
    119. timer = 0;
    120. durationEmpty = -1;
    121. timerEmpty = 0;
    122. // There is problem on Android M where canvas.restore() seems to be called automatically
    123. // For now, don't call canvas.restore() manually on Android M (API 23)
    124. if(Build.VERSION.SDK_INT != 23) {
    125. canvas.restore();
    126. }
    127. invalidate();
    128. if (onCompletionListener != null) onCompletionListener.onComplete(this);
    129. return;
    130. } else
    131. canvasHandler.postDelayed(runnable, frameRate);
    132. if (timer == 0)
    133. canvas.save();
    134. canvas.drawCircle(x, y, (radiusMax * (((float) timer * frameRate) / rippleDuration)), paint);
    135. paint.setColor(Color.parseColor("#ffff4444"));
    136. if (rippleType == 1 && originBitmap != null && (((float) timer * frameRate) / rippleDuration) > 0.4f) {
    137. if (durationEmpty == -1)
    138. durationEmpty = rippleDuration - timer * frameRate;
    139. timerEmpty++;
    140. final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * frameRate) / (durationEmpty))));
    141. canvas.drawBitmap(tmpBitmap, 0, 0, paint);
    142. tmpBitmap.recycle();
    143. }
    144. paint.setColor(rippleColor);
    145. if (rippleType == 1) {
    146. if ((((float) timer * frameRate) / rippleDuration) > 0.6f)
    147. paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timerEmpty * frameRate) / (durationEmpty)))));
    148. else
    149. paint.setAlpha(rippleAlpha);
    150. }
    151. else
    152. paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timer * frameRate) / rippleDuration))));
    153. timer++;
    154. }
    155. }
    156. @Override
    157. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    158. super.onSizeChanged(w, h, oldw, oldh);
    159. WIDTH = w;
    160. HEIGHT = h;
    161. scaleAnimation = new ScaleAnimation(1.0f, zoomScale, 1.0f, zoomScale, w / 2, h / 2);
    162. scaleAnimation.setDuration(zoomDuration);
    163. scaleAnimation.setRepeatMode(Animation.REVERSE);
    164. scaleAnimation.setRepeatCount(1);
    165. }
    166. /**
    167. * Launch Ripple animation for the current view with a MotionEvent
    168. *
    169. * @param event MotionEvent registered by the Ripple gesture listener
    170. */
    171. public void animateRipple(MotionEvent event) {
    172. createAnimation(event.getX(), event.getY());
    173. }
    174. /**
    175. * Launch Ripple animation for the current view centered at x and y position
    176. *
    177. * @param x Horizontal position of the ripple center
    178. * @param y Vertical position of the ripple center
    179. */
    180. public void animateRipple(final float x, final float y) {
    181. createAnimation(x, y);
    182. }
    183. /**
    184. * Create Ripple animation centered at x, y
    185. *
    186. * @param x Horizontal position of the ripple center
    187. * @param y Vertical position of the ripple center
    188. */
    189. private void createAnimation(final float x, final float y) {
    190. if (this.isEnabled() && !animationRunning) {
    191. if (hasToZoom)
    192. this.startAnimation(scaleAnimation);
    193. radiusMax = Math.max(WIDTH, HEIGHT);
    194. if (rippleType != 2)
    195. radiusMax /= 2;
    196. radiusMax -= ripplePadding;
    197. if (isCentered || rippleType == 1) {
    198. this.x = getMeasuredWidth() / 2;
    199. this.y = getMeasuredHeight() / 2;
    200. } else {
    201. this.x = x;
    202. this.y = y;
    203. }
    204. animationRunning = true;
    205. if (rippleType == 1 && originBitmap == null)
    206. originBitmap = getDrawingCache(true);
    207. invalidate();
    208. }
    209. }
    210. @Override
    211. public boolean onTouchEvent(MotionEvent event) {
    212. if (gestureDetector.onTouchEvent(event)) {
    213. animateRipple(event);
    214. sendClickEvent(false);
    215. }
    216. return super.onTouchEvent(event);
    217. }
    218. @Override
    219. public boolean onInterceptTouchEvent(MotionEvent event) {
    220. this.onTouchEvent(event);
    221. return super.onInterceptTouchEvent(event);
    222. }
    223. /**
    224. * Send a click event if parent view is a Listview instance
    225. *
    226. * @param isLongClick Is the event a long click ?
    227. */
    228. private void sendClickEvent(final Boolean isLongClick) {
    229. if (getParent() instanceof AdapterView) {
    230. final AdapterView adapterView = (AdapterView) getParent();
    231. final int position = adapterView.getPositionForView(this);
    232. final long id = adapterView.getItemIdAtPosition(position);
    233. if (isLongClick) {
    234. if (adapterView.getOnItemLongClickListener() != null)
    235. adapterView.getOnItemLongClickListener().onItemLongClick(adapterView, this, position, id);
    236. } else {
    237. if (adapterView.getOnItemClickListener() != null)
    238. adapterView.getOnItemClickListener().onItemClick(adapterView, this, position, id);
    239. }
    240. }
    241. }
    242. private Bitmap getCircleBitmap(final int radius) {
    243. final Bitmap output = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);
    244. final Canvas canvas = new Canvas(output);
    245. final Paint paint = new Paint();
    246. final Rect rect = new Rect((int)(x - radius), (int)(y - radius), (int)(x + radius), (int)(y + radius));
    247. paint.setAntiAlias(true);
    248. canvas.drawARGB(0, 0, 0, 0);
    249. canvas.drawCircle(x, y, radius, paint);
    250. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    251. canvas.drawBitmap(originBitmap, rect, rect, paint);
    252. return output;
    253. }
    254. /**
    255. * Set Ripple color, default is #FFFFFF
    256. *
    257. * @param rippleColor New color resource
    258. */
    259. public void setRippleColor(int rippleColor) {
    260. this.rippleColor = getResources().getColor(rippleColor);
    261. }
    262. public int getRippleColor() {
    263. return rippleColor;
    264. }
    265. public RippleType getRippleType()
    266. {
    267. return RippleType.values()[rippleType];
    268. }
    269. /**
    270. * Set Ripple type, default is RippleType.SIMPLE
    271. *
    272. * @param rippleType New Ripple type for next animation
    273. */
    274. public void setRippleType(final RippleType rippleType)
    275. {
    276. this.rippleType = rippleType.ordinal();
    277. }
    278. public Boolean isCentered()
    279. {
    280. return isCentered;
    281. }
    282. /**
    283. * Set if ripple animation has to be centered in its parent view or not, default is False
    284. *
    285. * @param isCentered
    286. */
    287. public void setCentered(final Boolean isCentered)
    288. {
    289. this.isCentered = isCentered;
    290. }
    291. public int getRipplePadding()
    292. {
    293. return ripplePadding;
    294. }
    295. /**
    296. * Set Ripple padding if you want to avoid some graphic glitch
    297. *
    298. * @param ripplePadding New Ripple padding in pixel, default is 0px
    299. */
    300. public void setRipplePadding(int ripplePadding)
    301. {
    302. this.ripplePadding = ripplePadding;
    303. }
    304. public Boolean isZooming()
    305. {
    306. return hasToZoom;
    307. }
    308. /**
    309. * At the end of Ripple effect, the child views has to zoom
    310. *
    311. * @param hasToZoom Do the child views have to zoom ? default is False
    312. */
    313. public void setZooming(Boolean hasToZoom)
    314. {
    315. this.hasToZoom = hasToZoom;
    316. }
    317. public float getZoomScale()
    318. {
    319. return zoomScale;
    320. }
    321. /**
    322. * Scale of the end animation
    323. *
    324. * @param zoomScale Value of scale animation, default is 1.03f
    325. */
    326. public void setZoomScale(float zoomScale)
    327. {
    328. this.zoomScale = zoomScale;
    329. }
    330. public int getZoomDuration()
    331. {
    332. return zoomDuration;
    333. }
    334. /**
    335. * Duration of the ending animation in ms
    336. *
    337. * @param zoomDuration Duration, default is 200ms
    338. */
    339. public void setZoomDuration(int zoomDuration)
    340. {
    341. this.zoomDuration = zoomDuration;
    342. }
    343. public int getRippleDuration()
    344. {
    345. return rippleDuration;
    346. }
    347. /**
    348. * Duration of the Ripple animation in ms
    349. *
    350. * @param rippleDuration Duration, default is 400ms
    351. */
    352. public void setRippleDuration(int rippleDuration)
    353. {
    354. this.rippleDuration = rippleDuration;
    355. }
    356. public int getFrameRate()
    357. {
    358. return frameRate;
    359. }
    360. /**
    361. * Set framerate for Ripple animation
    362. *
    363. * @param frameRate New framerate value, default is 10
    364. */
    365. public void setFrameRate(int frameRate)
    366. {
    367. this.frameRate = frameRate;
    368. }
    369. public int getRippleAlpha()
    370. {
    371. return rippleAlpha;
    372. }
    373. /**
    374. * Set alpha for ripple effect color
    375. *
    376. * @param rippleAlpha Alpha value between 0 and 255, default is 90
    377. */
    378. public void setRippleAlpha(int rippleAlpha)
    379. {
    380. this.rippleAlpha = rippleAlpha;
    381. }
    382. public void setOnRippleCompleteListener(OnRippleCompleteListener listener) {
    383. this.onCompletionListener = listener;
    384. }
    385. /**
    386. * Defines a callback called at the end of the Ripple effect
    387. */
    388. public interface OnRippleCompleteListener {
    389. void onComplete(RippleView rippleView);
    390. }
    391. public enum RippleType {
    392. SIMPLE(0),
    393. DOUBLE(1),
    394. RECTANGLE(2);
    395. int type;
    396. RippleType(int type)
    397. {
    398. this.type = type;
    399. }
    400. }
    401. }
  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. * Created by Administrator on 2016/5/3.
  21. */
  22. public class RippleView extends RelativeLayout{
  23. private int WIDTH;
  24. private int HEIGHT;
  25. private int frameRate = 10;
  26. private int rippleDuration = 400;
  27. private int rippleAlpha = 90;
  28. private Handler canvasHandler;
  29. private float radiusMax = 0;
  30. private boolean animationRunning = false;
  31. private int timer = 0;
  32. private int timerEmpty = 0;
  33. private int durationEmpty = -1;
  34. private float x = -1;
  35. private float y = -1;
  36. private int zoomDuration;
  37. private float zoomScale;
  38. private ScaleAnimation scaleAnimation;
  39. private Boolean hasToZoom;
  40. private Boolean isCentered;
  41. private Integer rippleType;
  42. private Paint paint;
  43. private Bitmap originBitmap;
  44. private int rippleColor;
  45. private int ripplePadding;
  46. private GestureDetector gestureDetector;
  47. private final Runnable runnable = new Runnable() {
  48. @Override
  49. public void run() {
  50. invalidate();
  51. }
  52. };
  53. private OnRippleCompleteListener onCompletionListener;
  54. public RippleView(Context context) {
  55. super(context);
  56. }
  57. public RippleView(Context context, AttributeSet attrs) {
  58. super(context, attrs);
  59. init(context, attrs);
  60. }
  61. public RippleView(Context context, AttributeSet attrs, int defStyle) {
  62. super(context, attrs, defStyle);
  63. init(context, attrs);
  64. }
  65. /**
  66. * Method that initializes all fields and sets listeners
  67. *
  68. * @param context Context used to create this view
  69. * @param attrs Attribute used to initialize fields
  70. */
  71. private void init(final Context context, final AttributeSet attrs) {
  72. if (isInEditMode())
  73. return;
  74. final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleView);
  75. rippleColor = typedArray.getColor(R.styleable.RippleView_rv_color, getResources().getColor(R.color.rippelColor));
  76. rippleType = typedArray.getInt(R.styleable.RippleView_rv_type, 0);
  77. hasToZoom = typedArray.getBoolean(R.styleable.RippleView_rv_zoom, false);
  78. isCentered = typedArray.getBoolean(R.styleable.RippleView_rv_centered, false);
  79. rippleDuration = typedArray.getInteger(R.styleable.RippleView_rv_rippleDuration, rippleDuration);
  80. frameRate = typedArray.getInteger(R.styleable.RippleView_rv_framerate, frameRate);
  81. rippleAlpha = typedArray.getInteger(R.styleable.RippleView_rv_alpha, rippleAlpha);
  82. ripplePadding = typedArray.getDimensionPixelSize(R.styleable.RippleView_rv_ripplePadding, 0);
  83. canvasHandler = new Handler();
  84. zoomScale = typedArray.getFloat(R.styleable.RippleView_rv_zoomScale, 1.03f);
  85. zoomDuration = typedArray.getInt(R.styleable.RippleView_rv_zoomDuration, 200);
  86. typedArray.recycle();
  87. paint = new Paint();
  88. paint.setAntiAlias(true);
  89. paint.setStyle(Paint.Style.FILL_AND_STROKE);
  90. paint.setColor(rippleColor);
  91. paint.setAlpha(rippleAlpha);
  92. this.setWillNotDraw(false);
  93. gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
  94. @Override
  95. public void onLongPress(MotionEvent event) {
  96. super.onLongPress(event);
  97. animateRipple(event);
  98. sendClickEvent(true);
  99. }
  100. @Override
  101. public boolean onSingleTapConfirmed(MotionEvent e) {
  102. return true;
  103. }
  104. @Override
  105. public boolean onSingleTapUp(MotionEvent e) {
  106. return true;
  107. }
  108. });
  109. this.setDrawingCacheEnabled(true);
  110. this.setClickable(true);
  111. }
  112. @Override
  113. public void draw(Canvas canvas) {
  114. super.draw(canvas);
  115. if (animationRunning) {
  116. canvas.save();
  117. if (rippleDuration <= timer * frameRate) {
  118. animationRunning = false;
  119. timer = 0;
  120. durationEmpty = -1;
  121. timerEmpty = 0;
  122. // There is problem on Android M where canvas.restore() seems to be called automatically
  123. // For now, don't call canvas.restore() manually on Android M (API 23)
  124. if(Build.VERSION.SDK_INT != 23) {
  125. canvas.restore();
  126. }
  127. invalidate();
  128. if (onCompletionListener != null) onCompletionListener.onComplete(this);
  129. return;
  130. } else
  131. canvasHandler.postDelayed(runnable, frameRate);
  132. if (timer == 0)
  133. canvas.save();
  134. canvas.drawCircle(x, y, (radiusMax * (((float) timer * frameRate) / rippleDuration)), paint);
  135. paint.setColor(Color.parseColor("#ffff4444"));
  136. if (rippleType == 1 && originBitmap != null && (((float) timer * frameRate) / rippleDuration) > 0.4f) {
  137. if (durationEmpty == -1)
  138. durationEmpty = rippleDuration - timer * frameRate;
  139. timerEmpty++;
  140. final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * frameRate) / (durationEmpty))));
  141. canvas.drawBitmap(tmpBitmap, 0, 0, paint);
  142. tmpBitmap.recycle();
  143. }
  144. paint.setColor(rippleColor);
  145. if (rippleType == 1) {
  146. if ((((float) timer * frameRate) / rippleDuration) > 0.6f)
  147. paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timerEmpty * frameRate) / (durationEmpty)))));
  148. else
  149. paint.setAlpha(rippleAlpha);
  150. }
  151. else
  152. paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timer * frameRate) / rippleDuration))));
  153. timer++;
  154. }
  155. }
  156. @Override
  157. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  158. super.onSizeChanged(w, h, oldw, oldh);
  159. WIDTH = w;
  160. HEIGHT = h;
  161. scaleAnimation = new ScaleAnimation(1.0f, zoomScale, 1.0f, zoomScale, w / 2, h / 2);
  162. scaleAnimation.setDuration(zoomDuration);
  163. scaleAnimation.setRepeatMode(Animation.REVERSE);
  164. scaleAnimation.setRepeatCount(1);
  165. }
  166. /**
  167. * Launch Ripple animation for the current view with a MotionEvent
  168. *
  169. * @param event MotionEvent registered by the Ripple gesture listener
  170. */
  171. public void animateRipple(MotionEvent event) {
  172. createAnimation(event.getX(), event.getY());
  173. }
  174. /**
  175. * Launch Ripple animation for the current view centered at x and y position
  176. *
  177. * @param x Horizontal position of the ripple center
  178. * @param y Vertical position of the ripple center
  179. */
  180. public void animateRipple(final float x, final float y) {
  181. createAnimation(x, y);
  182. }
  183. /**
  184. * Create Ripple animation centered at x, y
  185. *
  186. * @param x Horizontal position of the ripple center
  187. * @param y Vertical position of the ripple center
  188. */
  189. private void createAnimation(final float x, final float y) {
  190. if (this.isEnabled() && !animationRunning) {
  191. if (hasToZoom)
  192. this.startAnimation(scaleAnimation);
  193. radiusMax = Math.max(WIDTH, HEIGHT);
  194. if (rippleType != 2)
  195. radiusMax /= 2;
  196. radiusMax -= ripplePadding;
  197. if (isCentered || rippleType == 1) {
  198. this.x = getMeasuredWidth() / 2;
  199. this.y = getMeasuredHeight() / 2;
  200. } else {
  201. this.x = x;
  202. this.y = y;
  203. }
  204. animationRunning = true;
  205. if (rippleType == 1 && originBitmap == null)
  206. originBitmap = getDrawingCache(true);
  207. invalidate();
  208. }
  209. }
  210. @Override
  211. public boolean onTouchEvent(MotionEvent event) {
  212. if (gestureDetector.onTouchEvent(event)) {
  213. animateRipple(event);
  214. sendClickEvent(false);
  215. }
  216. return super.onTouchEvent(event);
  217. }
  218. @Override
  219. public boolean onInterceptTouchEvent(MotionEvent event) {
  220. this.onTouchEvent(event);
  221. return super.onInterceptTouchEvent(event);
  222. }
  223. /**
  224. * Send a click event if parent view is a Listview instance
  225. *
  226. * @param isLongClick Is the event a long click ?
  227. */
  228. private void sendClickEvent(final Boolean isLongClick) {
  229. if (getParent() instanceof AdapterView) {
  230. final AdapterView adapterView = (AdapterView) getParent();
  231. final int position = adapterView.getPositionForView(this);
  232. final long id = adapterView.getItemIdAtPosition(position);
  233. if (isLongClick) {
  234. if (adapterView.getOnItemLongClickListener() != null)
  235. adapterView.getOnItemLongClickListener().onItemLongClick(adapterView, this, position, id);
  236. } else {
  237. if (adapterView.getOnItemClickListener() != null)
  238. adapterView.getOnItemClickListener().onItemClick(adapterView, this, position, id);
  239. }
  240. }
  241. }
  242. private Bitmap getCircleBitmap(final int radius) {
  243. final Bitmap output = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);
  244. final Canvas canvas = new Canvas(output);
  245. final Paint paint = new Paint();
  246. final Rect rect = new Rect((int)(x - radius), (int)(y - radius), (int)(x + radius), (int)(y + radius));
  247. paint.setAntiAlias(true);
  248. canvas.drawARGB(0, 0, 0, 0);
  249. canvas.drawCircle(x, y, radius, paint);
  250. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
  251. canvas.drawBitmap(originBitmap, rect, rect, paint);
  252. return output;
  253. }
  254. /**
  255. * Set Ripple color, default is #FFFFFF
  256. *
  257. * @param rippleColor New color resource
  258. */
  259. public void setRippleColor(int rippleColor) {
  260. this.rippleColor = getResources().getColor(rippleColor);
  261. }
  262. public int getRippleColor() {
  263. return rippleColor;
  264. }
  265. public RippleType getRippleType()
  266. {
  267. return RippleType.values()[rippleType];
  268. }
  269. /**
  270. * Set Ripple type, default is RippleType.SIMPLE
  271. *
  272. * @param rippleType New Ripple type for next animation
  273. */
  274. public void setRippleType(final RippleType rippleType)
  275. {
  276. this.rippleType = rippleType.ordinal();
  277. }
  278. public Boolean isCentered()
  279. {
  280. return isCentered;
  281. }
  282. /**
  283. * Set if ripple animation has to be centered in its parent view or not, default is False
  284. *
  285. * @param isCentered
  286. */
  287. public void setCentered(final Boolean isCentered)
  288. {
  289. this.isCentered = isCentered;
  290. }
  291. public int getRipplePadding()
  292. {
  293. return ripplePadding;
  294. }
  295. /**
  296. * Set Ripple padding if you want to avoid some graphic glitch
  297. *
  298. * @param ripplePadding New Ripple padding in pixel, default is 0px
  299. */
  300. public void setRipplePadding(int ripplePadding)
  301. {
  302. this.ripplePadding = ripplePadding;
  303. }
  304. public Boolean isZooming()
  305. {
  306. return hasToZoom;
  307. }
  308. /**
  309. * At the end of Ripple effect, the child views has to zoom
  310. *
  311. * @param hasToZoom Do the child views have to zoom ? default is False
  312. */
  313. public void setZooming(Boolean hasToZoom)
  314. {
  315. this.hasToZoom = hasToZoom;
  316. }
  317. public float getZoomScale()
  318. {
  319. return zoomScale;
  320. }
  321. /**
  322. * Scale of the end animation
  323. *
  324. * @param zoomScale Value of scale animation, default is 1.03f
  325. */
  326. public void setZoomScale(float zoomScale)
  327. {
  328. this.zoomScale = zoomScale;
  329. }
  330. public int getZoomDuration()
  331. {
  332. return zoomDuration;
  333. }
  334. /**
  335. * Duration of the ending animation in ms
  336. *
  337. * @param zoomDuration Duration, default is 200ms
  338. */
  339. public void setZoomDuration(int zoomDuration)
  340. {
  341. this.zoomDuration = zoomDuration;
  342. }
  343. public int getRippleDuration()
  344. {
  345. return rippleDuration;
  346. }
  347. /**
  348. * Duration of the Ripple animation in ms
  349. *
  350. * @param rippleDuration Duration, default is 400ms
  351. */
  352. public void setRippleDuration(int rippleDuration)
  353. {
  354. this.rippleDuration = rippleDuration;
  355. }
  356. public int getFrameRate()
  357. {
  358. return frameRate;
  359. }
  360. /**
  361. * Set framerate for Ripple animation
  362. *
  363. * @param frameRate New framerate value, default is 10
  364. */
  365. public void setFrameRate(int frameRate)
  366. {
  367. this.frameRate = frameRate;
  368. }
  369. public int getRippleAlpha()
  370. {
  371. return rippleAlpha;
  372. }
  373. /**
  374. * Set alpha for ripple effect color
  375. *
  376. * @param rippleAlpha Alpha value between 0 and 255, default is 90
  377. */
  378. public void setRippleAlpha(int rippleAlpha)
  379. {
  380. this.rippleAlpha = rippleAlpha;
  381. }
  382. public void setOnRippleCompleteListener(OnRippleCompleteListener listener) {
  383. this.onCompletionListener = listener;
  384. }
  385. /**
  386. * Defines a callback called at the end of the Ripple effect
  387. */
  388. public interface OnRippleCompleteListener {
  389. void onComplete(RippleView rippleView);
  390. }
  391. public enum RippleType {
  392. SIMPLE(0),
  393. DOUBLE(1),
  394. RECTANGLE(2);
  395. int type;
  396. RippleType(int type)
  397. {
  398. this.type = type;
  399. }
  400. }
  401. }

Android5.0以上的项目都会有的按钮点击特效--水波纹的更多相关文章

  1. Web前端-按钮点击效果(水波纹)

    这种效果可以由元素内嵌套canves实现,也可以由css3实现. Canves实现 网上摘了一份canves实现的代码,略微去掉了些重复定义的样式并且给出js注释,代码如下 第一种方法: html骨架 ...

  2. 【数据售卖平台】—— Vue2.0入门学习项目爬坑

    前言:这个项目是我从零学习Vue2.0时用于练习基础知识的入门项目,包含了Vue2.0几乎所有项目都会用到的基础功能,是新手用来练手的好项目,这里温故知新对功能点做一个总结.github地址:http ...

  3. Android自定义组件系列【14】——Android5.0按钮波纹效果实现

    今天任老师发表了一篇关于Android5.0中按钮按下的波纹效果实现<Android L中水波纹点击效果的实现>,出于好奇我下载了源代码看了一下效果,正好手边有一个Nexus手机,我结合实 ...

  4. Android5.0新特性之——按钮点击效果动画(涟漪效果)

    Android5.0 Material Design设计的动画效果 RippleDrawable涟漪效果 涟漪效果是Android5.0以后的新特性.为了兼容性,建议新建drawable-v21文件夹 ...

  5. Android5.0(Lollipop) BLE蓝牙4.0+浅析code(二)

    作者:Bgwan链接:https://zhuanlan.zhihu.com/p/23347612来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. Android5.0(L ...

  6. Vue3实战系列:Vue3.0 + Vant3.0 搭建种子项目

    最近在用 Vue3 写一个开源的商城项目,开源后让大家也可以用现成的 Vue3 大型商城项目源码来练练手,目前处于开发阶段,过程中用到了 Vant3.0,于是就整理了这篇文章来讲一下如何使用 Vue3 ...

  7. android5.0联系人 sort_key改成phonebook_label

    项目中用到了联系人根据字母排序,在android4.0手机上是可以的,但是在android4.4以上的手机排序是乱的,一般字母排序都是根据sort_key这个拼音进行排序,而android5.0这个字 ...

  8. 一个Activity掌握Android5.0新控件 (转)

    原文地址:http://blog.csdn.net/lavor_zl/article/details/51279386 谷歌在推出Android5.0的同时推出了一些新控件,Android5.0中最常 ...

  9. 友情提醒:欲开发android5.0以上应用,请全部更新开发工具至最新

    周末帮人完成一个项目,android5.0以上版本,谁知道被开发工具折腾的死去活来.我的开发环境是adt-bundle-windows-x86-20140702.zip版本,也是目前能找到的adt-b ...

随机推荐

  1. Rsync(远程同步): linux中Rsync命令的实际示例

    rsync的 ( 远程同步 )为在Linux / Unix系统局部 拷贝和同步文件和目录远程以及一个最常用的命令. 随着rsync命令的帮助,您可以复制并在目录中远程和本地同步数据,在磁盘和网络,进行 ...

  2. js收藏代码

    js收藏代码~ 1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <table border oncon ...

  3. 使用VIM将文件的其中的连续几行注释删除或者给其中的连续几行添加注释

    一.使用VIM将文件的其中的连续几行注释删除 1.用VIM打开一个文件,比如打开sshd_config文件,以该文件的下面几行为例: #vim  sshd_config 2.此时,按ctrl+v键,使 ...

  4. paping使用来测试联通&网站由于tcp协议导致的无法通信问题超时问题

    1. 使用paping来测试连通性 Linux 平台: : wget http://www.updateweb.cn/softwares/paping_1.5.5_x86-64_linux.tar.g ...

  5. Kubeadm 安装部署 Kubernetes 集群

    阅读目录: 准备工作 部署 Master 管理节点 部署 Minion 工作节点 部署 Hello World 应用 安装 Dashboard 插件 安装 Heapster 插件 后记 相关文章:Ku ...

  6. 安装 LightGBM 包的过程

    conda install cmake conda install gcc git clone --recursive https://github.com/Microsoft/LightGBM ; ...

  7. toString 方法在数组中的使用

    对于一个一维数组,他在转换成字符串的时候应该调用Arrays.toString(); 对于一个多维数组,他在转换成字符串的时候应该调用Arrays.deepToString(); 实例: packag ...

  8. iOS开发引入第三方类库的问题

    在开发iOS程序的过程中,通常在导入第三方的类库(.a/.o)文件会报出一系列的错误: Undefined symbols for architecture i386: "std::stri ...

  9. PHP实现网页爬虫

    抓取某一个网页中的内容,需要对DOM树进行解析,找到指定节点后,再抓取我们需要的内容,过程有点繁琐.LZ总结了几种常用的.易于实现的网页抓取方式,如果熟悉JQuery选择器,这几种框架会相当简单. 一 ...

  10. LNK2026 模块对于 SAFESEH 映像是不安全的

    解决方法如下: 配置属性 -> 链接器 -> 命令行 位置添加如下内容: /SAFESEH:NO