2013-08-14 4 views
7

Je dessine une image bitmap mise à l'échelle sur un canevas et souhaite fondre mon image à un moment donné. Fondamentalement, lorsque mon image de personnage passe au-dessus d'une certaine section de la toile, j'ai besoin que l'image de caractère disparaisse progressivement (3 secondes), avant que la page ne se redirige automatiquement vers la classe Java suivante.Android - Fondu image bitmap sur le canevas

Actuellement, mon image redirige simplement vers la nouvelle classe Java, veuillez voir ci-dessous du code sur la façon dont je crée mon image.

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

Ensuite, au sein de la toile onDraw:

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 
} 

J'ai regardé en ligne, mais ne peut pas travailler tout à fait comment obtenir la disparition progressive de travailler pour mon image drawable tiré par les cheveux de mes jeux ressources de dossiers drawable. Merci

Répondre

8

Si vous pensez qu'il est possible que vous souhaitiez modifier l'animation de fondu en cours de route, telle que la mise à l'échelle et/ou la rotation, vous devez utiliser une animation XML.

Mais pour juste un fondu bitmap rapide, vous pouvez publier de manière répétée des messages d'invalidation retardés.Vous voulez sans doute de limiter votre zone invalidée juste où votre personnage est bitmap:

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

Je recommande de mettre les constantes FADE_MILLISECONDS et FADE_STEP dans res/integers.xml juste pour qu'ils ne sont pas codées en dur.

+0

J'ai implémenté le code ci-dessus et l'évanouissement fonctionne correctement. Cependant, la question ici est le fait que ma re-direct ne fonctionne pas. Il frappe la fonction avec le code de redirection, mais semble l'ignorer, des idées? –

+0

J'ai ajouté un champ "currentAlpha", en utilisant setAlpha/getAlpha ne fonctionnait probablement pas avec autre chose qu'une étape alpha de 1. –

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 cahracter 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(); 

    } 

cela rendra votre bitmap devient transparent (l'alpha sera de 100) .. puis rediriger vers la classe suivante après 3 secondes.

Mise à jour: pour le bitmap que vous ne pouvez pas utiliser .setAlpha donc nous devons utiliser une peinture, nous avons donc créé une nouvelle peinture à chaque fois mis alors le bitmap avec la peinture. mais si vous avez une imageView, vous pouvez utiliser .setalpha

+0

Cela fonctionne en retardant la redirection, mais je veux faire en sorte que l'image s'efface lentement. Esentially, j'ai une image de trou de ver et veux que l'image de caractère disparaisse dans cela par l'intermédiaire d'une certaine sorte sur l'animation (je pensais disparaître l'image loin). –

+0

Juste essayé votre code, cependant réalisé que comme il s'agit d'un bitmap à partir des ressources drawable vous ne pouvez pas utiliser setAlpha. Existe-t-il un autre moyen, s'il vous plaît voir mon code original pour reproduire l'image. –

+0

J'ai mis à jour le code, vérifiez-le maintenant. –

3

La meilleure façon pour moi d'expliquer cela est de fournir un exemple de vue personnalisée complète que vous pouvez tirer les pièces dont vous avez besoin. Voici une vue qui accomplit cela.

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

La façon la plus efficace de modifier dynamiquement la transparence de ce que vous dessinez est de l'appliquer à l'aide d'un dessin Paint à votre Canvas. Vous aurez besoin de continuellement invalidate() la vue avec chaque transition d'image pour que l'animation s'affiche jusqu'à ce que le personnage soit parti. L'exemple utilise un objet Animation et un objet Transformation pour gérer tous les calculs de synchronisation afin que l'animation soit réellement bonne.

L'essentiel ici est que vous commencez l'animation via un déclencheur externe (je recommande de ne pas faire le chèque pour le moment de disparaître dans onDraw(), sans doute mieux à l'endroit où les emplacements de caractères sont mis à jour. Dans mon exemple, par souci de simplicité, j'ai commencé quand la vue de toucher.

ce déclencheur démarre l'animation et obtient la valeur de transformation initiale, puis invalidate() déclenche une nouvelle onDraw(). alors que l'animation est en cours d'exécution, onDraw() est répétée en raison de la invalidate() et à chaque itération, l'alpha de la peinture diminue légèrement

Lorsque l'animation est terminée, elle appelle le AnimationListener pour vous, afin que vous puissiez déclencher la transition d'écran à l'intérieur de onAnimationEnd().

+0

Vous ne devez invalider que la zone où le caractère est redessiné. –

+0

Cela peut être une bonne optimisation si la vue globale est grande. Bien que dans de nombreux cas courants (par exemple avec l'accélération matérielle activée), les rects sales sont effectivement ignorés; il ne vaut donc généralement pas la peine d'inclure, sauf si le rendement le justifie. – Devunwired

+0

Cette réponse de l'un des développeurs Android semble contredire votre affirmation que l'accélération matérielle ignore les régions sales: http://stackoverflow.com/questions/7233830/partial-invalidation-in-custom-android-view-with-hardware-acceleration –