为什么在视图上运行第二个viewpropertyanimation会破坏动画侦听器?

时间:2016-10-28 14:27:27

标签: android android-animation viewpropertyanimator

我有一个奇怪的问题,我的onAnimationEnd被重复调用(因此我的动画一直反复运行,即使我没有明确地调用它)。

以下是有关正在发生的事情的屏幕录制:https://youtu.be/TfGiLvwLdBM

以下是我的代码:

public class MainActivity extends AppCompatActivity {

private static final String TAG = "TT_MainActivity";

ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

    setupViews();
    showLogin();
}

private void setupViews() {
    // Login views
    binding.loginContainer.setTranslationY(Utils.getScreenHeight(this));
    binding.tvNotRegistered.setTranslationY(Utils.getScreenHeight(this));
    binding.tvLoginTitle.setTranslationY(-Utils.dpToPx(500));
    binding.etEmail.setTranslationY(-Utils.dpToPx(500));
    binding.etPassword.setTranslationY(-Utils.dpToPx(500));
    binding.btnLogin.setTranslationY(-Utils.dpToPx(500));

    // Signup views
    binding.signupContainer.setTranslationY(-Utils.getScreenHeight(this));
    binding.tvAlreadyHaveAAccount.setTranslationY(-Utils.getScreenHeight(this));
    binding.tvSignupTitle.setTranslationY(-Utils.dpToPx(500));
    binding.etEmailSignup.setTranslationY(-Utils.dpToPx(500));
    binding.etPasswordSignup.setTranslationY(-Utils.dpToPx(500));
    binding.btnSignup.setTranslationY(-Utils.dpToPx(500));

    // Click listeners
    setOnClickListeners();
}

private void setOnClickListeners() {
    // LOGIN
    binding.btnLogin.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d(TAG, "login()...");
        }
    });

    binding.tvNotRegistered.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d(TAG, "showSignup()..");
            binding.tvNotRegistered.animate()
                    .translationY(Utils.getScreenHeight(MainActivity.this))
                    .setInterpolator(new AccelerateInterpolator());
            binding.loginContainer.animate()
                    .translationY(Utils.getScreenHeight(MainActivity.this))
                    .setInterpolator(new AccelerateInterpolator())
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            Log.d(TAG, "onAnimationEnd: showSignup()");
                            binding.loginContainer.setVisibility(View.GONE);
                            binding.tvNotRegistered.setVisibility(View.GONE);
                            showSignup();
                        }
                    });
        }
    });

    binding.btnSignup.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d(TAG, "signup()...");
        }
    });

    // SIGNUP
    binding.tvAlreadyHaveAAccount.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d(TAG, "showLogin()..");
            binding.tvAlreadyHaveAAccount.animate()
                    .translationY(-Utils.getScreenHeight(MainActivity.this))
                    .setInterpolator(new AccelerateInterpolator());
            binding.signupContainer.animate()
                    .translationY(-Utils.getScreenHeight(MainActivity.this))
                    .setInterpolator(new AccelerateInterpolator())
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            Log.d(TAG, "onAnimationEnd: showLogin()");
                            binding.signupContainer.setVisibility(View.GONE);
                            binding.tvAlreadyHaveAAccount.setVisibility(View.GONE);
                            showLogin();
                        }
                    });
        }
    });
}


// SIGNUP
private void showSignup() {
    binding.signupContainer.setVisibility(View.VISIBLE);
    binding.tvAlreadyHaveAAccount.setVisibility(View.VISIBLE);
    binding.signupContainer.animate()
            .setDuration(300)
            .setInterpolator(new OvershootInterpolator(1.0f))
            .translationY(0)
            .setStartDelay(300);
    binding.tvAlreadyHaveAAccount.animate()
            .setDuration(300)
            .setStartDelay(400)
            .translationY(0)
            .setInterpolator(new OvershootInterpolator(1.0f))
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    animateSignupContainerContents();
                }
            });
}

private void animateSignupContainerContents() {
    binding.tvSignupTitle.animate()
            .translationY(0)
            .setDuration(400)
            .setInterpolator(new DecelerateInterpolator());

    binding.etEmailSignup.animate()
            .translationY(0)
            .setDuration(300)
            .setInterpolator(new DecelerateInterpolator());

    binding.etPasswordSignup.animate()
            .translationY(0)
            .setDuration(200)
            .setInterpolator(new DecelerateInterpolator());

    binding.btnSignup.animate()
            .translationY(0)
            .setDuration(100)
            .setInterpolator(new DecelerateInterpolator());
}

// LOGIN
private void showLogin() {
    binding.loginContainer.setVisibility(View.VISIBLE);
    binding.tvNotRegistered.setVisibility(View.VISIBLE);
    binding.loginContainer.animate()
            .setDuration(300)
            .setInterpolator(new OvershootInterpolator(1.0f))
            .translationY(0)
            .setStartDelay(300);
    binding.tvNotRegistered.animate()
            .setDuration(300)
            .setStartDelay(400)
            .translationY(0)
            .setInterpolator(new OvershootInterpolator(1.0f))
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    animateLoginContainerContents();
                }
            });
}

private void animateLoginContainerContents() {
    binding.tvLoginTitle.animate()
            .translationY(0)
            .setDuration(400)
            .setInterpolator(new DecelerateInterpolator());

    binding.etEmail.animate()
            .translationY(0)
            .setDuration(300)
            .setInterpolator(new DecelerateInterpolator());

    binding.etPassword.animate()
            .translationY(0)
            .setDuration(200)
            .setInterpolator(new DecelerateInterpolator());

    binding.btnLogin.animate()
            .translationY(0)
            .setDuration(100)
            .setInterpolator(new DecelerateInterpolator());
}

}

使用相应的xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="mango.matts.MainActivity">

<RelativeLayout
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_login_gradient">

    <include layout="@layout/anchors"/>

    <!--Start login-->

    <LinearLayout android:id="@+id/loginContainer"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="@android:color/white"
        android:elevation="@dimen/material_dialog_elevation"
        android:layout_marginStart="@dimen/activity_horizontal_margin"
        android:layout_marginEnd="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/login_container_padding_vertical"
        android:paddingBottom="@dimen/login_container_padding_vertical"
        android:paddingEnd="@dimen/login_container_padding_horizontal"
        android:paddingStart="@dimen/login_container_padding_horizontal"
        android:layout_marginBottom="@dimen/login_container_margin_bottom">

        <TextView android:id="@+id/tvLoginTitle"
            style="@style/MaterialTypography.Regular.Title"
            android:layout_gravity="center_horizontal"
            android:layout_width="@dimen/login_content_width"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/login_text_margin_bottom"
            android:textAlignment="center"
            android:text="@string/login"/>

        <EditText android:id="@+id/etEmail"
            android:inputType="textEmailAddress"
            android:hint="@string/email"
            android:layout_width="match_parent"
            android:layout_marginBottom="@dimen/login_text_margin_bottom"
            android:layout_height="wrap_content" />

        <EditText android:id="@+id/etPassword"
            android:inputType="textPassword"
            android:hint="@string/password"
            android:layout_marginBottom="@dimen/login_text_margin_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <Button android:id="@+id/btnLogin"
            android:text="@string/login"
            android:textAllCaps="true"
            style="@style/MaterialTypography.Regular.Button"
            android:textColor="@android:color/white"
            android:backgroundTint="@color/colorAccent"
            android:layout_width="match_parent"
            android:layout_height="@dimen/btn_login_height" />

    </LinearLayout>

    <TextView android:id="@+id/tvNotRegistered"
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/loginContainer"
        style="@style/MaterialTypography.Regular"
        android:textColor="@android:color/white"
        android:text="@string/notRegisteredSignup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <!--End login-->
    <!--Start Signup-->
    <LinearLayout android:id="@+id/signupContainer"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="@android:color/white"
        android:elevation="@dimen/material_dialog_elevation"
        android:layout_marginStart="@dimen/activity_horizontal_margin"
        android:layout_marginEnd="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/login_container_padding_vertical"
        android:paddingBottom="@dimen/login_container_padding_vertical"
        android:paddingEnd="@dimen/login_container_padding_horizontal"
        android:paddingStart="@dimen/login_container_padding_horizontal"
        android:layout_marginBottom="@dimen/login_container_margin_bottom">

        <TextView android:id="@+id/tvSignupTitle"
            style="@style/MaterialTypography.Regular.Title"
            android:layout_gravity="center_horizontal"
            android:layout_width="@dimen/login_content_width"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/login_text_margin_bottom"
            android:textAlignment="center"
            android:text="@string/signup"/>

        <EditText android:id="@+id/etEmailSignup"
            android:inputType="textEmailAddress"
            android:hint="@string/email"
            android:layout_width="match_parent"
            android:layout_marginBottom="@dimen/login_text_margin_bottom"
            android:layout_height="wrap_content"/>

        <EditText android:id="@+id/etPasswordSignup"
            android:inputType="textPassword"
            android:hint="@string/password"
            android:layout_marginBottom="@dimen/login_text_margin_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <Button android:id="@+id/btnSignup"
            android:text="@string/signup"
            android:textAllCaps="true"
            style="@style/MaterialTypography.Regular.Button"
            android:textColor="@android:color/white"
            android:backgroundTint="@color/colorAccent"
            android:layout_width="match_parent"
            android:layout_height="@dimen/btn_login_height" />

    </LinearLayout>

    <TextView android:id="@+id/tvAlreadyHaveAAccount"
        android:layout_centerHorizontal="true"
        android:layout_below="@+id/signupContainer"
        style="@style/MaterialTypography.Regular"
        android:textColor="@android:color/white"
        android:text="@string/alreadyAMemberLogin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

1 个答案:

答案 0 :(得分:1)

发生这种情况是因为对animate()的调用始终返回相同的ViewPropertyAnimator对象。它是该特定观点的内部对象。

我认为出于效率原因就是这样,不需要在每次通话时都创建新对象。

对于我们的开发人员来说,这意味着我们在该对象上设置的所有参数都保持在调用之间。因此,如果您打电话给setDuration(1234),然后再打电话给另一个动画,它仍将使用1234毫秒作为持续时间。延迟,插值器或setListener也是如此。

因此,使其工作的方法是始终重置您不用于该动画的任何参数。这意味着您应该将.setListener(null)调用到任何不使用侦听器的动画。

你也可以创建一个帮助方法,如:

static ViewPropertyAnimator animate(View view){
    return view.animate()
        .setListener(null)
        .setDuration(DEFAULT_DURATION)
        .setStartDelay(0)
        .setInterpolator(DEFAULT_INTERPOLATOR);
}