android:如何动画 - 翻译LayerDrawable的单层

时间:2013-02-24 23:40:10

标签: android animation

我查看了android动画类,但我不确定我是否正在查看我正在寻找的内容。我想知道是否可以将翻译动画(更改X坐标)添加到LayerDrawable的单个图层?我找到了TranslateAnimation类,但它似乎只适用于整个ImageView,我只想为LayerDrawable的一个单层设置动画。有什么建议?提前谢谢。

3 个答案:

答案 0 :(得分:3)

简而言之:可以使用ValueAnimator来调整该drawable的界限

更详细: 假设你有一个可绘制的图层列表,内部项目可绘制(id:innerRed),并假设你的布局中有Buttonid:btnWithDrawableBg)并且已经将此分层可绘制分配给background属性,您可以使用ValueAnimator来调整该drawable的边界,如下面的示例所示(将x位置ping到每边100):

<强> pos_animator.xml

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:andoird="http://schemas.android.com/apk/res/android"
  andoird:repeatCount="infinite"
  andoird:repeatMode="reverse"
  andoird:valueFrom="-100"
  andoird:valueTo="100"
  andoird:valueType="intType"
/>

<强> MyActivity.java

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // our button with the drawable background
    Button btnWithBg = (Button) findViewById(R.id.btnWithDrawableBg);
    // the layered drawable
    final LayerDrawable layerDrawable = (LayerDrawable) btnWithBg.getBackground();
    // internal layer (item) drawable with id:innerRed
    final GradientDrawable innerRedShape = (GradientDrawable)layerDrawable.findDrawableByLayerId(R.id.innerRed);
    // our animator based on the xml above
    ValueAnimator posAnim = (ValueAnimator) AnimatorInflater.loadAnimator(
            mainLayout.getContext(), R.animator.pos_animator);

    posAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            // get current offset value and adjust drawable bounds
            int value = (Integer)animation.getAnimatedValue();
            Rect bounds = innerRedShape.copyBounds();//see Note below
            // here only manipulating x value
            bounds.offset(value, 0);
            innerRedShape.setBounds(bounds);
        }
    });
    posAnim.setTarget(innerRedShape);
    posAnim.start();
}

注意: copyBounds()是必需的(而不只是getBounds().offset())基于此SO post

答案 1 :(得分:0)

我已经找到了答案......似乎一旦创建了一个LayerDrawable,你就无法操纵这些层。从缺乏响应,我认为我的问题可能是错误的东西,我重新设计使用LayerDrawable,但动画作为单独的drawable / imageView对象,我在每个动画之前和之后生成和销毁。然后,我使用imageView上的ObjectAnimator来实现所需的图像转换。因此,如果有人想要为其LayerDrawable的单个图层设置动画,请尝试重新设计,以便您可以使用Animator类。

答案 2 :(得分:0)

我这样做了:

<强>的onCreate()

ImageView imageView = (ImageView) findViewById(R.id.imageView);

Resources r = getResources();

Drawable[] layers = new Drawable[2];

layers[0] = r.getDrawable(R.drawable.your_background_res);

PulseDrawable pulseDrawable = new PulseDrawable(Color.WHITE);
layers[1] = pulseDrawable;

LayerDrawable layerDrawable = new LayerDrawable(layers);

// This will adjust X & Y of layer, we have to pass layer index (250 pixels from Left and 150 pixels from Right)
layerDrawable.setLayerInset(1, 250, 150, 0, 0);

imageView.setImageDrawable(layerDrawable);

<强> PulseDrawable.java

import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.view.animation.DecelerateInterpolator;

public class PulseDrawable extends Drawable {
    private final static float CENTER_AREA_SIZE = 0.6f;
    private final static int PULSE_START_COLOR_OPACITY = 0;
    private final static float MINIMUM_RADIUS = 0;
    private final static int ANIMATION_DURATION_IN_MS = 1500;
    private final int color;
    private Paint centerPaint;
    private Paint pulsePaint;
    private float fullSizeRadius = 60;
    private float currentExpandAnimationValue = 0f;
    private int currentAlphaAnimationValue = 255;

    public PulseDrawable(int color) {
        this.color = color;
        initializeDrawable();
    }

    private void initializeDrawable() {
        preparePaints();
        prepareAnimation();
    }

    private void prepareAnimation() {
        final ValueAnimator expandAnimator = ValueAnimator.ofFloat(0f, 1f);
        expandAnimator.setRepeatCount(ValueAnimator.INFINITE);
        expandAnimator.setRepeatMode(ValueAnimator.RESTART);
        expandAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentExpandAnimationValue = (float) animation.getAnimatedValue();
                if (currentExpandAnimationValue == 0f) {
                    currentAlphaAnimationValue = 255;
                }
                invalidateSelf();
            }
        });
        final ValueAnimator alphaAnimator = ValueAnimator.ofInt(255, 0);
        alphaAnimator.setStartDelay(ANIMATION_DURATION_IN_MS / 4);
        alphaAnimator.setRepeatCount(ValueAnimator.INFINITE);
        alphaAnimator.setRepeatMode(ValueAnimator.RESTART);
        alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentAlphaAnimationValue = (int) animation.getAnimatedValue();
            }
        });
        AnimatorSet animation = new AnimatorSet();
        animation.playTogether(expandAnimator, alphaAnimator);
        animation.setDuration(ANIMATION_DURATION_IN_MS);
        animation.setInterpolator(new DecelerateInterpolator());
        animation.start();
    }

    private void preparePaints() {
        pulsePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        pulsePaint.setStyle(Paint.Style.FILL);
        centerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        centerPaint.setStyle(Paint.Style.FILL);
        centerPaint.setColor(color);
    }

    @Override
    public void setAlpha(int alpha) {
        pulsePaint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) { }

    @Override
    public int getOpacity() {
        return pulsePaint.getAlpha();
    }

    @Override
    public void draw(Canvas canvas) {
        Rect bounds = getBounds();

        //TODO - If we want to draw circle on center of canvas use below code

        /*float centerX = bounds.exactCenterX();
        float centerY = bounds.exactCenterY();*/

        float startX = bounds.left;
        float startY = bounds.top;

//        calculateFullSizeRadius();
        preparePaintShader();
        renderPulse(canvas, startX, startY);
        renderCenterArea(canvas, startX, startY);
    }

    private void renderPulse(Canvas canvas, float centerX, float centerY) {
        float currentRadius = fullSizeRadius * currentExpandAnimationValue;
        if (currentRadius > MINIMUM_RADIUS) {
            canvas.drawCircle(centerX, centerY, currentRadius, pulsePaint);
        }
    }

    private void renderCenterArea(Canvas canvas, float centerX, float centerY) {
        float currentCenterAreaRadius = fullSizeRadius * CENTER_AREA_SIZE;
        if (currentCenterAreaRadius > MINIMUM_RADIUS) {
            canvas.save();
            float left = centerX - currentCenterAreaRadius;
            float top = centerY - currentCenterAreaRadius;
            float right = centerX + currentCenterAreaRadius;
            float bottom = centerY + currentCenterAreaRadius;
            canvas.clipRect(left, top, right, bottom);
            canvas.drawCircle(centerX, centerY, currentCenterAreaRadius, centerPaint);
            canvas.restore();
        }
    }
    private void preparePaintShader() {
        Rect bounds = getBounds();
        float centerX = bounds.exactCenterX();
        float centerY = bounds.exactCenterY();
        float radius = (Math.min(bounds.width(), bounds.height()) / 2);
        if (radius > MINIMUM_RADIUS) {
            int edgeColor = getPulseColor();
            int centerColor = Color.argb(PULSE_START_COLOR_OPACITY, Color.red(color),
                    Color.green(color),
                    Color.blue(color));
            pulsePaint.setShader(new RadialGradient(centerX, centerY, radius,
                    centerColor, edgeColor, Shader.TileMode.CLAMP));
        } else {
            pulsePaint.setShader(null);
        }
    }

    private int getPulseColor() {
        return Color.argb(currentAlphaAnimationValue, Color.red(color),
                Color.green(color),
                Color.blue(color));
    }

    private void calculateFullSizeRadius() {
        Rect bounds = getBounds();
        float minimumDiameter = Math.min(bounds.width(), bounds.height());
        fullSizeRadius = (minimumDiameter / 2);
    }
}

<强>输出

enter image description here

注意:您可以添加多个图层,对于演示,我添加了两个图层。

希望这会对你有所帮助。