1

I'm trying to animate a card flip and then fling it away with an animation. For the most part I've completed that. The problem is I can't get the card to reliably be removed.

Question: How can I reliably delete a View after animation on it is complete? (also I'm using AnimationSet, so this may change things)

Here is what my code looks like.

flingCardAway(the problem area)

private void flingCardAway(){
    final View cardContainer = findViewById(R.id.card_container);
    ViewCompat.setTranslationZ(cardContainer, 1.0f);

    AnimationSet anim = new AnimationSet(true);

    RotateAnimation rotate1 = new RotateAnimation(0,-45, Animation.RELATIVE_TO_SELF,0.5f , Animation.RELATIVE_TO_SELF,0.5f );
    rotate1.setStartOffset(100);
    rotate1.setDuration(500);
    anim.addAnimation(rotate1);

    TranslateAnimation trans1 =  new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
    trans1.setDuration(600);
    anim.addAnimation(trans1);

    AlphaAnimation opacity1 = new AlphaAnimation(1.0f, 0.0f);
    opacity1.setDuration(400);
    opacity1.setStartOffset(200);
    anim.addAnimation(opacity1);

    cardContainer.setAnimation(anim);
    cardContainer.setVisibility(View.VISIBLE);



    anim.setAnimationListener(new Animation.AnimationListener(){
        @Override
        public void onAnimationStart(Animation arg0) {
        }
        @Override
        public void onAnimationRepeat(Animation arg0) {
        }
        @Override
        public void onAnimationEnd(Animation arg0) {
            final View cardContainer2 = findViewById(R.id.card_container);
            ((ViewGroup)cardContainer2.getParent()).removeView(cardContainer2);
        }
    });
}

Full class for reference Study.java

package com.example.trevorwood.biggles.study;

import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

import com.example.trevorwood.biggles.R;

public class Study extends AppCompatActivity {
    LinearLayout mFlipCardLinearLayout;
    LinearLayout mCardFlippedButtons;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_study);
        Intent intent = getIntent();
        // String value = intent.getStringExtra("key");
        Toolbar toolbar = (Toolbar) findViewById(R.id.study_toolbar);
        toolbar.setTitleTextColor(Color.WHITE);//0xAARRGGBB
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        mFlipCardLinearLayout = (LinearLayout) findViewById(R.id.flip_card_linear_layout);
        mCardFlippedButtons = (LinearLayout) findViewById(R.id.card_flipped_buttons);

        final Drawable upArrow = getResources().getDrawable(R.drawable.ic_back_arrow);
        upArrow.setColorFilter(getResources().getColor(R.color.colorWhite), PorterDuff.Mode.SRC_ATOP);
        getSupportActionBar().setHomeAsUpIndicator(upArrow);

        makeNewCard();

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            // Respond to the action bar's Up/Home button
            case android.R.id.home:
                onBackPressed();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
    }

    public void onCardClick(View view) {
        flipCard();
    }

    public void onCardFlippedButtonsClick(View view) {
        Integer numberPressed;
        switch (view.getId()){
            case R.id.color_button_1:numberPressed = 1;break;
            case R.id.color_button_2:numberPressed = 2;break;
            case R.id.color_button_3:numberPressed = 3;break;
            case R.id.color_button_4:numberPressed = 4;break;
            case R.id.color_button_5:numberPressed = 5;break;
            default:numberPressed = 0;
        }

        saveCardStats(numberPressed);
        flingCardAway();
        resetForNewCard();
        makeNewCard();
    }

    private void flipCard() {
        FrameLayout cardFrame = (FrameLayout) findViewById(R.id.card_frame);
        Integer childCount = cardFrame.getChildCount();
        Log.d("Simple","childCount: "+childCount);

        View cardContainer = findViewById(R.id.card_container);
        View cardFace = findViewById(R.id.card_front);
        View cardBack = findViewById(R.id.card_back);

        FlipAnimation flipAnimation = new FlipAnimation(cardFace, cardBack);

        if (cardFace.getVisibility() == View.GONE) {
            mFlipCardLinearLayout.setVisibility(View.VISIBLE);
            mCardFlippedButtons.setVisibility(View.GONE);
            flipAnimation.reverse();
        }else{
            mFlipCardLinearLayout.setVisibility(View.GONE);
            mCardFlippedButtons.setVisibility(View.VISIBLE);
        }
        cardContainer.startAnimation(flipAnimation);
    }

    private void saveCardStats(Integer numberPressed){

    }

    private void flingCardAway(){
        final View cardContainer = findViewById(R.id.card_container);
        ViewCompat.setTranslationZ(cardContainer, 1.0f);

        AnimationSet anim = new AnimationSet(true);

        RotateAnimation rotate1 = new RotateAnimation(0,-45, Animation.RELATIVE_TO_SELF,0.5f , Animation.RELATIVE_TO_SELF,0.5f );
        rotate1.setStartOffset(100);
        rotate1.setDuration(500);
        anim.addAnimation(rotate1);

        TranslateAnimation trans1 =  new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
        trans1.setDuration(600);
        anim.addAnimation(trans1);

        AlphaAnimation opacity1 = new AlphaAnimation(1.0f, 0.0f);
        opacity1.setDuration(400);
        opacity1.setStartOffset(200);
        anim.addAnimation(opacity1);

        cardContainer.setAnimation(anim);
        cardContainer.setVisibility(View.VISIBLE);



        anim.setAnimationListener(new Animation.AnimationListener(){
            @Override
            public void onAnimationStart(Animation arg0) {
            }
            @Override
            public void onAnimationRepeat(Animation arg0) {
            }
            @Override
            public void onAnimationEnd(Animation arg0) {
                final View cardContainer2 = findViewById(R.id.card_container);
                ((ViewGroup)cardContainer2.getParent()).removeView(cardContainer2);
            }
        });
    }

    private void resetForNewCard(){
        mFlipCardLinearLayout.setVisibility(View.VISIBLE);
        mCardFlippedButtons.setVisibility(View.GONE);
    }

    private void makeNewCard(){
        FrameLayout cardFrame = (FrameLayout) findViewById(R.id.card_frame);
        Integer childCount = cardFrame.getChildCount();
        Log.d("Simple","childCount: "+childCount);
        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.study_card, cardFrame);
    }

}

FlipAnimation.java (not as important, just a reference)

package com.example.trevorwood.biggles.study;

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;

public class FlipAnimation extends Animation {
    private Camera camera;
    private View fromView;
    private View toView;

    private float centerX;
    private float centerY;

    private boolean forward = true;

    /**
     * Creates a 3D flip animation between two views.
     *
     * @param fromView First view in the transition.
     * @param toView   Second view in the transition.
     */
    public FlipAnimation(View fromView, View toView) {
        this.fromView = fromView;
        this.toView = toView;

        setDuration(300);
        setFillAfter(false);
        setInterpolator(new AccelerateDecelerateInterpolator());
    }

    public void reverse() {
        forward = false;
        View switchView = toView;
        toView = fromView;
        fromView = switchView;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        centerX = width / 2;
        centerY = height / 2;
        camera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        // Angle around the y-axis of the rotation at the given time
        // calculated both in radians and degrees.
        final double radians = Math.PI * interpolatedTime;
        float degrees = (float) (180.0 * radians / Math.PI);

        // Once we reach the midpoint in the animation, we need to hide the
        // source view and show the destination view. We also need to change
        // the angle by 180 degrees so that the destination does not come in
        // flipped around
        if (interpolatedTime >= 0.5f) {
            degrees -= 180.f;
            fromView.setVisibility(View.GONE);
            toView.setVisibility(View.VISIBLE);
        }

        if (forward)
            degrees = -degrees; //determines direction of rotation when flip begins

        final Matrix matrix = t.getMatrix();
        camera.save();
        camera.translate(0, 0, Math.abs(degrees)*6);
        camera.getMatrix(matrix);
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

I saw this, it helped but didn't solve my problem. End animation event android

I saw this too, but am not sure how to implement it into my own project. android animation is not finished in onAnimationEnd

The google docs all point to this link but this isn't reliable under rapid clicks.

Trevor Wood
  • 2,347
  • 5
  • 31
  • 56

1 Answers1

0

This worked for me. Even though if you were to think about it, it probably shouldn't work. (It 100% would not work if converted to JavaScript, as the view is being removed before the animation has ended.) Perhaps somebody with more Android experience can explain why this works.

My hypothesis on why this works (please keep in mind, this is just a guess): is that Android's animations actually turn the view into something else entirely, while the original view is turned transparent. Then when the animation is ended, the animation view is deleted and the original view is turned back to visible.

private void flingCardAway(){

    View cardContainer = findViewById(R.id.card_container);
    ViewCompat.setTranslationZ(cardContainer, 1.0f);

    AnimationSet anim = new AnimationSet(true);

    RotateAnimation rotate1 = new RotateAnimation(0,-45, Animation.RELATIVE_TO_SELF,0.5f , Animation.RELATIVE_TO_SELF,0.5f );
    rotate1.setStartOffset(10);
    rotate1.setDuration(500);
    anim.addAnimation(rotate1);

    TranslateAnimation trans1 =  new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.2f, Animation.RELATIVE_TO_PARENT, -0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
    trans1.setDuration(100);
    anim.addAnimation(trans1);

    TranslateAnimation trans2 =  new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
    trans2.setStartOffset(100);
    trans2.setDuration(100);
    anim.addAnimation(trans2);

    AlphaAnimation opacity1 = new AlphaAnimation(1.0f, 0.0f);
    opacity1.setDuration(300);
    opacity1.setStartOffset(300);
    anim.addAnimation(opacity1);

    cardContainer.setAnimation(anim);


    mCardFrame.removeAllViews();

}
Trevor Wood
  • 2,347
  • 5
  • 31
  • 56