最近看到360、UC、网易新闻客户端都应用了水波纹效果,就在私下里也研究了一下,参照GIT上大神的分享,自己也跟着做了一个示例,下面先看效果:


1.RippleEffect核心实现类

packagecom.example.RippleEffect;importandroid.content.Context;importandroid.content.res.TypedArray;importandroid.graphics.Bitmap;importandroid.graphics.Canvas;importandroid.graphics.Color;importandroid.graphics.Paint;importandroid.graphics.PorterDuff;importandroid.graphics.PorterDuffXfermode;importandroid.graphics.Rect;importandroid.os.Handler;importandroid.support.annotation.ColorRes;importandroid.util.AttributeSet;importandroid.view.GestureDetector;importandroid.view.MotionEvent;importandroid.view.animation.Animation;importandroid.view.animation.ScaleAnimation;importandroid.widget.AdapterView;importandroid.widget.RelativeLayout;/***RippleViewcustomlayout**CustomLayoutthatallowstouseRippleUIpatternaboveAPI21*/publicclassRippleViewextendsRelativeLayout{privateintWIDTH;privateintHEIGHT;privateintframeRate=10;privateintrippleDuration=400;privateintrippleAlpha=90;privateHandlercanvasHandler;privatefloatradiusMax=0;privatebooleananimationRunning=false;privateinttimer=0;privateinttimerEmpty=0;privateintdurationEmpty=-1;privatefloatx=-1;privatefloaty=-1;privateintzoomDuration;privatefloatzoomScale;privateScaleAnimationscaleAnimation;privateBooleanhasToZoom;privateBooleanisCentered;privateIntegerrippleType;privatePaintpaint;privateBitmaporiginBitmap;privateintrippleColor;privateintripplePadding;privateGestureDetectorgestureDetector;privatefinalRunnablerunnable=newRunnable(){@Overridepublicvoidrun(){invalidate();}};privateOnRippleCompleteListeneronCompletionListener;publicRippleView(Contextcontext){super(context);}publicRippleView(Contextcontext,AttributeSetattrs){super(context,attrs);init(context,attrs);}publicRippleView(Contextcontext,AttributeSetattrs,intdefStyle){super(context,attrs,defStyle);init(context,attrs);}/***Methodthatinitializesallfieldsandsetslisteners**@paramcontextContextusedtocreatethisview*@paramattrsAttributeusedtoinitializefields*/privatevoidinit(finalContextcontext,finalAttributeSetattrs){if(isInEditMode())return;finalTypedArraytypedArray=context.obtainStyledAttributes(attrs,R.styleable.RippleView);rippleColor=typedArray.getColor(R.styleable.RippleView_rv_color,getResources().getColor(R.color.rippelColor));rippleType=typedArray.getInt(R.styleable.RippleView_rv_type,0);hasToZoom=typedArray.getBoolean(R.styleable.RippleView_rv_zoom,false);isCentered=typedArray.getBoolean(R.styleable.RippleView_rv_centered,false);rippleDuration=typedArray.getInteger(R.styleable.RippleView_rv_rippleDuration,rippleDuration);frameRate=typedArray.getInteger(R.styleable.RippleView_rv_framerate,frameRate);rippleAlpha=typedArray.getInteger(R.styleable.RippleView_rv_alpha,rippleAlpha);ripplePadding=typedArray.getDimensionPixelSize(R.styleable.RippleView_rv_ripplePadding,0);canvasHandler=newHandler();zoomScale=typedArray.getFloat(R.styleable.RippleView_rv_zoomScale,1.03f);zoomDuration=typedArray.getInt(R.styleable.RippleView_rv_zoomDuration,200);typedArray.recycle();paint=newPaint();paint.setAntiAlias(true);paint.setStyle(Paint.Style.FILL);paint.setColor(rippleColor);paint.setAlpha(rippleAlpha);this.setWillNotDraw(false);gestureDetector=newGestureDetector(context,newGestureDetector.SimpleOnGestureListener(){@OverridepublicvoidonLongPress(MotionEventevent){super.onLongPress(event);animateRipple(event);sendClickEvent(true);}@OverridepublicbooleanonSingleTapConfirmed(MotionEvente){returntrue;}@OverridepublicbooleanonSingleTapUp(MotionEvente){returntrue;}});this.setDrawingCacheEnabled(true);this.setClickable(true);}@Overridepublicvoiddraw(Canvascanvas){super.draw(canvas);if(animationRunning){if(rippleDuration<=timer*frameRate){animationRunning=false;timer=0;durationEmpty=-1;timerEmpty=0;canvas.restore();invalidate();if(onCompletionListener!=null)onCompletionListener.onComplete(this);return;}elsecanvasHandler.postDelayed(runnable,frameRate);if(timer==0)canvas.save();canvas.drawCircle(x,y,(radiusMax*(((float)timer*frameRate)/rippleDuration)),paint);paint.setColor(Color.parseColor("#ffff4444"));if(rippleType==1&&originBitmap!=null&&(((float)timer*frameRate)/rippleDuration)>0.4f){if(durationEmpty==-1)durationEmpty=rippleDuration-timer*frameRate;timerEmpty++;finalBitmaptmpBitmap=getCircleBitmap((int)((radiusMax)*(((float)timerEmpty*frameRate)/(durationEmpty))));canvas.drawBitmap(tmpBitmap,0,0,paint);tmpBitmap.recycle();}paint.setColor(rippleColor);if(rippleType==1){if((((float)timer*frameRate)/rippleDuration)>0.6f)paint.setAlpha((int)(rippleAlpha-((rippleAlpha)*(((float)timerEmpty*frameRate)/(durationEmpty)))));elsepaint.setAlpha(rippleAlpha);}elsepaint.setAlpha((int)(rippleAlpha-((rippleAlpha)*(((float)timer*frameRate)/rippleDuration))));timer++;}}@OverrideprotectedvoidonSizeChanged(intw,inth,intoldw,intoldh){super.onSizeChanged(w,h,oldw,oldh);WIDTH=w;HEIGHT=h;scaleAnimation=newScaleAnimation(1.0f,zoomScale,1.0f,zoomScale,w/2,h/2);scaleAnimation.setDuration(zoomDuration);scaleAnimation.setRepeatMode(Animation.REVERSE);scaleAnimation.setRepeatCount(1);}/***LaunchRippleanimationforthecurrentviewwithaMotionEvent**@parameventMotionEventregisteredbytheRipplegesturelistener*/publicvoidanimateRipple(MotionEventevent){createAnimation(event.getX(),event.getY());}/***LaunchRippleanimationforthecurrentviewcenteredatxandyposition**@paramxHorizontalpositionoftheripplecenter*@paramyVerticalpositionoftheripplecenter*/publicvoidanimateRipple(finalfloatx,finalfloaty){createAnimation(x,y);}/***CreateRippleanimationcenteredatx,y**@paramxHorizontalpositionoftheripplecenter*@paramyVerticalpositionoftheripplecenter*/privatevoidcreateAnimation(finalfloatx,finalfloaty){if(this.isEnabled()&&!animationRunning){if(hasToZoom)this.startAnimation(scaleAnimation);radiusMax=Math.max(WIDTH,HEIGHT);if(rippleType!=2)radiusMax/=2;radiusMax-=ripplePadding;if(isCentered||rippleType==1){this.x=getMeasuredWidth()/2;this.y=getMeasuredHeight()/2;}else{this.x=x;this.y=y;}animationRunning=true;if(rippleType==1&&originBitmap==null)originBitmap=getDrawingCache(true);invalidate();}}@OverridepublicbooleanonTouchEvent(MotionEventevent){if(gestureDetector.onTouchEvent(event)){animateRipple(event);sendClickEvent(false);}returnsuper.onTouchEvent(event);}@OverridepublicbooleanonInterceptTouchEvent(MotionEventevent){this.onTouchEvent(event);returnsuper.onInterceptTouchEvent(event);}/***SendaclickeventifparentviewisaListviewinstance**@paramisLongClickIstheeventalongclick?*/privatevoidsendClickEvent(finalBooleanisLongClick){if(getParent()instanceofAdapterView){finalAdapterViewadapterView=(AdapterView)getParent();finalintposition=adapterView.getPositionForView(this);finallongid=adapterView.getItemIdAtPosition(position);if(isLongClick){if(adapterView.getOnItemLongClickListener()!=null)adapterView.getOnItemLongClickListener().onItemLongClick(adapterView,this,position,id);}else{if(adapterView.getOnItemClickListener()!=null)adapterView.getOnItemClickListener().onItemClick(adapterView,this,position,id);}}}privateBitmapgetCircleBitmap(finalintradius){finalBitmapoutput=Bitmap.createBitmap(originBitmap.getWidth(),originBitmap.getHeight(),Bitmap.Config.ARGB_8888);finalCanvascanvas=newCanvas(output);finalPaintpaint=newPaint();finalRectrect=newRect((int)(x-radius),(int)(y-radius),(int)(x+radius),(int)(y+radius));paint.setAntiAlias(true);canvas.drawARGB(0,0,0,0);canvas.drawCircle(x,y,radius,paint);paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));canvas.drawBitmap(originBitmap,rect,rect,paint);returnoutput;}/***SetRipplecolor,defaultis#FFFFFF**@paramrippleColorNewcolorresource*/@ColorRespublicvoidsetRippleColor(intrippleColor){this.rippleColor=getResources().getColor(rippleColor);}publicintgetRippleColor(){returnrippleColor;}publicRippleTypegetRippleType(){returnRippleType.values()[rippleType];}/***SetRippletype,defaultisRippleType.SIMPLE**@paramrippleTypeNewRippletypefornextanimation*/publicvoidsetRippleType(finalRippleTyperippleType){this.rippleType=rippleType.ordinal();}publicBooleanisCentered(){returnisCentered;}/***Setifrippleanimationhastobecenteredinitsparentviewornot,defaultisFalse**@paramisCentered*/publicvoidsetCentered(finalBooleanisCentered){this.isCentered=isCentered;}publicintgetRipplePadding(){returnripplePadding;}/***SetRipplepaddingifyouwanttoavoidsomegraphicglitch**@paramripplePaddingNewRipplepaddinginpixel,defaultis0px*/publicvoidsetRipplePadding(intripplePadding){this.ripplePadding=ripplePadding;}publicBooleanisZooming(){returnhasToZoom;}/***AttheendofRippleeffect,thechildviewshastozoom**@paramhasToZoomDothechildviewshavetozoom?defaultisFalse*/publicvoidsetZooming(BooleanhasToZoom){this.hasToZoom=hasToZoom;}publicfloatgetZoomScale(){returnzoomScale;}/***Scaleoftheendanimation**@paramzoomScaleValueofscaleanimation,defaultis1.03f*/publicvoidsetZoomScale(floatzoomScale){this.zoomScale=zoomScale;}publicintgetZoomDuration(){returnzoomDuration;}/***Durationoftheendinganimationinms**@paramzoomDurationDuration,defaultis200ms*/publicvoidsetZoomDuration(intzoomDuration){this.zoomDuration=zoomDuration;}publicintgetRippleDuration(){returnrippleDuration;}/***DurationoftheRippleanimationinms**@paramrippleDurationDuration,defaultis400ms*/publicvoidsetRippleDuration(intrippleDuration){this.rippleDuration=rippleDuration;}publicintgetFrameRate(){returnframeRate;}/***SetframerateforRippleanimation**@paramframeRateNewframeratevalue,defaultis10*/publicvoidsetFrameRate(intframeRate){this.frameRate=frameRate;}publicintgetRippleAlpha(){returnrippleAlpha;}/***Setalphaforrippleeffectcolor**@paramrippleAlphaAlphavaluebetween0and255,defaultis90*/publicvoidsetRippleAlpha(intrippleAlpha){this.rippleAlpha=rippleAlpha;}publicvoidsetOnRippleCompleteListener(OnRippleCompleteListenerlistener){this.onCompletionListener=listener;}/***DefinesacallbackcalledattheendoftheRippleeffect*/publicinterfaceOnRippleCompleteListener{voidonComplete(RippleViewrippleView);}publicenumRippleType{SIMPLE(0),DOUBLE(1),RECTANGLE(2);inttype;RippleType(inttype){this.type=type;}}}

2.自定义属性

<?xmlversion="1.0"encoding="utf-8"?><resources><declare-styleablename="RippleView">rv_zoomDuration<attrname="rv_alpha"format="integer"/><attrname="rv_framerate"format="integer"/><attrname="rv_rippleDuration"format="integer"/><attrname="rv_zoomDuration"format="integer"/><attrname="rv_color"format="color"/><attrname="rv_centered"format="boolean"/><attrname="rv_type"format="enum"><enumname="simpleRipple"value="0"/><enumname="doubleRipple"value="1"/><enumname="rectangle"value="2"/></attr><attrname="rv_ripplePadding"format="dimension"/><attrname="rv_zoom"format="boolean"/><attrname="rv_zoomScale"format="float"/></declare-styleable></resources>

3.主布局文件

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:ripple="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_horizontal"android:orientation="vertical"><!--1rv_centered="true"rv_type="simpleRipple"--><com.example.RippleEffect.RippleViewandroid:id="@+id/more"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"ripple:rv_centered="true"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#BAC9FF"android:padding="15dp"android:src="@drawable/ic_launcher"/></com.example.RippleEffect.RippleView><!--2rv_centered="false"rv_type="simpleRipple"--><com.example.RippleEffect.RippleViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"ripple:rv_centered="false"ripple:rv_type="simpleRipple"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#BAC9FF"android:padding="15dp"android:src="@drawable/ic_launcher"/></com.example.RippleEffect.RippleView><!--3rv_type="doubleRipple"--><com.example.RippleEffect.RippleViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"ripple:rv_type="doubleRipple"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#BAC9FF"android:padding="15dp"android:src="@drawable/ic_launcher"/></com.example.RippleEffect.RippleView><!--4rv_type="rectangle"--><com.example.RippleEffect.RippleViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"ripple:rv_type="doubleRipple"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#BAC9FF"android:padding="15dp"android:src="@drawable/ic_launcher"/></com.example.RippleEffect.RippleView><!--5rv_zoom="true"rv_ripplePadding="20dp"ripple:rv_zoomScale="1.25"--><com.example.RippleEffect.RippleViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"ripple:rv_centered="false"ripple:rv_color="#D91615"ripple:rv_rippleDuration="2000"ripple:rv_ripplePadding="20dp"ripple:rv_zoom="true"ripple:rv_zoomDuration="200"ripple:rv_zoomScale="1.25"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#BAC9FF"android:padding="15dp"android:src="@drawable/ic_launcher"/></com.example.RippleEffect.RippleView><!--6rv_type="simpleRipple"rv_alpha="10"rv_framerate="100"--><com.example.RippleEffect.RippleViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"ripple:rv_alpha="200"ripple:rv_framerate="100"ripple:rv_type="simpleRipple"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#BAC9FF"android:padding="15dp"android:src="@drawable/ic_launcher"/></com.example.RippleEffect.RippleView><!--7rv_type="simpleRipple"rv_alpha="10"rv_framerate="2"--><com.example.RippleEffect.RippleViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"ripple:rv_alpha="200"ripple:rv_framerate="2"ripple:rv_type="simpleRipple"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#BAC9FF"android:padding="15dp"android:src="@drawable/ic_launcher"/></com.example.RippleEffect.RippleView><!--8rv_type="simpleRipple"rv_alpha="10"rv_framerate="2"--><com.example.RippleEffect.RippleViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"ripple:rv_alpha="200"ripple:rv_framerate="2"ripple:rv_type="simpleRipple"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#BAC9FF"android:padding="15dp"android:text="Button"/></com.example.RippleEffect.RippleView></LinearLayout></ScrollView></LinearLayout>

感谢git上大神的热情分享给予的帮助,以上就是实现水波纹效果的全部实现,仅供大家参考学习,欢迎一起学习交流~