本文将以动画形式来实现水波纹效果,核心思想就是点击的时候通过执行一张图片的动画来达到水波纹效果。
首选把水波纹效果的代码贴出来,本文使用了三个类,如下。
类WaterRippleActivity.java
import android.app.Activity;
import android.os.Bundle;
import com.example.kingsoft.CustomAdapter.R;
import com.example.kingsoft.CustomWidget.WaterRippleFrameLayout;
public class WaterRippleActivity extends Activity {
WaterRippleFrameLayout waterRippleFrameLayout =
null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.water_ripple_layout);
waterRippleFrameLayout = (WaterRippleFrameLayout)findViewById(R.id.water_repple_framelayout);
waterRippleFrameLayout.init();
}
}
类WaterRippleFrameLayout.java
import android.content.Context;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.example.kingsoft.CustomAdapter.R;
public
class WaterRippleFrameLayout extends FrameLayout{
private ImageView mImageView =
null;
private boolean mIsInit =
false;
public WaterRippleFrameLayout(
@NonNull Context context) {
super(context);
}
public WaterRippleFrameLayout(
@NonNull Context context,
@Nullable AttributeSet attrs) {
super(context, attrs);
}
public WaterRippleFrameLayout(
@NonNull Context context,
@Nullable AttributeSet attrs,
@AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public WaterRippleFrameLayout(
@NonNull Context context,
@Nullable AttributeSet attrs,
@AttrRes int defStyleAttr,
@StyleRes int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP){
onClick(mImageView,ev);
}
return true;
//super.dispatchTouchEvent(ev);
}
public
void init(){
if (mIsInit)
return;
getViewTreeObserver
().addOnPreDrawListener(() -> {
if (!mIsInit){
mImageView = (ImageView)findViewById(R.id.ppt_remote_img_clicker);
mImageView.setVisibility(GONE);
mIsInit = true;
}
return true;
});
}
public void onClick(View v, MotionEvent ev) {
if (null != mImageView) {
float curX = ev.getX();
float curY = ev.getY();
mImageView.setVisibility(VISIBLE);
ViewLayoutUnitl.setViewMargin(mImageView, (int)(curX - mImageView.getWidth()/2), (int)(curY - mImageView.getHeight()/2));
doWaterRippleAnim(mImageView);
}
}
public void doWaterRippleAnim(View view){
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
AnimationSet animationSet = new AnimationSet(true);
ScaleAnimation scaleAnimation = new ScaleAnimation(1,2,1,2);
AlphaAnimation alphaAnimation = new AlphaAnimation(1,0);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(alphaAnimation);
animationSet.setDuration(1000);
animationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
view.setVisibility(GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
view.startAnimation(animationSet);
}
public static class ViewLayoutUnitl{
public static void setViewMargin(View view, int x, int y){
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params instanceof FrameLayout.LayoutParams){
((MarginLayoutParams)params).leftMargin = x;
((MarginLayoutParams)params).rightMargin = -x;
((MarginLayoutParams)params).topMargin = y;
((MarginLayoutParams)params).bottomMargin = -y;
view.setLayoutParams(params);
}else if (params instanceof LinearLayout.LayoutParams){
((LinearLayout.LayoutParams)params).leftMargin = x;
((LinearLayout.LayoutParams)params).rightMargin = -x;
((LinearLayout.LayoutParams)params).topMargin = y;
((LinearLayout.LayoutParams)params).bottomMargin = -y;
view.setLayoutParams(params);
}else {
FrameLayout.LayoutParams newParams = new FrameLayout.LayoutParams(params);
newParams.leftMargin = x;
newParams.rightMargin = -x;
newParams.topMargin = y;
newParams.bottomMargin = -y;
view.setLayoutParams(newParams);
}
}
}
}
资源文件water_ripple_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff">
<com.example.kingsoft.CustomWidget.WaterRippleFrameLayout
android:id="@+id/water_repple_framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/ppt_remote_img_clicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ppt_remote_touch_circle_black"/>
</com.example.kingsoft.CustomWidget.WaterRippleFrameLayout>
</LinearLayout>
图片:
核心方法doWaterRippleAnim讲解:通过Scale和Alpha动画来实现水波纹效果,即是一边进行缩放动画,一边进行透明度动画。增加动画的监听,当动画执行完毕即可隐藏本ImageView。
public void doWaterRippleAnim(View view){
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
AnimationSet animationSet =
new AnimationSet(
true);
ScaleAnimation scaleAnimation =
new ScaleAnimation(
1,
2,
1,
2);
AlphaAnimation alphaAnimation =
new AlphaAnimation(
1,
0);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(alphaAnimation);
animationSet.setDuration(
1000);
animationSet.setAnimationListener(
new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
view.setVisibility(GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
view.startAnimation(animationSet);
}
内部类ViewLayoutUnitl,里面是计算点击事件执行动画的坐标,通过margin的偏移值来实现。
注意以下代码:addOnPreDrawListener()是在绘制之前执行的,控件都会经历mesure -> layout ->draw,最后呈现在桌面,而只有经过mesure和layout之后才能精准获取到控件尺寸,因此经常会通过addOnPreDrawListener()来获取控件尺寸;本例中通过这个函数来获取子对象ImageView。注意下面代码采用拉姆表达式。
getViewTreeObserver
().addOnPreDrawListener(() -> {
if (!mIsInit){
mImageView = (ImageView)findViewById(R.id.ppt_remote_img_clicker);
mImageView.setVisibility(GONE);
mIsInit = true;
}
return true;
});