Android - 在画布上淡出位图图像

时间:2013-08-14 10:19:44

标签: android image bitmap android-canvas fadeout

我正在将一个缩放的位图绘制到画布上,并希望在指定的时间淡出我的图像。

基本上,当我的角色图像越过画布的某个部分时,我需要角色图像慢慢淡出(3秒),然后页面会自动重定向到下一个java类。

目前,我的图片只是重定向到新的java类,请参阅下面的一些代码,了解我如何创建图像。

Resources res = getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, res.getDisplayMetrics());
imgSpacing = (int) px / 2;
int size = (int) ((PhoneWidth / 5) - px);

chrImg = BitmapFactory.decodeResource(getResources(), R.drawable.character);
chrImg = Bitmap.createScaledBitmap(chrImg, size, size, true);

然后在画布上绘制:

if(indexX == mazeFinishX && indexY == mazeFinishY)
{
    canvas.drawBitmap(finish, j * totalCellWidth, i * totalCellHeight, null);
    // As soon as the character moves over this square they are automatically re-directed to new page
    // This is where I want to fade the character image out before the re-direct
}

我已经在网上看了,但是无法解决如何让我的游戏资源可绘制文件夹中提取的可绘制图像的淡入效果。感谢

3 个答案:

答案 0 :(得分:9)

如果您认为有可能想要改变淡入淡出动画,例如缩放和/或旋转,那么您应该使用动画XML。

但是对于快速位图淡化,您可以重复发布延迟的失效消息。您可能希望将无效区域限制为字符位图的位置:

private static final int FADE_MILLISECONDS = 3000; // 3 second fade effect
private static final int FADE_STEP = 120;          // 120ms refresh

// Calculate our alpha step from our fade parameters
private static final int ALPHA_STEP = 255 / (FADE_MILLISECONDS / FADE_STEP);

// Initializes the alpha to 255
private Paint alphaPaint = new Paint();

// Need to keep track of the current alpha value
private int currentAlpha = 255;

@Override
protected void onDraw(Canvas canvas) {
    ...
    if(indexX == mazeFinishX && indexY == mazeFinishY) {

        // Drawing your wormhole?
        int x = j * totalCellWidth;
        int y = i * totalCellHeight;
        canvas.drawBitmap(finish, x, y, null);

        if (currentAlpha > 0) {

           // Draw your character at the current alpha value
           canvas.drawBitmap(chrImg, x, y, alphaPaint);

           // Update your alpha by a step
           alphaPaint.setAlpha(currentAlpha);
           currentAlpha -= ALPHA_STEP;

           // Assuming you hold on to the size from your createScaledBitmap call
           postInvalidateDelayed(FADE_STEP, x, y, x + size, y + size);

        } else {
           // No character draw, just reset your alpha paint
           currentAlpha = 255;
           alphaPaint.setAlpha(currentAlpha);

           // Now do your redirect
        }
    }
    ...
}

我建议将常量FADE_MILLISECONDS和FADE_STEP放入res / integers.xml中,这样它们就不会被硬编码。

答案 1 :(得分:3)

我解释此问题的最佳方式是提供一个完整的自定义视图示例,您可以从中获取所需的部分。以下是实现此目的的视图。

public class CharacterView extends View {

    private Paint mCharacterPaint;
    private Bitmap mCharacterBitmap;
    private Transformation mTransformation;
    private AlphaAnimation mFadeOut;

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

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

    public CharacterView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        //This would be your character image instead
        mCharacterBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);

        //We need a paint to efficiently modify the alpha
        mCharacterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //This is needed to house the current value during the animation
        mTransformation = new Transformation();
        //Construct an animation that will do all the timing math for you
        mFadeOut = new AlphaAnimation(1f, 0f);
        mFadeOut.setDuration(500);
        //Use a listener to trigger the end action
        mFadeOut.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) { }

            @Override
            public void onAnimationEnd(Animation animation) {
                //Trigger your action to change screens here.
            }

            @Override
            public void onAnimationRepeat(Animation animation) { }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            //In this example, touching the view triggers the animation
            // your code would run this sequence when the character reaches the
            // appropriate coordinates (P.S. I would not advocate putting this code
            // inside of onDraw()
            mFadeOut.start();
            mFadeOut.getTransformation(System.currentTimeMillis(), mTransformation);
            invalidate();
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //...existing drawing code...

        canvas.drawBitmap(mCharacterBitmap, 0, 0, mCharacterPaint);
        if (mFadeOut.hasStarted() && !mFadeOut.hasEnded()) {
            mFadeOut.getTransformation(System.currentTimeMillis(), mTransformation);
            //Keep drawing until we are done
            mCharacterPaint.setAlpha((int)(255 * mTransformation.getAlpha()));
            invalidate();
        } else {
            //Reset the alpha if animation is canceled
            mCharacterPaint.setAlpha(255);
        }
    }
}

动态修改绘制内容的透明度的最有效方法是使用Paint绘图将其应用到Canvas。您需要在每次帧转换时不断invalidate()视图以显示动画,直到角色消失为止。该示例使用Animation对象和Transformation对象来处理所有计时数学,以使动画看起来很好。

这里的要点是你通过一些外部触发器启动动画(我不建议检查何时淡出onDraw(),在更新这些角色位置的地方可能更好。我的例子,为了简单起见,我在触摸视图时启动了这个。

此触发器启动动画并获取初始转换值,然后invalidate()触发新的onDraw()。当动画运行时,由于onDraw()而重复invalidate(),并且每次迭代时,绘画上的alpha会略微降低。

动画完成后,它会为您调用AnimationListener,因此您可以在onAnimationEnd()内触发屏幕转换。

答案 2 :(得分:1)

        if(indexX == mazeFinishX && indexY == mazeFinishY)
        {
            canvas.drawBitmap(finish, j * totalCellWidth, i * totalCellHeight, null);
            // As soon as the character moves over this square they are automtically re-directs to new page
            new CountDownTimer(0500, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {}
                @Override
                public void onFinish() {
Paint paint = new Paint();
paint.setAlpha(25);
canvas.drawBitmap(chrImg, 0, 0, paint);
                }
            }.start();
            new CountDownTimer(0500, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {}
                @Override
                public void onFinish() {
Paint paint = new Paint();
paint.setAlpha(45);
canvas.drawBitmap(chrImg, 0, 0, paint);             }
            }.start();
            new CountDownTimer(0500, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {}
                @Override
                public void onFinish() {
Paint paint = new Paint();
paint.setAlpha(70);
canvas.drawBitmap(chrImg, 0, 0, paint);             }
            }.start();
            new CountDownTimer(0500, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {}
                @Override
                public void onFinish() {
Paint paint = new Paint();
paint.setAlpha(100);
canvas.drawBitmap(chrImg, 0, 0, paint);             }
            }.start();
            // This is where I want to fade the character image out before the re-direct
            new CountDownTimer(3000, 1000) {

            @Override
            public void onTick(long millisUntilFinished) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onFinish() {
                // TODO Auto-generated method stub

                    Intent i = new Intent(currentclass.this, nextClass.class);
                    startActivity(i);
            }
        }.start();

    }

这将使您的位图变得透明(alpha将为100)..然后在3秒后重定向到下一个类。

<强>更新 对于位图,你不能使用.setAlpha所以我们必须使用一个paint,所以我们每次创建一个新的paint,然后用paint设置位图。但是如果你有一个imageView,你可以使用.setalpha