当前位置: 代码迷 >> 综合 >> Android实战简易教程四十四(Ripple Effect-为控件增加涟漪效果)
  详细解决方案

Android实战简易教程四十四(Ripple Effect-为控件增加涟漪效果)

热度:36   发布时间:2024-01-10 01:53:01.0

最近发现了一款可以为控件增加涟漪效果的github项目,可以提升应用的逼格啊,大家不妨引入到自己的项目中。该项目本身是android studio下面编译,我改成了eclipse下可以运行的项目,下面我们来看一下具体的用法吧!

1.RippleView.java:

[java]  view plain copy
  1. /* 
  2.  * The MIT License (MIT) 
  3.  * 
  4.  * Copyright (c) 2014 Robin Chutaux 
  5.  * 
  6.  * Permission is hereby granted, free of charge, to any person obtaining a copy 
  7.  * of this software and associated documentation files (the "Software"), to deal 
  8.  * in the Software without restriction, including without limitation the rights 
  9.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  10.  * copies of the Software, and to permit persons to whom the Software is 
  11.  * furnished to do so, subject to the following conditions: 
  12.  * 
  13.  * The above copyright notice and this permission notice shall be included in 
  14.  * all copies or substantial portions of the Software. 
  15.  * 
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
  19.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
  21.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
  22.  * THE SOFTWARE. 
  23.  */  
  24.   
  25. package com.example.rippleeffectview;  
  26.   
  27. import com.example.test.R;  
  28.   
  29. import android.content.Context;  
  30. import android.content.res.TypedArray;  
  31. import android.graphics.Bitmap;  
  32. import android.graphics.Canvas;  
  33. import android.graphics.Paint;  
  34. import android.graphics.PorterDuff;  
  35. import android.graphics.PorterDuffXfermode;  
  36. import android.graphics.Rect;  
  37. import android.os.Handler;  
  38. import android.util.AttributeSet;  
  39. import android.view.GestureDetector;  
  40. import android.view.MotionEvent;  
  41. import android.view.View;  
  42. import android.view.ViewGroup;  
  43. import android.view.animation.Animation;  
  44. import android.view.animation.ScaleAnimation;  
  45. import android.widget.RelativeLayout;  
  46.   
  47. /** 
  48.  *  
  49.  * Date :      10/8/2014 
  50.  */  
  51. public class RippleView extends RelativeLayout  
  52. {  
  53.     private int WIDTH;  
  54.     private int HEIGHT;  
  55.     private int FRAME_RATE = 10;  
  56.     private int DURATION = 400;  
  57.     private int PAINT_ALPHA = 90;  
  58.     private Handler canvasHandler;  
  59.     private float radiusMax = 0;  
  60.     private boolean animationRunning = false;  
  61.     private int timer = 0;  
  62.     private int timerEmpty = 0;  
  63.     private int durationEmpty = -1;  
  64.     private float x = -1;  
  65.     private float y = -1;  
  66.     private int zoomDuration;  
  67.     private float zoomScale;  
  68.     private ScaleAnimation scaleAnimation;  
  69.     private Boolean hasToZoom;  
  70.     private Boolean isCentered;  
  71.     private Integer rippleType;  
  72.     private Paint paint;  
  73.     private Bitmap originBitmap;  
  74.     private int rippleColor;  
  75.     private View childView;  
  76.     private int ripplePadding;  
  77.     private GestureDetector gestureDetector;  
  78.     private Runnable runnable = new Runnable()  
  79.     {  
  80.         @Override  
  81.         public void run()  
  82.         {  
  83.             invalidate();  
  84.         }  
  85.     };  
  86.   
  87.     public RippleView(Context context)  
  88.     {  
  89.         super(context);  
  90.     }  
  91.   
  92.     public RippleView(Context context, AttributeSet attrs)  
  93.     {  
  94.         super(context, attrs);  
  95.         init(context, attrs);  
  96.     }  
  97.   
  98.     public RippleView(Context context, AttributeSet attrs, int defStyle)  
  99.     {  
  100.         super(context, attrs, defStyle);  
  101.         init(context, attrs);  
  102.     }  
  103.   
  104.     private void init(final Context context, final AttributeSet attrs)  
  105.     {  
  106.         if (isInEditMode())  
  107.             return;  
  108.   
  109.         final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleView);  
  110.         rippleColor = typedArray.getColor(R.styleable.RippleView_rv_color, getResources().getColor(R.color.rippelColor));  
  111.         rippleType = typedArray.getInt(R.styleable.RippleView_rv_type, 0);  
  112.         hasToZoom = typedArray.getBoolean(R.styleable.RippleView_rv_zoom, false);  
  113.         isCentered = typedArray.getBoolean(R.styleable.RippleView_rv_centered, false);  
  114.         DURATION = typedArray.getInteger(R.styleable.RippleView_rv_rippleDuration, DURATION);  
  115.         FRAME_RATE = typedArray.getInteger(R.styleable.RippleView_rv_framerate, FRAME_RATE);  
  116.         PAINT_ALPHA = typedArray.getInteger(R.styleable.RippleView_rv_alpha, PAINT_ALPHA);  
  117.         ripplePadding = typedArray.getDimensionPixelSize(R.styleable.RippleView_rv_ripplePadding, 0);  
  118.         canvasHandler = new Handler();  
  119.         zoomScale = typedArray.getFloat(R.styleable.RippleView_rv_zoomScale, 1.03f);  
  120.         zoomDuration = typedArray.getInt(R.styleable.RippleView_rv_zoomDuration, 200);  
  121.         paint = new Paint();  
  122.         paint.setAntiAlias(true);  
  123.         paint.setStyle(Paint.Style.FILL);  
  124.         paint.setColor(rippleColor);  
  125.         paint.setAlpha(PAINT_ALPHA);  
  126.         this.setWillNotDraw(false);  
  127.   
  128.         gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener()  
  129.         {  
  130.             @Override  
  131.             public boolean onSingleTapConfirmed(MotionEvent e)  
  132.             {  
  133.                 return true;  
  134.             }  
  135.   
  136.             @Override  
  137.             public boolean onSingleTapUp(MotionEvent e)  
  138.             {  
  139.                 return true;  
  140.             }  
  141.         });  
  142.   
  143.         this.setDrawingCacheEnabled(true);  
  144.     }  
  145.   
  146.     @Override  
  147.     public void addView(View child, int index, ViewGroup.LayoutParams params)  
  148.     {  
  149.         childView = child;  
  150.         super.addView(child, index, params);  
  151.     }  
  152.   
  153.     @Override  
  154.     public void draw(Canvas canvas)  
  155.     {  
  156.         super.draw(canvas);  
  157.         if (animationRunning)  
  158.         {  
  159.             if (DURATION <= timer * FRAME_RATE)  
  160.             {  
  161.                 animationRunning = false;  
  162.                 timer = 0;  
  163.                 durationEmpty = -1;  
  164.                 timerEmpty = 0;  
  165.                 canvas.restore();  
  166.                 invalidate();  
  167.                 return;  
  168.             }  
  169.             else  
  170.                 canvasHandler.postDelayed(runnable, FRAME_RATE);  
  171.   
  172.             if (timer == 0)  
  173.                 canvas.save();  
  174.   
  175.   
  176.             canvas.drawCircle(x, y, (radiusMax * (((float) timer * FRAME_RATE) / DURATION)), paint);  
  177.   
  178.             paint.setColor(getResources().getColor(android.R.color.holo_red_light));  
  179.   
  180.             if (rippleType == 1 && originBitmap != null && (((float) timer * FRAME_RATE) / DURATION) > 0.4f)  
  181.             {  
  182.                 if (durationEmpty == -1)  
  183.                     durationEmpty = DURATION - timer * FRAME_RATE;  
  184.   
  185.                 timerEmpty++;  
  186.                 final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * FRAME_RATE) / (durationEmpty))));  
  187.                 canvas.drawBitmap(tmpBitmap, 00, paint);  
  188.                 tmpBitmap.recycle();  
  189.             }  
  190.   
  191.             paint.setColor(rippleColor);  
  192.   
  193.             if (rippleType == 1)  
  194.             {  
  195.                 if ((((float) timer * FRAME_RATE) / DURATION) > 0.6f)  
  196.                     paint.setAlpha((int) (PAINT_ALPHA - ((PAINT_ALPHA) * (((float) timerEmpty * FRAME_RATE) / (durationEmpty)))));  
  197.                 else  
  198.                     paint.setAlpha(PAINT_ALPHA);  
  199.             }  
  200.             else  
  201.                 paint.setAlpha((int) (PAINT_ALPHA - ((PAINT_ALPHA) * (((float) timer * FRAME_RATE) / DURATION))));  
  202.   
  203.             timer++;  
  204.         }  
  205.     }  
  206.   
  207.     @Override  
  208.     protected void onSizeChanged(int w, int h, int oldw, int oldh)  
  209.     {  
  210.         super.onSizeChanged(w, h, oldw, oldh);  
  211.         WIDTH = w;  
  212.         HEIGHT = h;  
  213.   
  214.         scaleAnimation = new ScaleAnimation(1.0f, zoomScale, 1.0f, zoomScale, w / 2, h / 2);  
  215.         scaleAnimation.setDuration(zoomDuration);  
  216.         scaleAnimation.setRepeatMode(Animation.REVERSE);  
  217.         scaleAnimation.setRepeatCount(1);  
  218.     }  
  219.   
  220.     @Override  
  221.     public boolean onTouchEvent(MotionEvent event)  
  222.     {  
  223.         if (gestureDetector.onTouchEvent(event) && !animationRunning)  
  224.         {  
  225.             if (hasToZoom)  
  226.                 this.startAnimation(scaleAnimation);  
  227.   
  228.             radiusMax = Math.max(WIDTH, HEIGHT);  
  229.   
  230.             if (rippleType != 2)  
  231.                 radiusMax /= 2;  
  232.   
  233.             radiusMax -= ripplePadding;  
  234.   
  235.             if (isCentered || rippleType == 1)  
  236.             {  
  237.                 this.x = getMeasuredWidth() / 2;  
  238.                 this.y = getMeasuredHeight() / 2;  
  239.             }  
  240.             else  
  241.             {  
  242.                 this.x = event.getX();  
  243.                 this.y = event.getY();  
  244.             }  
  245.   
  246.             animationRunning = true;  
  247.   
  248.             if (rippleType == 1 && originBitmap == null)  
  249.                 originBitmap = getDrawingCache(true);  
  250.   
  251.             invalidate();  
  252.             this.performClick();  
  253.         }  
  254.   
  255.         childView.onTouchEvent(event);  
  256.         return true;  
  257.     }  
  258.   
  259.     @Override  
  260.     public boolean onInterceptTouchEvent(MotionEvent event)  
  261.     {  
  262.        return true;  
  263.     }  
  264.   
  265.     private Bitmap getCircleBitmap(final int radius) {  
  266.         final Bitmap output = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);  
  267.         final Canvas canvas = new Canvas(output);  
  268.         final Paint paint = new Paint();  
  269.         final Rect rect = new Rect((int)(x - radius), (int)(y - radius), (int)(x + radius), (int)(y + radius));  
  270.   
  271.         paint.setAntiAlias(true);  
  272.         canvas.drawARGB(0000);  
  273.         canvas.drawCircle(x, y, radius, paint);  
  274.   
  275.         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));  
  276.         canvas.drawBitmap(originBitmap, rect, rect, paint);  
  277.   
  278.         return output;  
  279.     }  
  280. }  

2.MainActivity.java:

[java]  view plain copy
  1. package com.example.test;  
  2.   
  3. import com.example.rippleeffectview.RippleView;  
  4.   
  5. import android.os.Bundle;  
  6. import android.support.v7.app.ActionBarActivity;  
  7. import android.view.Menu;  
  8. import android.view.MenuItem;  
  9.   
  10. public class MainActivity extends ActionBarActivity {  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.          final RippleView rippleView = (RippleView) findViewById(R.id.more);  
  17.     }  
  18.   
  19.     @Override  
  20.     public boolean onCreateOptionsMenu(Menu menu) {  
  21.         // Inflate the menu; this adds items to the action bar if it is present.  
  22.         getMenuInflater().inflate(R.menu.main, menu);  
  23.         return true;  
  24.     }  
  25.   
  26.     @Override  
  27.     public boolean onOptionsItemSelected(MenuItem item) {  
  28.         // Handle action bar item clicks here. The action bar will  
  29.         // automatically handle clicks on the Home/Up button, so long  
  30.         // as you specify a parent activity in AndroidManifest.xml.  
  31.         int id = item.getItemId();  
  32.         if (id == R.id.action_settings) {  
  33.             return true;  
  34.         }  
  35.         return super.onOptionsItemSelected(item);  
  36.     }  
  37. }  

3.布局文件应该是需要注意的地方:

[html]  view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:ripple="http://schemas.android.com/apk/res-auto"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent" >  
  6.   
  7.     <com.example.rippleeffectview.RippleView  
  8.         android:id="@+id/more"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"  
  11.         android:layout_margin="5dp"  
  12.         ripple:rv_centered="true"  
  13.         ripple:rv_type="rectangle" >  
  14.   
  15.         <Button  
  16.             android:layout_width="match_parent"  
  17.             android:layout_height="80dp"  
  18.             android:background="@color/switch_thumb_normal_material_dark"  
  19.             android:text="I like Color" />  
  20.     </com.example.rippleeffectview.RippleView>  
  21.   
  22. </RelativeLayout>  

需要注意的地方如下图:


ripple:rv_centered="true"表示涟漪出现在中间位置;

ripple:rv_type="rectangle"表示涟漪的形状-长方形;

此外还有:

ripple:rv_type="doubleRipple"表示双涟漪;

ripple:rv_zoom="true"表示控件有缩放效果

ripple:rv_color="#000000"表示涟漪的颜色为黑色

还有其他属性在这里:

[html]  view plain copy
  1. <resources>  
  2.     <declare-styleable name="RippleView">  
  3.         <attr name="rv_alpha" format="integer" />  
  4.         <attr name="rv_framerate" format="integer"/>  
  5.         <attr name="rv_rippleDuration" format="integer"/>  
  6.         <attr name="rv_zoomDuration" format="integer" />  
  7.         <attr name="rv_color" format="color" />  
  8.         <attr name="rv_centered" format="boolean" />  
  9.         <attr name="rv_type" format="enum">  
  10.             <enum name="simpleRipple" value="0"/>  
  11.             <enum name="doubleRipple" value="1"/>  
  12.             <enum name="rectangle" value="2" />  
  13.         </attr>  
  14.         <attr name="rv_ripplePadding" format="dimension" />  
  15.         <attr name="rv_zoom" format="boolean" />  
  16.         <attr name="rv_zoomScale" format="float" />  
  17.   
  18.     </declare-styleable>  
  19. </resources>  

大家可以自行测试效果。

运行效果如下:


下面讨论一下如何将项目引入到自己的工程中:


复制上面箭头指向的三个文件到自己的项目中,按照上面例子所示的方法把控件包起来即可使用,非常方便,不懂的地方可以留言,谢谢!

下载地址

  相关解决方案