位图而不是视图上的波纹动画
Posted
技术标签:
【中文标题】位图而不是视图上的波纹动画【英文标题】:Ripple Animation on a Bitmap instead of View 【发布时间】:2019-10-10 17:03:57 【问题描述】:我一直在使用位图在视图中渲染小的彩色圆圈。现在我想在点击时在这些圆圈周围显示自定义涟漪动画。
在通过 *** 的答案搜索了一段时间后,主要建议将这些位图包装在 VIEW 中,并使用 android 的动画框架将动画应用于这些视图。
但问题是,我已经通过
使用该视图的画布在视图中绘制这些位图canvas.drawBitmap()
功能。我只想在单击时显示以这些位图为中心的涟漪。我的问题是,无论如何我可以为位图提供波纹或任何动画而不将它们包装为视图?
protected void fill(ILineDataSet set, boolean drawCircleHole,
boolean drawTransparentCircleHole, int selectedEntryIndex)
int colorCount = set.getCircleColorCount();
int holeColorCount = set.getCircleHoleColorCount();
circleRadius = set.getCircleRadius();
circleHoleRadius = set.getCircleHoleRadius();
for (int i = 0; i < (colorCount > holeColorCount ? colorCount: holeColorCount); i++)
Bitmap.Config conf = Bitmap.Config.ARGB_4444;
Bitmap circleBitmap = Bitmap.createBitmap((int) (circleRadius * 2.1),
(int) (circleRadius * 2.1), conf);
Canvas canvas = new Canvas(circleBitmap);
circleBitmaps[i] = circleBitmap;
//fill colors in the values' circles
mRenderPaint.setColor(set.getCircleColor(i < colorCount ? i : 0));
mCirclePaintInner.setColor(set.getCircleHoleColor(i < holeColorCount ? i : 0));
if (drawTransparentCircleHole)
// Begin path for circle with hole
mCirclePathBuffer.reset();
mCirclePathBuffer.addCircle(
circleRadius,
circleRadius,
circleRadius,
Path.Direction.CW);
// Cut hole in path
mCirclePathBuffer.addCircle(
circleRadius,
circleRadius,
circleHoleRadius,
Path.Direction.CCW);
// Fill in-between
canvas.drawPath(mCirclePathBuffer, mRenderPaint);
else
canvas.drawCircle(
circleRadius,
circleRadius,
circleRadius,
mRenderPaint);
if (drawCircleHole)
canvas.drawCircle(
circleRadius,
circleRadius,
circleHoleRadius,
mCirclePaintInner);
if (i == selectedEntryIndex)
circleBitmaps[i] = getScaledUpBitmap(circleBitmaps[i]);
private Bitmap getScaledUpBitmap(Bitmap bm)
//scale bitmap as twice its size
int width = bm.getWidth();
int height = bm.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(1.5f, 1.5f);
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
bm.recycle();
return resizedBitmap;
【问题讨论】:
你有位置和尺寸的圆圈列表吗?如果是,请分享您的代码以检测视图和列表条目类上的触摸事件。 @Ferran 是的,我管理位图数组列表。我已经编辑了这个问题。现在,我将选择作为参数的圆的索引发送给函数 fill() 并在其索引匹配时缩放相同的位图。我还想在点击时在该圆形位图周围显示波纹并在位图缩放完成后触发波纹动画。 【参考方案1】: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_
android:layout_
android:padding="0dp"
>
<com.mcblau.pacerblue.components.RippleLayout
android:id="@+id/container"
android:layout_
android:layout_
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);
将圆半径设置为波纹颜色。
【讨论】:
以上是关于位图而不是视图上的波纹动画的主要内容,如果未能解决你的问题,请参考以下文章