【问题标题】:Fading edges/mask with animation in AndroidAndroid中带有动画的淡化边缘/蒙版
【发布时间】:2016-08-10 05:44:48
【问题描述】:

我创建了一个动画,显示多辆汽车向上行驶。动画如下图所示:

Animated cars

此动画需要放置在 Google 地图片段的顶部,并且汽车必须在顶部和底部淡出。

现在我使用关键帧完成了这项工作,我手动创建了 15 张图像,这些图像依次显示以创建此效果。

问题是我宁愿只使用 ObjectAnimator 创建动画并在代码中制作淡入淡出的边缘,这样我就可以轻松更改 需要时拍下汽车的照片。

我尝试使用以下代码解决我的问题:

public class MaskView extends View {
    private Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.car);
    private float topStart = -bitmap.getHeight();
    private float top = 0; // Don't change!
    //private final float margin = Util.convertDpToPixel(5f, getContext());
    private final int smoothness = 10;
    private final float speed = bitmap.getHeight() / 20;
    private LinearGradient linearGradient = null;
    private Paint defaultPaint;
    private Paint maskPaint;
    private Path maskPath;

    public MaskView(Context context) {
        super(context);
        init();
    }

    public MaskView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        int width = getMeasuredWidth();
        int halfWidth = width / 2;
        int height = getMeasuredHeight();

        linearGradient = new LinearGradient(halfWidth, 0, halfWidth, height, new int[] {
                Color.parseColor("#00000000"), Color.parseColor("#CC000000"), Color.parseColor("#CC000000"), Color.parseColor("#00000000")}, new float[] {0f, 0.3f, 0.7f, 1f}, Shader.TileMode.CLAMP);

        defaultPaint = new Paint();
        defaultPaint.setStyle(Paint.Style.FILL);
        defaultPaint.setColor(Color.parseColor("#FF000000"));

        maskPaint = new Paint();
        maskPaint.setStyle(Paint.Style.FILL);
        maskPaint.setColor(Color.parseColor("#FF000000"));

        maskPaint.setShader(linearGradient);
        maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

        maskPath = new Path();
        maskPath.moveTo(0, 0);
        maskPath.lineTo(width, 0);
        maskPath.lineTo(width, height);
        maskPath.lineTo(0, height);
        maskPath.lineTo(0, 0);
    }

    private void init() {
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        post(new Runnable() {
            @Override
            public void run() {
                if(topStart < 0f) {
                    topStart += speed;
                }
                else
                    topStart = -bitmap.getHeight(); // Reset

              invalidate();
              postDelayed(this, smoothness);
            }
        });
    }

    @Override
    protected void onDraw(Canvas canvas) {
       if(linearGradient == null) return;

       top = topStart;

        while(top < canvas.getHeight())
        {
            canvas.drawBitmap(bitmap, 0, top, null);
            top += bitmap.getHeight();
        }

         canvas.drawPath(maskPath, maskPaint);
    }
}

这种方法使用 ondraw 方法来绘制汽车,并使用处理程序以一定的间隔将这些汽车向上移动 1px。然后它使用渐变过滤器淡出视图顶部和底部的边缘。这种方法的问题是动画似乎运行不流畅。

有人知道解决这个问题的好方法吗?由于背景是可滚动的(谷歌地图),所以我不能使用图像来实现淡化效果。

谢谢!

编辑:

将处理程序替换为 ValueAnimator。动画现在似乎运行得更流畅了,但仍然感觉有点滞后:

final ValueAnimator va = ValueAnimator.ofFloat(-bitmap.getHeight() - margin, 0f);
va.setInterpolator(new LinearInterpolator());
va.setDuration(smoothness);
va.setRepeatMode(ValueAnimator.INFINITE);
va.setRepeatCount(ValueAnimator.INFINITE);
a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    public void onAnimationUpdate(ValueAnimator animation) {
        float value = (float) animation.getAnimatedValue();
        topStart = value;
        invalidate();
    }
});
va.start();

【问题讨论】:

  • ObjectAnimator/ValueAnimator代替Handler,整体效果会好很多
  • 谢谢,我更新了我的问题
  • 对不起,我没有注意到它的无限动画,也许TimeAnimator会更好?
  • TimeAnimator 感觉不如 ValueAnimator。但也许我用错了。
  • 试试this

标签: java android google-maps android-studio


【解决方案1】:

使用这个简单的实现(你可以在onTimeUpdate监听器中调整速度,现在一辆车每秒向上移动):

public class MaskView extends View implements TimeAnimator.TimeListener {
    private Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.car);
    private float y;
    private Paint carPaint = new Paint();
    private Paint maskPaint = new Paint();
    private Rect carRect = new Rect();

    public MaskView(Context context) {
        super(context);
        init();
    }

    public MaskView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        int colors[] = {0x00000000, 0xff000000, 0xff000000, 0x00000000};
        float[] positions = {0f, 0.3f, 0.7f, 1f};
        maskPaint.setShader(new LinearGradient(0, 0, bitmap.getWidth(), h, colors, positions, Shader.TileMode.CLAMP));
        maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

        carPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.REPEAT));
        carRect.set(0, 0, bitmap.getWidth(), h + bitmap.getHeight());
    }

    private void init() {
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        TimeAnimator animator = new TimeAnimator();
        animator.setTimeListener(this);
        animator.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.translate(0, -y);
        canvas.drawRect(carRect, carPaint);
        canvas.translate(0, y);
        canvas.drawRect(carRect, maskPaint);
    }

    @Override
    public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
        y = (bitmap.getHeight() * totalTime / 1000f) % bitmap.getHeight();
        invalidate(carRect);
    }
}

编辑:

要使用这个预 JELLY_BEAN:

分级: 编译'com.nineoldandroids:library:2.4.0+'

类: 导入 com.nineoldandroids.animation.TimeAnimator;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多