Open xhcui2008 opened 7 years ago
你好,谢谢你得反馈,下一版本会解决这个问题。 这个问题是因为移动view后,相对应窗体上的rippleLayout的位置没有改变所导致的,目前是打算采用监听view的位置变化改变的方式来解决这个问题。 不知到你有没有其他方法和思路
想法倒是有,但是也存在问题,但是我的方案和你的方案是互补的,但是仍然有问题 我的方法是继承我需要使用的制定的View控件,然后在这个控件里面做动画,然后规定他只能随着动画运行,但是存在比如说Activity切换的时候,我点击这个View跳转,并且这个动画执行了一半,动画就暂停了,让从跳转的Activity返回以后,这个动画会继续运行,或者在popupwindow里面也会出现这个问题,
`public class RippleLinearLayout extends LinearLayout {
private Paint mPaint;
private int clickedViewWidth;
private int clickedViewHeight;
private int mMaxRippleRadius;
private int mRippleRadiusGap;
private int mRippleRadius = 0;
private float mCenterX;
private float mCenterY;
private int[] mLocationInScreen = new int[2];
private boolean shouldDrawRipple = false;
private boolean isPressed = false;
private int INVALIDATE_DURATION = 50;
private View clickedView;
private boolean isClickedParent = false;
public RippleLinearLayout(Context context) {
super(context);
init();
}
public RippleLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RippleLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
setWillNotDraw(false);
mPaint.setColor(Color.argb(50, 170, 170, 170));
}
public void setRippleColor(int color) {
mPaint.setColor(color);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
this.getLocationOnScreen(mLocationInScreen);
}
@Override public boolean dispatchTouchEvent(MotionEvent event) { int x = (int) event.getRawX(); int y = (int) event.getRawY(); int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { View clickedView = getTouchTarget(this, x, y); if (clickedView != null && clickedView.isClickable() && clickedView.isEnabled()) { this.clickedView = clickedView; isClickedParent = false; initParamForRipple(event, clickedView,false); postInvalidateDelayed(INVALIDATE_DURATION); } else { this.clickedView = this; isClickedParent = true; RippleLinearLayout.this.setClickable(true); initParamForRipple(event, clickedView,true); postInvalidateDelayed(INVALIDATE_DURATION); }
} else if (action == MotionEvent.ACTION_UP) {
isPressed = false;
RippleLinearLayout.this.setClickable(false);
postInvalidateDelayed(INVALIDATE_DURATION);
clickedView.performClick();
return true;
} else if (action == MotionEvent.ACTION_CANCEL) {
isPressed = false;
postInvalidateDelayed(INVALIDATE_DURATION);
}
return super.dispatchTouchEvent(event);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (!shouldDrawRipple) {
return;
}
if (mRippleRadius > mMaxRippleRadius / 2) {
mRippleRadius += mRippleRadiusGap * 4;
} else {
mRippleRadius += mRippleRadiusGap;
}
this.getLocationOnScreen(mLocationInScreen);
int[] location = new int[2];
clickedView.getLocationOnScreen(location);
int left = location[0] - mLocationInScreen[0];
int top = location[1] - mLocationInScreen[1];
int right = left + clickedView.getMeasuredWidth();
int bottom = top + clickedView.getMeasuredHeight();
canvas.save();
if (!isClickedParent) {
canvas.clipRect(left, top, right, bottom);
}
canvas.drawCircle(mCenterX, mCenterY, mRippleRadius, mPaint);
canvas.restore();
if (mRippleRadius <= mMaxRippleRadius) {
if (isClickedParent) {
postInvalidateDelayed(INVALIDATE_DURATION);
} else {
postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);
}
} else if (!isPressed) {
shouldDrawRipple = false;
if (isClickedParent) {
postInvalidateDelayed(INVALIDATE_DURATION);
} else {
postInvalidateDelayed(INVALIDATE_DURATION, left, top, right, bottom);
}
}
}
private void initParamForRipple(MotionEvent event, View view, boolean isClickedParent) {
mCenterX = event.getX();
mCenterY = event.getY();
if (isClickedParent) {
clickedViewWidth = this.getMeasuredWidth();
clickedViewHeight = this.getMeasuredHeight();
} else {
clickedViewWidth = view.getMeasuredWidth();
clickedViewHeight = view.getMeasuredHeight();
}
mMaxRippleRadius = (int) Math.sqrt(clickedViewWidth * clickedViewWidth + clickedViewHeight * clickedViewHeight);
mRippleRadius = 0;
shouldDrawRipple = true;
isPressed = true;
mRippleRadiusGap = mMaxRippleRadius / 20;
}
private View getTouchTarget(View view, int x, int y) {
View target = null;
ArrayList<View> TouchableViews = view.getTouchables();
for (View child : TouchableViews) {
if (isTouchPointInView(child, x, y) && child != RippleLinearLayout.this) {
target = child;
break;
}
}
return target;
}
private boolean isTouchPointInView(View view, int x, int y) {
int[] location = new int[2];
view.getLocationOnScreen(location);
int left = location[0];
int top = location[1];
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
if (view.isClickable() && y >= top && y <= bottom && x >= left && x <= right) {
return true;
}
return false;
}
}
public class RippleImageView extends ImageButton {
public void animationCancel() {
mRadiusAnimator.cancel();
}
/* The m down x. /
private float mDownX;
/* The m down y. / private float mDownY;
/* The m alpha factor. / private float mAlphaFactor;
/* The m density. / private float mDensity;
/* The m radius. / private float mRadius;
/* The m max radius. / private float mMaxRadius;
/* The m ripple color. / private int mRippleColor;
/* The m is animating. / private boolean mIsAnimating = false;
/* The m hover. / private boolean mHover = true;
/* The m radial gradient. / private RadialGradient mRadialGradient;
/* The m paint. / private Paint mPaint;
/* The m radius animator. / private ObjectAnimator mRadiusAnimator;
/**
@return the int / private int dp(int dp) { return (int) ((dp) - 0.5f);// mDensity }
/**
the context */ public RippleImageView(Context context) { this(context, null); }
/**
the attrs */ public RippleImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); }
/**
the def style */ public RippleImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RippleView); mRippleColor = a.getColor(R.styleable.RippleView_rippleColor, mRippleColor); mAlphaFactor = a.getFloat(R.styleable.RippleView_alphaFactor, mAlphaFactor); mHover = a.getBoolean(R.styleable.RippleView_hover, mHover); a.recycle(); }
/**
Inits the. */ public void init() { mDensity = getContext().getResources().getDisplayMetrics().density;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setAlpha(100); setRippleColor(Color.BLACK, 0.2f);
}
/**
the alpha factor */ public void setRippleColor(int rippleColor, float alphaFactor) { mRippleColor = rippleColor; mAlphaFactor = alphaFactor; }
/**
the new hover */ public void setHover(boolean enabled) { mHover = enabled; }
/*
@see android.view.View#onSizeChanged(int, int, int, int) / @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mMaxRadius = (float) Math.sqrt(w w + h * h); }
/* The m animation is cancel. / private boolean mAnimationIsCancel;
/* The m rect. / private Rect mRect;
/*
@see android.widget.TextView#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(final MotionEvent event) { Log.d("TouchEvent", String.valueOf(event.getActionMasked())); Log.d("mIsAnimating", String.valueOf(mIsAnimating)); Log.d("mAnimationIsCancel", String.valueOf(mAnimationIsCancel)); boolean superResult = super.onTouchEvent(event); if (event.getActionMasked() == MotionEvent.ACTION_DOWN && this.isEnabled() && mHover) { mRect = new Rect(getLeft(), getTop(), getRight(), getBottom()); mAnimationIsCancel = false; mDownX = event.getX(); mDownY = event.getY();
mRadiusAnimator = ObjectAnimator.ofFloat(this, "radius", 0, dp(50)).setDuration(400);
mRadiusAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mRadiusAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
mIsAnimating = true;
}
@Override
public void onAnimationEnd(Animator animator) {
setRadius(0);
ViewHelper.setAlpha(RippleImageView.this, 1);
mIsAnimating = false;
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mRadiusAnimator.start();
if (!superResult) {
return true;
}
} else if (event.getActionMasked() == MotionEvent.ACTION_MOVE && this.isEnabled() && mHover) { mDownX = event.getX(); mDownY = event.getY();
// Cancel the ripple animation when moved outside
if (mAnimationIsCancel = !mRect.contains(getLeft() + (int) event.getX(), getTop() + (int) event.getY())) {
setRadius(0);
} else {
setRadius(dp(50));
}
if (!superResult) {
return true;
}
} else if (event.getActionMasked() == MotionEvent.ACTION_UP && !mAnimationIsCancel && this.isEnabled()) { mDownX = event.getX(); mDownY = event.getY();
final float tempRadius = (float) Math.sqrt(mDownX * mDownX + mDownY * mDownY);
float targetRadius = Math.max(tempRadius, mMaxRadius);
if (mIsAnimating) {
mRadiusAnimator.cancel();
}
mRadiusAnimator = ObjectAnimator.ofFloat(this, "radius", dp(50), targetRadius);
mRadiusAnimator.setDuration(500);
mRadiusAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mRadiusAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
mIsAnimating = true;
}
@Override
public void onAnimationEnd(Animator animator) {
setRadius(0);
ViewHelper.setAlpha(RippleImageView.this, 1);
mIsAnimating = false;
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mRadiusAnimator.start();
if (!superResult) {
return true;
}
} return superResult; }
/**
@return the int / public int adjustAlpha(int color, float factor) { int alpha = Math.round(Color.alpha(color) factor); int red = Color.red(color); int green = Color.green(color); int blue = Color.blue(color); return Color.argb(alpha, red, green, blue); }
/**
the new radius */ public void setRadius(final float radius) { mRadius = radius; if (mRadius > 0) { mRadialGradient = new RadialGradient(mDownX, mDownY, mRadius, adjustAlpha(mRippleColor, mAlphaFactor), mRippleColor, Shader.TileMode.MIRROR); mPaint.setShader(mRadialGradient); } invalidate(); }
/* The m path. / private Path mPath = new Path();
/*
@see android.widget.TextView#onDraw(android.graphics.Canvas) */ @Override protected void onDraw(final Canvas canvas) { super.onDraw(canvas);
if (isInEditMode()) { return; }
canvas.save(Canvas.CLIP_SAVE_FLAG);
mPath.reset(); mPath.addCircle(mDownX, mDownY, mRadius, Path.Direction.CW);
canvas.clipPath(mPath); canvas.restore();
canvas.drawCircle(mDownX, mDownY, mRadius, mPaint); }
}`
你得这个方案比较好解决,在view 退出视图 onDetachedFromWindow 方法内 停止动画就好了
哦,好的,谢谢你,不过希望我的思路,可以给你帮助
不客气。 相互学习
已经修复你提的bug
比如说,我嵌套fragment,当我在fragment里面点击以后,fragment发生位移然后该动画,仍然停留在远处不动,拦截原View的Onclick事件