├── .gitignore ├── README.md ├── app ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── kince │ │ └── rippleview │ │ ├── MainActivity.java │ │ ├── button │ │ └── RippleButton.java │ │ └── draw │ │ ├── BasicRippleView.java │ │ ├── HalfRippleView.java │ │ └── ObjectRippleView.java │ └── res │ ├── drawable-hdpi │ ├── easy3d_ic_apply.png │ └── ic_launcher.png │ ├── drawable-mdpi │ ├── easy3d_ic_apply.png │ └── ic_launcher.png │ ├── drawable-xhdpi │ ├── easy3d_ic_apply.png │ └── ic_launcher.png │ ├── drawable-xxhdpi │ ├── easy3d_ic_apply.png │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ ├── menu │ └── main.xml │ ├── values-v11 │ └── styles.xml │ ├── values-v14 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── ripple.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Android template 3 | # Built application files 4 | *.apk 5 | *.ap_ 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | 18 | # Gradle files 19 | .gradle/ 20 | build/ 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | 25 | # Proguard folder generated by Eclipse 26 | proguard/ 27 | 28 | # Log Files 29 | *.log 30 | 31 | # Android Studio Navigation editor temp files 32 | .navigation/ 33 | 34 | # Android Studio captures folder 35 | captures/ 36 | 37 | # Intellij 38 | *.iml 39 | .idea/workspace.xml 40 | 41 | # Keystore files 42 | *.jks 43 | 44 | .idea/ 45 | KittyLive-Android.iml 46 | #gradle/ 47 | gradlew 48 | gradlew.bat 49 | 50 | .DS_Store 51 | /build 52 | 53 | *iml 54 | 55 | */build 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RippleView 2 | ======================== 3 | 8/9/2014 15:38:51 PM 4 | 5 | > 概述 6 | 7 | 波纹效果的视图,模仿Solo足球动态壁纸。 8 | 9 | 10 | > 效果图 11 | 12 |
13 | 14 |
15 | 16 | 17 | > 开发环境 18 | 19 | 20 | Eclipse 21 | 22 | 23 | 24 | > 关注我 25 | 26 | 追梦赤子心 27 | 28 | > License 29 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 30 | http://www.apache.org/licenses/LICENSE-2.0 31 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.kince.rippleview" 9 | minSdkVersion 16 10 | targetSdkVersion 25 11 | } 12 | 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'com.android.support:support-v4:25.3.1' 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/kince/rippleview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.kince.rippleview; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.os.Bundle; 7 | import android.view.animation.DecelerateInterpolator; 8 | 9 | import com.kince.rippleview.draw.HalfRippleView; 10 | import com.kince.rippleview.draw.ObjectRippleView; 11 | import com.kince.rippleview.draw.BasicRippleView; 12 | 13 | public class MainActivity extends Activity { 14 | 15 | private HalfRippleView mHalfRippleView; 16 | private ObjectRippleView mObjectRippleView; 17 | private BasicRippleView mBasicRippleView; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | 24 | initObjectRippleView(); 25 | } 26 | 27 | private void initBasicRippleView(){ 28 | mBasicRippleView = (BasicRippleView) findViewById(R.id.rippleview); 29 | mBasicRippleView.setRippleColor(Color.RED);//设置波纹的颜色 30 | mBasicRippleView.onStart(true);//开始绘制 31 | } 32 | 33 | private void initObjectRippleView(){ 34 | mObjectRippleView = (ObjectRippleView) findViewById(R.id.rippleview); 35 | mObjectRippleView.setDuration(3000); 36 | mObjectRippleView.setStyle(Paint.Style.FILL); 37 | mObjectRippleView.setColor(Color.RED); 38 | mObjectRippleView.setInterpolator(new DecelerateInterpolator()); 39 | mObjectRippleView.start(); 40 | } 41 | 42 | private void initHalfRippleView(){ 43 | mHalfRippleView =(HalfRippleView) findViewById(R.id.rippleview); 44 | mHalfRippleView.stratRipple(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/kince/rippleview/button/RippleButton.java: -------------------------------------------------------------------------------- 1 | package com.kince.rippleview.button; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.Button; 6 | 7 | /** 8 | * Created by Kince183 on 2017/4/6. 9 | * 10 | */ 11 | public class RippleButton extends Button{ 12 | 13 | public RippleButton(Context context) { 14 | super(context); 15 | } 16 | 17 | public RippleButton(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | public RippleButton(Context context, AttributeSet attrs, int defStyleAttr) { 22 | super(context, attrs, defStyleAttr); 23 | } 24 | 25 | @Override 26 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 27 | super.onSizeChanged(w, h, oldw, oldh); 28 | } 29 | 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/kince/rippleview/draw/BasicRippleView.java: -------------------------------------------------------------------------------- 1 | package com.kince.rippleview.draw; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.os.Handler; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Iterator; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by Kince183 on 2017/4/6. 17 | */ 18 | public class BasicRippleView extends View { 19 | 20 | private Context mContext; 21 | private Paint mCirclePaint;// 圆圈画笔 22 | 23 | private int mStartDiameter;//波纹出现时的直径 24 | private int mColorDiameter;//波纹颜色最深时的直径 25 | private int mEndDiameter;//波纹消失时的直径 26 | private int mRippleWidth;//波纹的宽度 27 | 28 | private int mRippleColor = Color.parseColor("#ffffff");//波纹的颜色 29 | private int maxPaintAlpha; 30 | 31 | private int mCircleRadius; 32 | private List mCircleRadiusList = new ArrayList<>();//放置绘制出来的波 33 | 34 | private boolean isLoop;// 是否循环动画 35 | private long mCurrentTime = System.currentTimeMillis();//获得当前时间 36 | 37 | //开启handle进行重复绘制 38 | private Handler mHandler = new Handler(); 39 | private Runnable mRunnable = new Runnable() { 40 | 41 | @Override 42 | public void run() { 43 | invalidate();// 刷新界面 44 | controlCircle(); 45 | if (isLoop) { 46 | mHandler.postDelayed(mRunnable, 50); 47 | } 48 | } 49 | }; 50 | 51 | enum Mode{ 52 | STYLE_STROKE, 53 | STYLE_FILL; 54 | } 55 | 56 | public BasicRippleView(Context context) { 57 | this(context, null); 58 | } 59 | 60 | public BasicRippleView(Context context, AttributeSet attrs) { 61 | super(context, attrs); 62 | initView(context); 63 | } 64 | 65 | public BasicRippleView(Context context, AttributeSet attrs, int defStyleAttr) { 66 | super(context, attrs, defStyleAttr); 67 | initView(context); 68 | } 69 | 70 | private void initView(Context context) { 71 | this.mContext = context; 72 | mStartDiameter = dp2px(25); 73 | mRippleWidth = dp2px(2); 74 | mEndDiameter = dp2px(112); 75 | maxPaintAlpha = 255; 76 | 77 | mCirclePaint = new Paint(); 78 | mCirclePaint.setAntiAlias(true); 79 | mCirclePaint.setStrokeWidth(mRippleWidth); 80 | mCirclePaint.setStyle(Paint.Style.FILL); 81 | mCirclePaint.setColor(mRippleColor); 82 | 83 | mCircleRadius = mStartDiameter / 2; 84 | mCircleRadiusList.add(mCircleRadius); 85 | } 86 | 87 | @Override 88 | protected void onDraw(Canvas canvas) { 89 | drawCircle(canvas); 90 | super.onDraw(canvas); 91 | } 92 | 93 | /** 94 | * @param canvas 95 | */ 96 | private void drawCircle(Canvas canvas) { 97 | mEndDiameter = Math.min(canvas.getWidth(), canvas.getHeight()); 98 | mColorDiameter = mStartDiameter + (mEndDiameter - mStartDiameter) / 2; 99 | 100 | //绘制波纹,同时改变透明度 101 | for (int i = 0; i < mCircleRadiusList.size(); i++) { 102 | int r = mCircleRadiusList.get(i);//绘制的半径 103 | 104 | if (r < mColorDiameter / 2) { 105 | mCirclePaint.setAlpha(maxPaintAlpha * (r - mStartDiameter / 2) / ((mEndDiameter - mStartDiameter) / 2));//根据半径来让透明度变化 106 | } else { 107 | mCirclePaint.setAlpha(maxPaintAlpha - maxPaintAlpha * (r - mStartDiameter / 2) / ((mEndDiameter - mStartDiameter) / 2));//根据半径来让透明度变化 108 | } 109 | 110 | canvas.drawCircle(mEndDiameter / 2, mEndDiameter / 2, r, mCirclePaint); 111 | } 112 | } 113 | 114 | /** 115 | * 控制圆圈的显示逻辑 116 | */ 117 | private void controlCircle() { 118 | //隔一段时间添加一个波 119 | if (System.currentTimeMillis() - mCurrentTime > 600) { 120 | mCircleRadiusList.add(mStartDiameter / 2); 121 | mCurrentTime = System.currentTimeMillis();//当前时间重新赋值刷新 122 | } 123 | 124 | //改变半径的值 125 | for (int i = 0; i < mCircleRadiusList.size(); i++) { 126 | mCircleRadiusList.set(i, mCircleRadiusList.get(i) + 1);//不断的改变半径 127 | } 128 | 129 | //性能优化,控制波的数量(迭代器) 130 | Iterator iterator = mCircleRadiusList.iterator(); 131 | while (iterator.hasNext()) { 132 | Integer next = iterator.next();//获取这个值 133 | if (next >= mEndDiameter / 2) {//大于结束时半径并且包含则移除 134 | if (mCircleRadiusList.contains(next)) { 135 | iterator.remove();//使用迭代器来移除(否则有异常) 136 | } 137 | } 138 | } 139 | } 140 | 141 | /** 142 | * 开始动画 143 | */ 144 | public void onStart() { 145 | mHandler.post(mRunnable); 146 | } 147 | 148 | /** 149 | * 开始动画 150 | * 151 | * @param loop 152 | */ 153 | public void onStart(boolean loop) { 154 | isLoop = loop; 155 | mHandler.post(mRunnable); 156 | } 157 | 158 | /** 159 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 160 | */ 161 | private int dp2px(float dpValue) { 162 | final float scale = mContext.getResources().getDisplayMetrics().density; 163 | return (int) (dpValue * scale + 0.5f); 164 | } 165 | 166 | /** 167 | * 设置RippleView开始显示时的直径 168 | * 169 | * @param startDiameterDp 直径(单位:dp) 170 | */ 171 | public void setStartDiameter(int startDiameterDp) { 172 | mStartDiameter = dp2px(startDiameterDp); 173 | mCircleRadius = mStartDiameter / 2; 174 | mCircleRadiusList.clear(); 175 | mCircleRadiusList.add(mCircleRadius); 176 | } 177 | 178 | /** 179 | * 设置RippleView结束显示时的直径 180 | * 181 | * @param endDiameter 直径(单位:px) 182 | */ 183 | public void setEndDiameter(int endDiameter) { 184 | this.mRippleWidth = endDiameter; 185 | } 186 | 187 | /** 188 | * 设置RippleView线条的颜色 189 | * 190 | * @param rippleColor 颜色 191 | */ 192 | public void setRippleColor(int rippleColor) { 193 | mCirclePaint.setColor(rippleColor); 194 | } 195 | 196 | /** 197 | * 设置是否循环显示动画 198 | * 199 | * @param loop 200 | */ 201 | public void setLoop(boolean loop) { 202 | isLoop = loop; 203 | } 204 | 205 | public void setMode(Mode mode){ 206 | 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /app/src/main/java/com/kince/rippleview/draw/HalfRippleView.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.kince.rippleview.draw; 5 | 6 | import android.content.Context; 7 | import android.graphics.Bitmap; 8 | import android.graphics.BitmapFactory; 9 | import android.graphics.Canvas; 10 | import android.graphics.Color; 11 | import android.graphics.Paint; 12 | import android.graphics.RectF; 13 | import android.os.Handler; 14 | import android.os.Message; 15 | import android.util.AttributeSet; 16 | import android.view.View; 17 | 18 | import com.kince.rippleview.R; 19 | 20 | /** 21 | * @author kince 22 | * @version v1.0.0 23 | * @category ²¨ÎÆ 24 | * @since 2014.8.9 25 | */ 26 | public class HalfRippleView extends View { 27 | 28 | private int mScreenWidth; 29 | private int mScreenHeight; 30 | 31 | private Bitmap mRippleBitmap; 32 | private Paint mRipplePaint = new Paint(); 33 | 34 | private int mBitmapWidth; 35 | private int mBitmapHeight; 36 | 37 | private boolean isStartRipple; 38 | 39 | private int heightPaddingTop; 40 | private int heightPaddingBottom; 41 | private int widthPaddingLeft; 42 | private int widthPaddingRight; 43 | 44 | private RectF mRect = new RectF(); 45 | 46 | private int rippleFirstRadius = 0; 47 | private int rippleSecendRadius = -33; 48 | private int rippleThirdRadius = -66; 49 | 50 | private Paint textPaint = new Paint(); 51 | private String mText = "µã»÷ÎÒ°É"; 52 | 53 | private Handler handler = new Handler() { 54 | @Override 55 | public void handleMessage(Message msg) { 56 | // TODO Auto-generated method stub 57 | super.handleMessage(msg); 58 | invalidate(); 59 | if (isStartRipple) { 60 | rippleFirstRadius++; 61 | if (rippleFirstRadius > 100) { 62 | rippleFirstRadius = 0; 63 | } 64 | rippleSecendRadius++; 65 | if (rippleSecendRadius > 100) { 66 | rippleSecendRadius = 0; 67 | } 68 | rippleThirdRadius++; 69 | if (rippleThirdRadius > 100) { 70 | rippleThirdRadius = 0; 71 | } 72 | sendEmptyMessageDelayed(0, 20); 73 | } 74 | } 75 | }; 76 | 77 | /** 78 | * @param context 79 | */ 80 | public HalfRippleView(Context context) { 81 | super(context); 82 | // TODO Auto-generated constructor stub 83 | init(); 84 | } 85 | 86 | /** 87 | * @param context 88 | * @param attrs 89 | */ 90 | public HalfRippleView(Context context, AttributeSet attrs) { 91 | super(context, attrs); 92 | // TODO Auto-generated constructor stub 93 | init(); 94 | } 95 | 96 | /** 97 | * @param context 98 | * @param attrs 99 | * @param defStyleAttr 100 | */ 101 | public HalfRippleView(Context context, AttributeSet attrs, int defStyleAttr) { 102 | super(context, attrs, defStyleAttr); 103 | // TODO Auto-generated constructor stub 104 | init(); 105 | } 106 | 107 | private void init() { 108 | mRipplePaint.setColor(4961729); 109 | mRipplePaint.setAntiAlias(true); 110 | mRipplePaint.setStyle(Paint.Style.FILL); 111 | 112 | textPaint.setTextSize(30); 113 | textPaint.setAntiAlias(true); 114 | textPaint.setStyle(Paint.Style.FILL); 115 | textPaint.setColor(Color.WHITE); 116 | 117 | mRippleBitmap = BitmapFactory.decodeStream(getResources() 118 | .openRawResource(R.drawable.easy3d_ic_apply)); 119 | mBitmapWidth = mRippleBitmap.getWidth(); 120 | mBitmapHeight = mRippleBitmap.getHeight(); 121 | } 122 | 123 | @Override 124 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 125 | // TODO Auto-generated method stub 126 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 127 | int mh = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 128 | int mw = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); 129 | if (mBitmapWidth < 2 * mBitmapHeight) { 130 | mBitmapWidth = (2 * mBitmapHeight); 131 | } 132 | setMeasuredDimension(mBitmapWidth, mBitmapHeight); 133 | } 134 | 135 | @Override 136 | protected void onDraw(Canvas canvas) { 137 | // TODO Auto-generated method stub 138 | super.onDraw(canvas); 139 | if (isStartRipple) { 140 | float f1 = 3 * mBitmapHeight / 10; 141 | mRipplePaint.setAlpha(255); 142 | canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 143 | 7 * mBitmapHeight / 10, mRipplePaint); 144 | int i1 = (int) (220.0F - (220.0F - 0.0F) / 100.0F 145 | * rippleFirstRadius); 146 | mRipplePaint.setAlpha(i1); 147 | canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7 148 | * mBitmapHeight / 10 + f1 * rippleFirstRadius / 100.0F, 149 | mRipplePaint); 150 | if (rippleSecendRadius >= 0) { 151 | int i3 = (int) (220.0F - (220.0F - 0.0F) / 100.0F 152 | * rippleSecendRadius); 153 | mRipplePaint.setAlpha(i3); 154 | canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 155 | 7 * mBitmapHeight / 10 + f1 * rippleSecendRadius 156 | / 100.0F, mRipplePaint); 157 | } 158 | if (rippleThirdRadius >= 0) { 159 | int i2 = (int) (220.0F - (220.0F - 0.0F) / 100.0F 160 | * rippleThirdRadius); 161 | mRipplePaint.setAlpha(i2); 162 | canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7 163 | * mBitmapHeight / 10 + f1 * rippleThirdRadius / 100.0F, 164 | mRipplePaint); 165 | } 166 | 167 | } 168 | mRipplePaint.setAlpha(30); 169 | canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, mBitmapHeight, 170 | mRipplePaint); 171 | mRipplePaint.setAlpha(120); 172 | canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 173 | 9 * mBitmapHeight / 10, mRipplePaint); 174 | mRipplePaint.setAlpha(180); 175 | canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 176 | 8 * mBitmapHeight / 10, mRipplePaint); 177 | mRipplePaint.setAlpha(255); 178 | canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 179 | 7 * mBitmapHeight / 10, mRipplePaint); 180 | float length = textPaint.measureText(mText); 181 | canvas.drawText(mText, (mBitmapWidth - length) / 2, 182 | mBitmapHeight * 3 / 4, textPaint); 183 | } 184 | 185 | @Override 186 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 187 | // TODO Auto-generated method stub 188 | super.onSizeChanged(w, h, oldw, oldh); 189 | mScreenWidth = w; 190 | mScreenHeight = h; 191 | confirmSize(); 192 | invalidate(); 193 | } 194 | 195 | private void confirmSize() { 196 | int minScreenSize = Math.min(mScreenWidth, mScreenHeight); 197 | int widthOverSize = mScreenWidth - minScreenSize; 198 | int heightOverSize = mScreenHeight - minScreenSize; 199 | heightPaddingTop = (getPaddingTop() + heightOverSize / 2); 200 | heightPaddingBottom = (getPaddingBottom() + heightOverSize / 2); 201 | widthPaddingLeft = (getPaddingLeft() + widthOverSize / 2); 202 | widthPaddingRight = (getPaddingRight() + widthOverSize / 2); 203 | 204 | int width = getWidth(); 205 | int height = getHeight(); 206 | 207 | mRect = new RectF(widthPaddingLeft, heightPaddingTop, width 208 | - widthPaddingRight, height * 2 - heightPaddingBottom); 209 | } 210 | 211 | public void stratRipple() { 212 | isStartRipple = true; 213 | handler.sendEmptyMessage(0); 214 | } 215 | 216 | public void stopRipple() { 217 | isStartRipple = false; 218 | handler.removeMessages(0); 219 | } 220 | 221 | } 222 | -------------------------------------------------------------------------------- /app/src/main/java/com/kince/rippleview/draw/ObjectRippleView.java: -------------------------------------------------------------------------------- 1 | package com.kince.rippleview.draw; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.util.AttributeSet; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.view.animation.Interpolator; 10 | import android.view.animation.LinearInterpolator; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Iterator; 14 | import java.util.List; 15 | 16 | /** 17 | * 水波纹特效 18 | *

19 | * Created by fbchen2 on 2016/5/25. 20 | */ 21 | public class ObjectRippleView extends View { 22 | 23 | private float mInitialRadius = 50; // 初始波纹半径 24 | 25 | private float mMaxRadius; // 最大波纹半径 26 | 27 | private long mDuration = 1000; // 一个波纹从创建到消失的持续时间 28 | 29 | private int mSpeed = 500; // 波纹的创建速度,每500ms创建一个 30 | 31 | private float mMaxRadiusRate = 0.85f; 32 | 33 | private boolean mMaxRadiusSet; 34 | 35 | private boolean mIsRunning; 36 | 37 | private long mLastCreateTime; 38 | 39 | private List mCircleList = new ArrayList(); 40 | 41 | private Runnable mCreateCircle = new Runnable() { 42 | 43 | @Override 44 | public void run() { 45 | if (mIsRunning) { 46 | newCircle(); 47 | postDelayed(mCreateCircle, mSpeed); 48 | } 49 | } 50 | }; 51 | 52 | private Interpolator mInterpolator = new LinearInterpolator(); 53 | 54 | private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 55 | 56 | public ObjectRippleView(Context context) { 57 | super(context); 58 | } 59 | 60 | public ObjectRippleView(Context context, AttributeSet attrs) { 61 | super(context, attrs); 62 | } 63 | 64 | public void setStyle(Paint.Style style) { 65 | mPaint.setStyle(style); 66 | } 67 | 68 | @Override 69 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 70 | if (!mMaxRadiusSet) { 71 | mMaxRadius = Math.min(w, h) * mMaxRadiusRate / 2.0f; 72 | } 73 | } 74 | 75 | public void setMaxRadiusRate(float maxRadiusRate) { 76 | mMaxRadiusRate = maxRadiusRate; 77 | } 78 | 79 | public void setColor(int color) { 80 | mPaint.setColor(color); 81 | } 82 | 83 | /** 84 | * 开始 85 | */ 86 | public void start() { 87 | if (!mIsRunning) { 88 | mIsRunning = true; 89 | mCreateCircle.run(); 90 | } 91 | } 92 | 93 | /** 94 | * 缓慢停止 95 | */ 96 | public void stop() { 97 | mIsRunning = false; 98 | } 99 | 100 | /** 101 | * 立即停止 102 | */ 103 | public void stopImmediately() { 104 | mIsRunning = false; 105 | mCircleList.clear(); 106 | invalidate(); 107 | } 108 | 109 | protected void onDraw(Canvas canvas) { 110 | Iterator iterator = mCircleList.iterator(); 111 | 112 | while (iterator.hasNext()) { 113 | Circle circle = iterator.next(); 114 | float radius = circle.getCurrentRadius(); 115 | 116 | if (System.currentTimeMillis() - circle.mCreateTime < mDuration) { 117 | mPaint.setAlpha(circle.getAlpha()); 118 | canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mPaint); 119 | } else { 120 | iterator.remove(); 121 | } 122 | } 123 | 124 | if (mCircleList.size() > 0) { 125 | postInvalidateDelayed(10); 126 | } 127 | } 128 | 129 | public void setInitialRadius(float radius) { 130 | mInitialRadius = radius; 131 | } 132 | 133 | public void setDuration(long duration) { 134 | mDuration = duration; 135 | } 136 | 137 | public void setMaxRadius(float maxRadius) { 138 | mMaxRadius = maxRadius; 139 | mMaxRadiusSet = true; 140 | } 141 | 142 | public void setSpeed(int speed) { 143 | mSpeed = speed; 144 | } 145 | 146 | private void newCircle() { 147 | long currentTime = System.currentTimeMillis(); 148 | if (currentTime - mLastCreateTime < mSpeed) { 149 | return; 150 | } 151 | Circle circle = new Circle(); 152 | mCircleList.add(circle); 153 | invalidate(); 154 | mLastCreateTime = currentTime; 155 | } 156 | 157 | private class Circle { 158 | private long mCreateTime; 159 | 160 | Circle() { 161 | mCreateTime = System.currentTimeMillis(); 162 | } 163 | 164 | int getAlpha() { 165 | float percent = (getCurrentRadius() - mInitialRadius) / (mMaxRadius - mInitialRadius); 166 | return (int) (255 - mInterpolator.getInterpolation(percent) * 255); 167 | } 168 | 169 | float getCurrentRadius() { 170 | float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mDuration; 171 | Log.i("Kince","ss = "+(mInitialRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mInitialRadius))); 172 | return mInitialRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mInitialRadius); 173 | } 174 | } 175 | 176 | public void setInterpolator(Interpolator interpolator) { 177 | mInterpolator = interpolator; 178 | } 179 | 180 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/easy3d_ic_apply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/app/src/main/res/drawable-hdpi/easy3d_ic_apply.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/easy3d_ic_apply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/app/src/main/res/drawable-mdpi/easy3d_ic_apply.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/easy3d_ic_apply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/app/src/main/res/drawable-xhdpi/easy3d_ic_apply.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/easy3d_ic_apply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/app/src/main/res/drawable-xxhdpi/easy3d_ic_apply.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 |

4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 64dp 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RippleView 5 | Hello world! 6 | Settings 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:2.3.1' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | jcenter() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Apr 06 14:23:03 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /ripple.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroKince/RippleView/2c50679590d52ab161c866bb8643764c17f30fb7/ripple.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------