2013-08-14 22 views
7

Rysuję skalowaną mapę bitową na płótnie i chcę zanikać obraz w określonym czasie.Android - Zanikanie obrazu bitmapy na płótnie

Zasadniczo, gdy obraz mojej postaci przechodzi nad określoną sekcją płótna, wymagam, aby obraz postaci powoli znikał (3 sekundy), zanim strona automatycznie przekieruje się do następnej klasy języka Java.

Obecnie mój obraz po prostu przekierowuje do nowej klasy java. Poniżej znajduje się kod opisujący sposób tworzenia obrazu

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

Następnie w OnDraw płótnie:

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 
} 

Szukałem w internecie, jednak nie całkiem wyszło jak najlepiej blaknięcie pracować dla mojego rozciągliwej obrazu pobranego z moich gier zasobów odkształcalne folderów. Dzięki

Odpowiedz

8

Jeśli sądzisz, że istnieje możliwość zmiany animacji zejścia z drogi, takiej jak skalowanie i/lub obracanie, powinieneś użyć animacji XML.

Jednak w przypadku szybkiego znikania bitmapy można wielokrotnie wysyłać wiadomości z opóźnieniem.Prawdopodobnie chcesz, aby ograniczyć obszar unieważnionego po prostu gdzie bitmapy postać jest:

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

polecam stawianie FADE_MILLISECONDS stałych i FADE_STEP do Res/integers.xml tak nie są one zakodowane.

+0

Zaimplementowałem powyższy kod, a zanik działa poprawnie. Jednak problem polega na tym, że moje przekierowanie nie działa. Uderza w funkcję z kodem przekierowania, jakkolwiek zdaje się to ignorować, jakieś pomysły? –

+0

Dodałem pole "currentAlpha", używając setAlpha/getAlpha prawdopodobnie nie działało z niczym innym niż krokiem alfa 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(); 

    } 

to sprawi, że Twoja bitmapa stanie się przezroczysta (alpha będzie 100) .., a następnie przekieruje do następnej klasy po 3 sekundach.

Aktualizacja: na bitmapę nie można wykorzystać .setAlpha więc musimy użyć farby, dlatego stworzyliśmy nową farbę za każdym razem, a następnie ustawić bitmapę z farbą. ale jeśli masz imageView, możesz użyć .setalpha

+0

Powoduje to opóźnienie przekierowania, jednak chcę, aby obraz powoli znikał. Zasadniczo mam obraz robaka i chcę, aby obraz postaci znikał w jakiś sposób w animacji (myślałem, że zniknę z obrazu). –

+0

Po prostu wypróbowałem twój kod, jednak zdałem sobie sprawę, że ponieważ jest to bitmapa z zasobów losowanych, nie możesz użyć setAlpha. Czy jest inny sposób, proszę zobaczyć mój oryginalny kod do replikacji obrazu. –

+0

Zaktualizowałem kod, sprawdź teraz. –

3

Najlepszym sposobem, aby to wyjaśnić, jest pełny przykład niestandardowego widoku, który można pobrać z tego, czego potrzebujesz. Poniżej znajduje się widok, który to umożliwia.

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

Najbardziej efektywny sposób dynamicznie modyfikować przejrzystości co rysujesz jest zastosowanie go za pomocą Paint rysunek do Canvas. Będziesz musiał stale wyświetlać widok z każdą klatką, aby animacja była wyświetlana do momentu zniknięcia postaci. W przykładzie użyto obiektu Animation i obiektu Transformation, aby obsłużyć całą matematykę czasową, aby animacja rzeczywiście wyglądała dobrze.

Najważniejsze jest to, że uruchamiasz animację za pomocą zewnętrznego wyzwalacza (nie zalecałbym sprawdzania, kiedy należy zaniknąć w onDraw(), prawdopodobnie lepiej w miejscu, w którym te lokalizacje są zaktualizowane.) W moim przykładzie dla uproszczenia, zacząłem tę gdy widok na dotknięciu.

Ten wyzwalacz uruchamia animację i pobiera wartość początkową transformacji, a następnie invalidate() wyzwala nowy onDraw(). Chociaż animacja jest uruchomiony, onDraw() powtarza się ze względu na invalidate() i każda iteracja alfa na farbie nieznacznie się zmniejsza

Po zakończeniu animacji zadzwoni do ciebie: AnimationListener, dzięki czemu możesz wywołać przejście ekranu wewnątrz onAnimationEnd().

+0

Powinieneś tylko unieważnić obszar, w którym przerysowana jest postać. –

+0

To może być dobra optymalizacja, jeśli ogólny widok jest duży. Chociaż w wielu typowych przypadkach (np. Przy włączonym przyspieszeniu sprzętowym) brudne recty są właściwie ignorowane; więc generalnie nie warto angażować się w to, o ile nie gwarantuje tego wydajność. – Devunwired

+0

Ta odpowiedź od jednego z programistów Androida wydaje się przeczyć twojemu twierdzeniu, że akceleracja sprzętowa ignoruje brudne regiony: http://stackoverflow.com/questions/7233830/partial-invalidation-in-custom-android-view-withhardt-acceleration –