【问题标题】:Animate newly created View of unknown size动画新创建的未知大小的视图
【发布时间】:2016-12-27 09:42:35
【问题描述】:

我想在 View 添加到父级后立即为其设置动画(类似于 DrawerLayout)。问题在于 View 的大小不同,而动画目标位置取决于该大小。简化示例代码:

    AnimatingView extends View {
        public int offsetX;

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            final int screenWidth = MeasureSpec.getSize(widthMeasureSpec);
            final int screenHeight = MeasureSpec.getSize(heightMeasureSpec);
            offsetX = calculateOffset(screenWidth);
            ...
        }
    }

类似的代码触发动画:

    @Override
    public void onClick(View v) {
        AnimatingView animatingView = new AnimatingView(getContext());
        parentLayout.addView(animatingView);
        animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
    }

在这种情况下,onMeasure() 发生在animate() 之后,因此动画失败。取决于视图测量的正确方法是什么?

简单而愚蠢的方法是基于isInitialized 标志的animateOnceAfterMeasuring(),但我认为这不是正确的方法。

【问题讨论】:

  • 为什么不在父布局 xml 中使用 `android:animateLayoutChanges' 属性
  • animatingView.animate().x(animatingView.offsetX).setDuration(500).start(); 行放入parentLayout.post(new Runnable() {});
  • @sohanshetty 在这种情况下,父 ViewGroup 会将孩子布置在默认位置,而不是孩子应该实际停止其移动的位置
  • @AkshayBhat'AB' post() 不保证在布局周期后运行
  • post 的作用是将runnable 添加到消息队列中。所以你之前所做的操作已经在消息队列中,所以它只会在布局/绘图通过后执行。

标签: android android-animation android-custom-view


【解决方案1】:

这应该可行:

    AnimatingView animatingView = new AnimatingView(getContext());
    parentLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                v.removeOnLayoutChangeListener(this);
                animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
            }
         });

【讨论】:

    【解决方案2】:

    您可以为此使用 ViewTreeObserver

    @Override
    public void onClick(View v) {
        final AnimatingView animatingView = new AnimatingView(getContext());
        parentLayout.addView(animatingView);
        animatingView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (Build.VERSION.SDK_INT < 16) {
                    animatingView.getViewTreeObserver().removeGlobalOnLayoutL‌​istener(this);
                } else {
                    animatingView.getViewTreeObserver().removeOnGlobalLayoutList‌​ener(this);
                }
                animatingView.animate().x(animatingView.offsetX).setDuration(500).start();
            }
        });
    }
    

    【讨论】:

    • 你应该在全局布局后移除这个监听器:if (Build.VERSION.SDK_INT &lt; 16) { animatingView.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { animatingView.getViewTreeObserver().removeOnGlobalLayoutListener(this); }
    猜你喜欢
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2020-09-29
    • 2016-01-30
    相关资源
    最近更新 更多