我有一个奇怪的问题,我的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>
答案 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);
}