zoukankan      html  css  js  c++  java
  • 在Android中实现来自Material设计的Ripple效果:RippleEffect

    网络示例图:

    RippleView.java

      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.maomao.beautymovie.widget;
     26 
     27 
     28 import com.maomao.beautymovie.R;
     29 
     30 import android.content.Context;
     31 import android.content.res.TypedArray;
     32 import android.graphics.Bitmap;
     33 import android.graphics.Canvas;
     34 import android.graphics.Paint;
     35 import android.graphics.PorterDuff;
     36 import android.graphics.PorterDuffXfermode;
     37 import android.graphics.Rect;
     38 import android.os.Handler;
     39 import android.util.AttributeSet;
     40 import android.view.GestureDetector;
     41 import android.view.MotionEvent;
     42 import android.view.View;
     43 import android.view.ViewGroup;
     44 import android.view.animation.Animation;
     45 import android.view.animation.ScaleAnimation;
     46 import android.widget.RelativeLayout;
     47 
     48 /**
     49  * Author :    Chutaux Robin
     50  * Date :      10/8/2014
     51  */
     52 public class RippleView extends RelativeLayout
     53 {
     54     private int WIDTH;
     55     private int HEIGHT;
     56     private int FRAME_RATE = 10;
     57     private int DURATION = 400;
     58     private int PAINT_ALPHA = 90;
     59     private Handler canvasHandler;
     60     private float radiusMax = 0;
     61     private boolean animationRunning = false;
     62     private int timer = 0;
     63     private int timerEmpty = 0;
     64     private int durationEmpty = -1;
     65     private float x = -1;
     66     private float y = -1;
     67     private int zoomDuration;
     68     private float zoomScale;
     69     private ScaleAnimation scaleAnimation;
     70     private Boolean hasToZoom;
     71     private Boolean isCentered;
     72     private Integer rippleType;
     73     private Paint paint;
     74     private Bitmap originBitmap;
     75     private int rippleColor;
     76     private View childView;
     77     private int ripplePadding;
     78     private GestureDetector gestureDetector;
     79     private Runnable runnable = new Runnable()
     80     {
     81         @Override
     82         public void run()
     83         {
     84             invalidate();
     85         }
     86     };
     87 
     88     public RippleView(Context context)
     89     {
     90         super(context);
     91     }
     92 
     93     public RippleView(Context context, AttributeSet attrs)
     94     {
     95         super(context, attrs);
     96         init(context, attrs);
     97     }
     98 
     99     public RippleView(Context context, AttributeSet attrs, int defStyle)
    100     {
    101         super(context, attrs, defStyle);
    102         init(context, attrs);
    103     }
    104 
    105     private void init(final Context context, final AttributeSet attrs)
    106     {
    107         if (isInEditMode())
    108             return;
    109 
    110         final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleView);
    111         rippleColor = typedArray.getColor(R.styleable.RippleView_rv_color, getResources().getColor(R.color.rippelColor));
    112         rippleType = typedArray.getInt(R.styleable.RippleView_rv_type, 0);
    113         hasToZoom = typedArray.getBoolean(R.styleable.RippleView_rv_zoom, false);
    114         isCentered = typedArray.getBoolean(R.styleable.RippleView_rv_centered, false);
    115         DURATION = typedArray.getInteger(R.styleable.RippleView_rv_rippleDuration, DURATION);
    116         FRAME_RATE = typedArray.getInteger(R.styleable.RippleView_rv_framerate, FRAME_RATE);
    117         PAINT_ALPHA = typedArray.getInteger(R.styleable.RippleView_rv_alpha, PAINT_ALPHA);
    118         ripplePadding = typedArray.getDimensionPixelSize(R.styleable.RippleView_rv_ripplePadding, 0);
    119         canvasHandler = new Handler();
    120         zoomScale = typedArray.getFloat(R.styleable.RippleView_rv_zoomScale, 1.03f);
    121         zoomDuration = typedArray.getInt(R.styleable.RippleView_rv_zoomDuration, 200);
    122         paint = new Paint();
    123         paint.setAntiAlias(true);
    124         paint.setStyle(Paint.Style.FILL);
    125         paint.setColor(rippleColor);
    126         paint.setAlpha(PAINT_ALPHA);
    127         this.setWillNotDraw(false);
    128 
    129         gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener()
    130         {
    131             @Override
    132             public boolean onSingleTapConfirmed(MotionEvent e)
    133             {
    134                 return true;
    135             }
    136 
    137             @Override
    138             public boolean onSingleTapUp(MotionEvent e)
    139             {
    140                 return true;
    141             }
    142         });
    143 
    144         this.setDrawingCacheEnabled(true);
    145     }
    146 
    147     @Override
    148     public void addView(View child, int index, ViewGroup.LayoutParams params)
    149     {
    150         childView = child;
    151         super.addView(child, index, params);
    152     }
    153 
    154     @Override
    155     public void draw(Canvas canvas)
    156     {
    157         super.draw(canvas);
    158         if (animationRunning)
    159         {
    160             if (DURATION <= timer * FRAME_RATE)
    161             {
    162                 animationRunning = false;
    163                 timer = 0;
    164                 durationEmpty = -1;
    165                 timerEmpty = 0;
    166                 canvas.restore();
    167                 invalidate();
    168                 return;
    169             }
    170             else
    171                 canvasHandler.postDelayed(runnable, FRAME_RATE);
    172 
    173             if (timer == 0)
    174                 canvas.save();
    175 
    176 
    177             canvas.drawCircle(x, y, (radiusMax * (((float) timer * FRAME_RATE) / DURATION)), paint);
    178 
    179             paint.setColor(getResources().getColor(android.R.color.holo_red_light));
    180 
    181             if (rippleType == 1 && originBitmap != null && (((float) timer * FRAME_RATE) / DURATION) > 0.4f)
    182             {
    183                 if (durationEmpty == -1)
    184                     durationEmpty = DURATION - timer * FRAME_RATE;
    185 
    186                 timerEmpty++;
    187                 final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * FRAME_RATE) / (durationEmpty))));
    188                 canvas.drawBitmap(tmpBitmap, 0, 0, paint);
    189                 tmpBitmap.recycle();
    190             }
    191 
    192             paint.setColor(rippleColor);
    193 
    194             if (rippleType == 1)
    195             {
    196                 if ((((float) timer * FRAME_RATE) / DURATION) > 0.6f)
    197                     paint.setAlpha((int) (PAINT_ALPHA - ((PAINT_ALPHA) * (((float) timerEmpty * FRAME_RATE) / (durationEmpty)))));
    198                 else
    199                     paint.setAlpha(PAINT_ALPHA);
    200             }
    201             else
    202                 paint.setAlpha((int) (PAINT_ALPHA - ((PAINT_ALPHA) * (((float) timer * FRAME_RATE) / DURATION))));
    203 
    204             timer++;
    205         }
    206     }
    207 
    208     @Override
    209     protected void onSizeChanged(int w, int h, int oldw, int oldh)
    210     {
    211         super.onSizeChanged(w, h, oldw, oldh);
    212         WIDTH = w;
    213         HEIGHT = h;
    214 
    215         scaleAnimation = new ScaleAnimation(1.0f, zoomScale, 1.0f, zoomScale, w / 2, h / 2);
    216         scaleAnimation.setDuration(zoomDuration);
    217         scaleAnimation.setRepeatMode(Animation.REVERSE);
    218         scaleAnimation.setRepeatCount(1);
    219     }
    220 
    221     @Override
    222     public boolean onTouchEvent(MotionEvent event)
    223     {
    224         if (gestureDetector.onTouchEvent(event) && !animationRunning)
    225         {
    226             if (hasToZoom)
    227                 this.startAnimation(scaleAnimation);
    228 
    229             radiusMax = Math.max(WIDTH, HEIGHT);
    230 
    231             if (rippleType != 2)
    232                 radiusMax /= 2;
    233 
    234             radiusMax -= ripplePadding;
    235 
    236             if (isCentered || rippleType == 1)
    237             {
    238                 this.x = getMeasuredWidth() / 2;
    239                 this.y = getMeasuredHeight() / 2;
    240             }
    241             else
    242             {
    243                 this.x = event.getX();
    244                 this.y = event.getY();
    245             }
    246 
    247             animationRunning = true;
    248 
    249             if (rippleType == 1 && originBitmap == null)
    250                 originBitmap = getDrawingCache(true);
    251 
    252             invalidate();
    253             this.performClick();
    254         }
    255 
    256         childView.onTouchEvent(event);
    257         return true;
    258     }
    259 
    260     @Override
    261     public boolean onInterceptTouchEvent(MotionEvent event)
    262     {
    263        return true;
    264     }
    265 
    266     private Bitmap getCircleBitmap(final int radius) {
    267         final Bitmap output = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);
    268         final Canvas canvas = new Canvas(output);
    269         final Paint paint = new Paint();
    270         final Rect rect = new Rect((int)(x - radius), (int)(y - radius), (int)(x + radius), (int)(y + radius));
    271 
    272         paint.setAntiAlias(true);
    273         canvas.drawARGB(0, 0, 0, 0);
    274         canvas.drawCircle(x, y, radius, paint);
    275 
    276         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    277         canvas.drawBitmap(originBitmap, rect, rect, paint);
    278 
    279         return output;
    280     }
    281 }
    View Code

    xml中声明:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout android:orientation="vertical" 
     3     android:padding="5.0dip" 
     4     android:fitsSystemWindows="true" 
     5     android:clipToPadding="true" 
     6     android:layout_width="fill_parent" 
     7     android:layout_height="fill_parent"
     8     xmlns:android="http://schemas.android.com/apk/res/android"
     9     xmlns:ripple="http://schemas.android.com/apk/res-auto"
    10     xmlns:tools="http://schemas.android.com/tools"
    11     tools:context=".MainActivity">
    12     <EditText 
    13         android:textSize="16.0sp" 
    14         android:id="@+id/edit_email" 
    15         android:layout_width="fill_parent" 
    16         android:layout_height="wrap_content" 
    17         android:layout_marginTop="10.0dip" 
    18         android:hint="您的邮箱(选填)" 
    19         android:singleLine="true" />
    20     <EditText 
    21         android:textSize="16.0sp" 
    22         android:id="@+id/edit_advice" 
    23         android:layout_width="fill_parent" 
    24         android:layout_height="wrap_content" 
    25         android:layout_marginTop="20.0dip" 
    26         android:hint="您的意见或建议" />
    27 
    28    
    29     
    30         <com.maomao.beautymovie.widget.RippleView
    31         android:id="@+id/rect"
    32         android:layout_width="fill_parent"
    33         android:layout_marginTop="20dp"
    34         android:layout_marginLeft="10dp"
    35         android:layout_marginRight="10dp"
    36         android:layout_height="wrap_content"
    37         ripple:rv_type="rectangle"
    38         ripple:rv_zoom="true">
    39 
    40         <TextView
    41             android:id="@+id/rect_child"
    42             android:layout_width="fill_parent"
    43             android:layout_height="50dp"
    44             android:layout_centerInParent="true"
    45             android:textColor="@android:color/white"
    46             android:textSize="20sp"
    47             android:gravity="center"
    48             android:text="提交"
    49             android:background="@android:color/holo_blue_light"/>
    50 
    51     </com.maomao.beautymovie.widget.RippleView>
    52     
    53     
    54     
    55 </LinearLayout>

    activity中监听使用:

     1 package com.maomao.beautymovie;
     2 
     3 
     4 
     5 import com.maomao.beautymovie.widget.RippleView;
     6 
     7 
     8 public class FeedbackActivity extends BaseActivity {
     9 
    10     @Override
    11     protected void onCreate(Bundle savedInstanceState) {
    12         super.onCreate(savedInstanceState);
    13         setContentView(R.layout.activity_feedback);
    14         final RippleView rippleView = (RippleView) findViewById(R.id.rect);
    15 
    16         rippleView.setOnClickListener(new View.OnClickListener()
    17         {
    18             @Override
    19             public void onClick(View v)
    20             {
    21                 Toast.makeText(FeedbackActivity.this, "这是一个Toast提示", Toast.LENGTH_LONG).show();
    22             }
    23         });
    24  
    25             
    26     }
    27 
    28     @Override
    29     public boolean onOptionsItemSelected(MenuItem item) {
    30         if (item.getItemId() == android.R.id.home) {
    31             finish();
    32             return true;
    33         }
    34         return super.onOptionsItemSelected(item);
    35     }
    36 
    37 
    38 
    39 }

    demo:链接: http://pan.baidu.com/s/1i3zPZoD 密码: 96cz

  • 相关阅读:
    zabbix 配置发送邮件报警
    sql server 修改表结构语法大全
    SQL Server日期与字符串之间的转换
    Convert.ToDateTime(值),方法可以把一个值转化成DateTime类型。
    Oracle trunc()函数的用法
    Oracle job procedure 存储过程定时任务
    向数据库中插入一个DateTime类型的数据到一个Date类型的字段中,需要转换类型。TO_DATE('{0}','YYYY-MM-DD'))
    逗号分隔的字符串转换为行数据(collection)(续)
    Oracle中INSTR、SUBSTR和NVL的用法
    oracle中substr() instr() 用法
  • 原文地址:https://www.cnblogs.com/ning1121/p/4378375.html
Copyright © 2011-2022 走看看