Android - Fade out bitmap image on canvas

前端 未结 3 1542
闹比i
闹比i 2021-02-08 22:53

I am drawing a scaled bitmap onto a canvas and would like to fade my image out at a specified time.

Basically, when my character image goes over a certain section of the

相关标签:
3条回答
  • 2021-02-08 23:29

    If you think there's a possibility you will want to change the fade animation down the road, such as scaling and/or rotating, then you should go with an animation XML.

    But for just a quick bitmap fade, you can repeatedly post delayed invalidation messages. You probably want to limit your invalidated area to just where your character bitmap is:

    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
            }
        }
        ...
    }
    

    I'd recommend putting the constants FADE_MILLISECONDS and FADE_STEP into res/integers.xml just so they aren't hard-coded.

    0 讨论(0)
  • 2021-02-08 23:29

    The best way for me to explain this is provide a full custom view example that you can pull the pieces from that you need. Below is a view that accomplishes this.

    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);
            }
        }
    }
    

    The most efficient way to dynamically modify the transparency of what you draw is to apply it using a Paint drawing to your Canvas. You will need to continually invalidate() the view with each frame transition to get the animation to display until the character is gone. The example uses an Animation object and a Transformation object to handle all of the timing math to make the animation actually look good.

    The gist here is that you start the animation via some external trigger (I wouldn't recommend doing the check for when to fade out in onDraw(), probably better in the place where those character locations are updated. In my example, for simplicity sake, I started this when the view to touched.

    This trigger starts the animation and gets the initial transformation value, then invalidate() triggers a new onDraw(). While the animation is running, onDraw() is repeated due to the invalidate() and each iteration the alpha on the paint decreases slightly.

    When the animation is finished, it will call the AnimationListener for you, so you can trigger the screen transition inside of onAnimationEnd().

    0 讨论(0)
  • 2021-02-08 23:50
            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();
    
        }
    

    this will make your bitmap becomes transparent ( the alpha will be 100 ) .. and then redirect to the next class after 3 seconds.

    Update: for the bitmap you can't use .setAlpha so we must use a paint, so we created a new paint each time then set the bitmap with the paint. but if you have an imageView you can use .setalpha

    0 讨论(0)
提交回复
热议问题