自定义水波纹效果,android3.0以上都可以用

原文地址: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时,就会报空指针异常

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值