Android视图可见性切换动画拼接问题排查
解决Android视图可见性切换时的动画拼接问题
嘿,看了你的代码,我发现问题出在嵌套的动画监听逻辑太复杂,多个淡出动画的结束时机不一致,导致淡入动画可能被触发多次,或者时序混乱。咱们来简化这个逻辑,用更清晰的方式实现视图切换的淡入淡出效果。
核心问题分析
你现在的fadeOutViews方法里,每个视图的动画监听都嵌套在一起,当有多个视图需要淡出时,很难保证所有淡出动画都完成后再执行淡入,容易出现动画拼接不上的情况。而且重复的代码也增加了维护难度。
优化方案:用ViewPropertyAnimator的withEndAction统一管理动画时序
我们可以封装通用的淡入、淡出方法,利用withEndAction在所有淡出动画完成后,再统一执行淡入动画,这样逻辑更清晰,也不会出现时序问题。
修改后的完整代码
public class SearchBookTest extends AppCompatActivity { private final static int INTRO_VIEW = 0; private final static int OFFLINE_VIEW = 1; private boolean[] currentView = {true, false}; private FloatingSearchView mSearchView; private TextView mIntroTextViewTop; private TextView mIntroTextViewBottom; private TextView mNoConnectionTextViewTop; private TextView mNoConnectionTextViewBottom; private AppCompatButton mNoConnectionButton; private int mShortAnimationDuration; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_search_test); mSearchView = findViewById(R.id.floating_search_view); mIntroTextViewTop = findViewById(R.id.search_book_intro_top); mIntroTextViewBottom = findViewById(R.id.search_book_intro_bottom); mNoConnectionTextViewTop = findViewById(R.id.search_book_no_connection_top); mNoConnectionTextViewBottom = findViewById(R.id.search_book_no_connection_bottom); mNoConnectionButton = findViewById(R.id.search_book_no_connection_try_again); mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); // 初始化视图可见性,确保初始状态正确 setViewsVisibility(View.GONE, mNoConnectionTextViewTop, mNoConnectionTextViewBottom, mNoConnectionButton); setViewsVisibility(View.VISIBLE, mIntroTextViewTop, mIntroTextViewBottom); setupQueryChangeListener(); } private void setupQueryChangeListener() { mSearchView.setOnQueryChangeListener(new FloatingSearchView.OnQueryChangeListener() { @Override public void onSearchTextChanged(String oldQuery, String newQuery) { switch (newQuery.length()) { case 1: showIntroView(); break; case 2: showOfflineView(); break; default: // 可以根据需求处理其他长度的情况,比如隐藏所有视图 break; } } }); } private void showOfflineView() { if (currentView[INTRO_VIEW]) { // 需要隐藏Intro视图,显示Offline视图 switchViews( new View[]{mIntroTextViewTop, mIntroTextViewBottom}, new View[]{mNoConnectionTextViewTop, mNoConnectionTextViewBottom, mNoConnectionButton} ); currentView[INTRO_VIEW] = false; currentView[OFFLINE_VIEW] = true; } } private void showIntroView() { if (currentView[OFFLINE_VIEW]) { // 需要隐藏Offline视图,显示Intro视图 switchViews( new View[]{mNoConnectionTextViewTop, mNoConnectionTextViewBottom, mNoConnectionButton}, new View[]{mIntroTextViewTop, mIntroTextViewBottom} ); currentView[OFFLINE_VIEW] = false; currentView[INTRO_VIEW] = true; } } /** * 切换视图:先淡出要隐藏的视图,再淡入要显示的视图 */ private void switchViews(View[] viewsToHide, View[] viewsToShow) { // 先执行所有要隐藏视图的淡出动画 fadeOutViews(viewsToHide, () -> { // 所有淡出动画完成后,执行淡入动画 fadeInViews(viewsToShow); }); } /** * 淡出一组视图,完成后执行回调 */ private void fadeOutViews(View[] views, Runnable onFinish) { if (views == null || views.length == 0) { onFinish.run(); return; } int animatingCount = views.length; for (View view : views) { if (view == null) { if (--animatingCount == 0) { onFinish.run(); } continue; } view.animate() .alpha(0f) .setDuration(mShortAnimationDuration) .withEndAction(() -> { view.setVisibility(View.GONE); if (--animatingCount == 0) { onFinish.run(); } }); } } /** * 淡入一组视图 */ private void fadeInViews(View[] views) { if (views == null || views.length == 0) return; for (View view : views) { if (view == null) continue; view.setAlpha(0f); view.setVisibility(View.VISIBLE); view.animate() .alpha(1f) .setDuration(mShortAnimationDuration); } } /** * 批量设置视图可见性 */ private void setViewsVisibility(int visibility, View... views) { for (View view : views) { if (view != null) { view.setVisibility(visibility); } } } }
关键改进点
- 统一管理动画时序:用
switchViews方法封装切换逻辑,确保所有淡出动画完成后才执行淡入,避免时序混乱 - 简化动画监听:使用
withEndAction替代嵌套的AnimatorListenerAdapter,代码更简洁易读 - 批量操作视图:封装
setViewsVisibility方法,减少重复代码 - 初始化可见性:在
onCreate里明确设置初始视图的可见性,避免布局默认状态导致的异常
布局注意事项
确保你的布局文件中,初始不需要显示的视图(比如Offline相关视图)默认设置android:visibility="gone",或者在代码初始化时设置,避免初始显示异常。
比如在布局里给Offline视图添加:
android:visibility="gone"
这样修改后,视图切换的动画就会流畅衔接,不会出现拼接问题啦~
内容的提问来源于stack exchange,提问作者Mdp11
相关产品推荐
相关产品推荐

