Анимация Android Ripple - это комбинация растущей анимации + анимация затухания.
Другими словами, это процесс рисования, и поэтому не рекомендуется делать это непосредственно на растровом изображении.
Я написал класс, который представляет собой макет, который можно использовать в качестве сенсорной панели.
Этот макет, называемый RippleLayout
, расширен с RelativeLayout
. Вы можете использовать этот макет, чтобы рисовать круги и управлять событием onTouchListener
, чтобы показать анимацию пульсации в заданной точке.
RippleLayout.java
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import java.util.ArrayList;
import java.util.List;
public class RippleLayout extends RelativeLayout {
private AnimatorSet mAnimatorSet;
private Paint mPaint;
private boolean mStarted;
private float mX, mY;
private int mCount = 1;
private int mDuration = 300;
private float mRadius = 300;
private IntRippleView rippleView;
public RippleLayout(Context context) {
this(context, null, 0);
}
public RippleLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RippleLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void build() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.GRAY);
List<Animator> animators = new ArrayList<>();
rippleView = new IntRippleView(getContext());
rippleView.setCircleRadius(0);
rippleView.setCircleAlpha(1);
addView(rippleView);
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(rippleView, "CircleRadius", 0f, 1f);
scaleXAnimator.setRepeatCount(0);
animators.add(scaleXAnimator);
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(rippleView, "CircleAlpha", 1f, 0f);
alphaAnimator.setRepeatCount(0);
animators.add(alphaAnimator);
mAnimatorSet = new AnimatorSet();
mAnimatorSet.setInterpolator(new LinearInterpolator());
mAnimatorSet.playTogether(animators);
mAnimatorSet.setDuration(mDuration);
mAnimatorSet.addListener(mAnimatorListener);
}
public void doRipple(float x, float y) {
doRipple(x, y, mRadius, mPaint.getColor());
}
public synchronized void doRipple(float x, float y, float radius, int acolor) {
if (mStarted)
mAnimatorSet.end();
mX = x;
mY = y;
mRadius = radius;
rippleView.bringToFront();
mPaint.setColor(acolor);
mAnimatorSet.start();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
build();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAnimatorSet != null) {
mAnimatorSet.cancel();
mAnimatorSet = null;
}
mPaint = null;
}
private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
mStarted = true;
}
@Override
public void onAnimationEnd(Animator animator) {
mStarted = false;
}
@Override
public void onAnimationCancel(Animator animator) {
mStarted = false;
}
@Override
public void onAnimationRepeat(Animator animator) {
}
};
private class IntRippleView extends View {
public IntRippleView(Context context) {
super(context);
}
private float CircleRadius = 0;
public void setCircleRadius(float value) {
CircleRadius = value;
invalidate();
}
public float getCircleRadius() {
return CircleRadius;
}
private float CircleAlpha = 1;
public void setCircleAlpha(float value) {
CircleAlpha = value;
invalidate();
}
public float getCircleAlpha() {
return CircleAlpha;
}
@Override
protected void onDraw(Canvas canvas) {
int aColor = Color.RED;
mPaint.setAlpha((int)(255 * CircleAlpha));
canvas.drawCircle(mX, mY, mRadius * CircleRadius, mPaint);
}
}
}
Как пользоваться
В формате XML
<android.support.constraint.ConstraintLayout
android:id="@+id/mainlayout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="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:padding="0dp"
>
<com.mcblau.pacerblue.components.RippleLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
>
</com.mcblau.pacerblue.components.RippleLayout>
</android.support.constraint.ConstraintLayout>
В вашей деятельности
container = findViewById(R.id.container);
container.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// detect here which circle was touch
// get the center of the circle => mCenterX, mCenterY
container.doRipple(mCenterX, mCenterY); // ripple animation
return true;
}
});
Вы можете нарисовать свои круги непосредственно в RippleLayout или в другом. Если вы поместите RippleLayout
точно поверх своего растрового макета, вы можете использовать его в качестве сенсорной панели. В этом случае используйте setOnTouchListener
макета вашего круга.
Используйте doRipple(x, y);
или doRipple(x, y, radius, acolor);
, чтобы задать радиус круга в виде цвета пульсации.