对 Android 列表视图标题高度进行动画处理会导致动画结束时闪烁



>问题

我正在尝试对列表视图标题高度进行动画处理。我可以正确获取动画,但是在动画完成后,列表视图闪烁。

尝试并失败

  1. 在不更改布局参数的情况下使用AnimationSet.setFillAfter()。动画工作正常,但是当您开始滚动列表时,标题会跳回到原始位置。
  2. AnimationSet.setFillAfter()与在 onAnimationEnd() 处应用的新布局参数一起使用。动画结束后,标题将跳到所需高度的两倍(动画高度加上布局参数中设置的高度)。当您开始滚动列表时,标题将捕捉到所需的高度。

法典

 if (mSearchAdapter.getCount() > 0 && mListView.getChildAt(0) == mHeaderPlaceholder) {
         Log.i(TAG, "Animating list view to make room for info bar");
         AnimationSet slideAnimation = new AnimationSet(true);
         TranslateAnimation translate = new TranslateAnimation(0, 0, 0, newHeight);
         translate.setDuration(mInfoBarAnimationDuration);
         translate.setInterpolator(new DecelerateInterpolator());
         slideAnimation.addAnimation(translate);
         slideAnimation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    isAnimatingViewTransition = true;
                }
                @Override
                public void onAnimationEnd(Animation animation) {
                    isAnimatingViewTransition = false;
                    final AbsListView.LayoutParams layoutParams = (AbsListView.LayoutParams) mHeaderPlaceholder.getLayoutParams();
                    layoutParams.height = newHeight;
                    mHeaderPlaceholder.setLayoutParams(layoutParams);
                }
                @Override
                public void onAnimationRepeat(Animation animation) {
                }
        });
        mListView.startAnimation(slideAnimation);
 } else {
        Log.i(TAG, "Adjusting list view header to make room for info bar");
        mHeaderPlaceholder.getLayoutParams().height = newHeight;
 }

我认为可以通过侦听和覆盖列表视图的 ViewTreeObserver onPreDraw()onGlobalLayout()的事件来避免闪烁。但我不知道我该如何实现它。

任何帮助都非常感谢!

我没有对 ListView 标头进行动画处理,而是选择使用 ValueAnimator 来实现相同的效果。这是代码:

if (mSearchAdapter.getCount() > 0 && mListView.getChildAt(0) == mHeaderPlaceholder) {
            ValueAnimator mSlideListViewAnimator = ObjectAnimator.ofInt(from, to);
            mSlideListViewAnimator.setDuration(mInfoBarAnimationDuration);
            mSlideListViewAnimator.setInterpolator(new DecelerateInterpolator());
            mSlideListViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Integer animatedYValue= (Integer) animation.getAnimatedValue();
                    final AbsListView.LayoutParams layoutParams = (AbsListView.LayoutParams) mHeaderPlaceholder.getLayoutParams();
                    layoutParams.height = animatedYValue;
                    mHeaderPlaceholder.requestLayout();
                }
            });
            mSlideListViewAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    isAnimatingViewTransition = true;
                }
                @Override
                public void onAnimationEnd(Animator animation) {
                    isAnimatingViewTransition = false;
                }
            });
            mSlideListViewAnimator.start();
} else {
            Log.i(TAG, "Adjusting list view header to make room for info bar");
            mHeaderPlaceholder.getLayoutParams().height = newHeight;
}

最新更新