如何实现启动页TextView从中心显示2秒后动画移至顶部并固定?
实现启动页TextView的延迟移动动画
嘿,这个启动页的动画需求很常见,咱们一步步来拆解实现,保证效果丝滑又贴合你的要求👇
第一步:布局文件设置
先把TextView初始放在屏幕中心,用ConstraintLayout能轻松实现精准定位:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/tv_app_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="你的应用名称" android:textSize="24sp" android:textStyle="bold" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
第二步:实现延迟移动动画
核心逻辑是:让TextView在中心停留2秒,然后执行Y轴平移动画到顶部,最后固定位置避免布局刷新后回退。这里用ObjectAnimator更简洁,能直接操作View属性。
Kotlin 实现
import android.animation.ObjectAnimator import android.os.Bundle import android.os.Handler import android.os.Looper import androidx.appcompat.app.AppCompatActivity import kotlinx.android.synthetic.main.activity_splash.* class SplashActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_splash) // 延迟2秒触发动画 Handler(Looper.getMainLooper()).postDelayed({ // 计算移动距离:从中心到顶部 = 屏幕半高 - TextView自身半高,避免文字被顶出屏幕 val moveDistance = (resources.displayMetrics.heightPixels / 2 - tv_app_name.height / 2).toFloat() // 创建Y轴向上平移的动画 val animator = ObjectAnimator.ofFloat(tv_app_name, "translationY", 0f, -moveDistance) animator.duration = 800 // 动画时长可按需调整,800ms是比较自然的速度 animator.start() // 动画结束后修改布局约束,固定TextView在顶部 animator.addListener(object : android.animation.Animator.AnimatorListener { override fun onAnimationStart(animation: android.animation.Animator?) {} override fun onAnimationEnd(animation: android.animation.Animator?) { tv_app_name.layoutParams.apply { (this as androidx.constraintlayout.widget.ConstraintLayout.LayoutParams).run { topToTop = androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID bottomToBottom = androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.UNSET } tv_app_name.requestLayout() } } override fun onAnimationCancel(animation: android.animation.Animator?) {} override fun onAnimationRepeat(animation: android.animation.Animator?) {} }) }, 2000) // 2000毫秒 = 2秒延迟 } // Activity销毁时取消动画,避免内存泄漏 override fun onDestroy() { super.onDestroy() tv_app_name.animate().cancel() } }
Java 实现
import android.animation.ObjectAnimator; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import androidx.appcompat.app.AppCompatActivity; import android.widget.TextView; public class SplashActivity extends AppCompatActivity { private TextView tvAppName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); tvAppName = findViewById(R.id.tv_app_name); // 延迟2秒执行动画 new Handler(Looper.getMainLooper()).postDelayed(() -> { // 计算移动距离 float moveDistance = (getResources().getDisplayMetrics().heightPixels / 2 - tvAppName.getHeight() / 2); // 创建Y轴平移动画 ObjectAnimator animator = ObjectAnimator.ofFloat(tvAppName, "translationY", 0f, -moveDistance); animator.setDuration(800); animator.start(); // 动画结束后固定位置 animator.addListener(new android.animation.Animator.AnimatorListener() { @Override public void onAnimationStart(android.animation.Animator animation) {} @Override public void onAnimationEnd(android.animation.Animator animation) { androidx.constraintlayout.widget.ConstraintLayout.LayoutParams params = (androidx.constraintlayout.widget.ConstraintLayout.LayoutParams) tvAppName.getLayoutParams(); params.topToTop = androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID; params.bottomToBottom = androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.UNSET; tvAppName.setLayoutParams(params); } @Override public void onAnimationCancel(android.animation.Animator animation) {} @Override public void onAnimationRepeat(android.animation.Animator animation) {} }); }, 2000); } @Override protected void onDestroy() { super.onDestroy(); tvAppName.animate().cancel(); } }
关键细节提醒
- 移动距离必须考虑TextView自身高度,不然文字可能会被顶出屏幕外;
- 动画结束后修改布局约束是为了防止屏幕旋转、布局刷新等场景下,TextView回到中心位置;
- 在
onDestroy中取消动画,避免Activity销毁后动画仍在运行导致内存泄漏。
内容的提问来源于stack exchange,提问作者Satyaraj Moily
相关产品推荐
相关产品推荐

