原文地址:http://m.blog.csdn.net/blog/u012403246/42869009
这是大神写的水波纹效果demo,我把核心代码拷贝出来,放到这里,方便我以后用的时候直接来取,
该类继承linearLayout,并且可以直接应用到xml布局文件中,兼容android3.0以上系统,下面是核心代码:
package com.example.administrator.text;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import java.util.ArrayList;
public class RippleLayout extends LinearLayout implements Runnable{
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float mCenterX,mCenterY;
private int[] mLocation = new int[2];
private int INVALIDATE_DURATION = 40;
private int mTargetHeight,mTargetWidth;
private int mRevealRadius = 0,mRevealRadiusGap,mMaxRadius;
private int mMinBetweenWidthAndHeight,mMaxBetweenWidthAndHeight;
private boolean mIsPressed;
private boolean mShouldDoAnimation;
private View mTargetView;
private DispatchUpTouchEventRunnable mDispatchUpTouchEventRunnable = new DispatchUpTouchEventRunnable();
public RippleLayout(Context context) {
super(context);
init();
}
public RippleLayout(Context context, AttributeSet attrs){
super(context,attrs);
init();
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RippleLayout(Context context, AttributeSet attrs, int defStyleAttr){
super(context,attrs,defStyleAttr);
init();
}
public void init(){
setWillNotDraw(false);
mPaint.setColor(getResources().getColor(R.color.reveal_color));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
this.getLocationOnScreen(mLocation);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if(mTargetView == null || !mShouldDoAnimation || mTargetWidth <= 0)
return;
if(mRevealRadius > mMinBetweenWidthAndHeight / 2)
mRevealRadius += mRevealRadiusGap * 4;
else
mRevealRadius += mRevealRadiusGap;
int[] location = new int[2];
this.getLocationOnScreen(mLocation);
mTargetView.getLocationOnScreen(location);
int top = location[1] - mLocation[1];
int left = location[0] - mLocation[0];
int right = left + mTargetView.getMeasuredWidth();
int bottom = top + mTargetView.getMeasuredHeight();
canvas.save();
canvas.clipRect(left, top, right, bottom);
canvas.drawCircle(mCenterX, mCenterY, mRevealRadius, mPaint);
canvas.restore();
if(mRevealRadius <= mMaxRadius)
postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);
else if(!mIsPressed){
mShouldDoAnimation = false;
postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int x = (int)event.getRawX();
int y = (int)event.getRawY();
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
View targetView = getTargetView(this,x,y);
if(targetView != null && targetView.isEnabled()){
mTargetView = targetView;
initParametersForChild(event,targetView);
postInvalidateDelayed(INVALIDATE_DURATION);
}
break;
case MotionEvent.ACTION_UP:
mIsPressed = false;
postInvalidateDelayed(INVALIDATE_DURATION);
mDispatchUpTouchEventRunnable.event = event;
postDelayed(mDispatchUpTouchEventRunnable, 40);
break;
case MotionEvent.ACTION_CANCEL:
mIsPressed = false;
postInvalidateDelayed(INVALIDATE_DURATION);
break;
}
return super.dispatchTouchEvent(event);
}
public View getTargetView(View view,int x,int y){
View target = null;
ArrayList<View> views = view.getTouchables();
for(View child : views)
if(isTouchPointInView(child,x,y)){
target = child;
break;
}
return target;
}
public boolean isTouchPointInView(View child,int x,int y){
int[] location = new int[2];
child.getLocationOnScreen(location);
int top = location[1];
int left = location[0];
int right = left + child.getMeasuredWidth();
int bottom = top + child.getMeasuredHeight();
if(child.isClickable() && y>=top && y<= bottom && x >= left && x<= right)
return true;
else
return false;
}
public void initParametersForChild(MotionEvent event,View view){
mCenterX = event.getX();
mCenterY = event.getY();
mTargetWidth = view.getMeasuredWidth();
mTargetHeight = view.getMeasuredHeight();
mMinBetweenWidthAndHeight = Math.min(mTargetWidth, mTargetHeight);
mMaxBetweenWidthAndHeight = Math.max(mTargetWidth, mTargetHeight);
mRevealRadius = 0;
mRevealRadiusGap = mMinBetweenWidthAndHeight / 8;
mIsPressed = true;
mShouldDoAnimation = true;
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0] - mLocation[0];
int mTransformedCenterX = (int)mCenterX - left;
mMaxRadius = Math.max(mTransformedCenterX, mTargetWidth - mTransformedCenterX);
}
@Override
public void run() {
super.performClick();
}
@Override
public boolean performClick() {
postDelayed(this,40);
return true;
}
private class DispatchUpTouchEventRunnable implements Runnable{
public MotionEvent event;
@Override
public void run() {
if(mTargetView.isEnabled() && mTargetView.isClickable())
return;
if(isTouchPointInView(mTargetView, (int)event.getRawX(), (int)event.getRawX()))
mTargetView.performClick();
}
}
}
上面代码中需要一个color资源:这里贴上:
<color name="reveal_color">#1b000000</color>
OK,以上的代码就直接能实现水波纹效果,直接可以新建一个类,然后复制粘贴把以上代码放进去即可:
具体使用方法还是举个例子吧:如下代码:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
>
<com.example.administrator.text.RippleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:text="@string/hello_world"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
/>
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="45dp"
android:text="@string/hello_world"
android:clickable="true"
/>
</com.example.administrator.text.RippleLayout>
</RelativeLayout>
如上代码,直接用该类包裹想要实现水波纹效果的控件,即可让里面的控件实现水波纹效果,这里要注意,像textView这样的控件,本身是不可点击的,所以也就没有水波纹效果,若要实现水波纹效果,就要加一个android:clickable=" "属性,且属性值设为true,
同时也说明一下,这个类有一个小bug,当点击按钮进入下一个界面时,水波纹还没有扩散完就进入到下一个界面了,不过并没有什么大碍,一样可以使用,
并且这个类有局限性,比如当包裹GridView时,就会报空指针异常