在视图动画时调用 setVisibility

Posted

技术标签:

【中文标题】在视图动画时调用 setVisibility【英文标题】:Call setVisibility while the view is animated 【发布时间】:2017-04-14 22:19:20 【问题描述】:

当我在视图的子视图上调用 setVisibility 而(父)视图使用 ViewCompat.postOnAnimation 进行动画处理时,事情会被破坏。 (setVisibility 不起作用 + 其他一些东西被破坏了)。

问题 - 是否有任何动画方法或解决方法允许在父动画时对子调用 setVisibility?

这是一个非常重要的请求,我认为这并不罕见,因为例如 http 请求是在随机时间返回的,并且在此期间可以随时为视图设置动画。

代码请求编辑:

关于代码,有点复杂。我先解释一下。它是自定义 CoordinatorLayout Behavior 中的动画,是标准 BottomSheetBehavior 的克隆(工作表从下向上滑动)。

通过调用这个来启动动画:

ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));

SettleRunnable 是这样的:

private class SettleRunnable implements Runnable 

    private final View mView;

    @State
    private final int mTargetState;

    SettleRunnable(View view, @State int targetState) 
        mView = view;
        mTargetState = targetState;
    

    @Override
    public void run() 
        if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) 
            ViewCompat.postOnAnimation(mView, this);
         else 
            setStateInternal(mTargetState);
        
    

如你所见,所有的动画移动都是由 mViewDragHelper.continueSettling 完成的。拖动助手是标准类 ViewDragHelper。

ViewDragHelper.continueSettling 看起来像这样

public boolean continueSettling(boolean deferCallbacks) 
    if (mDragState == STATE_SETTLING) 
        boolean keepGoing = mScroller.computeScrollOffset();
        final int x = mScroller.getCurrX();
        final int y = mScroller.getCurrY();
        final int dx = x - mCapturedView.getLeft();
        final int dy = y - mCapturedView.getTop();

        if (dx != 0) 
            ViewCompat.offsetLeftAndRight(mCapturedView, dx);
        
        if (dy != 0) 
            ViewCompat.offsetTopAndBottom(mCapturedView, dy);
        

        if (dx != 0 || dy != 0) 
            mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy);
        

        if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) 
            // Close enough. The interpolator/scroller might think we're still moving
            // but the user sure doesn't.
            mScroller.abortAnimation();
            keepGoing = false;
        

        if (!keepGoing) 
            if (deferCallbacks) 
                mParentView.post(mSetIdleRunnable);
             else 
                setDragState(STATE_IDLE);
            
        
    

    return mDragState == STATE_SETTLING;

它只是根据所选的目标状态将工作表向上或向下移动到所需位置。

问题的伪代码是:

launchAnimation(); // it takes eg 300 ms
changeVisibilityOfAnimatedViewChildren(); // this is problem

我可以等到动画结束,但正如我所说,如果 http 请求有点问题,我希望立即刷新数据而无需等待。

动画元素是 CoordinatorLayout。受 setVisibility 影响的孩子是其一个或多个孩子。

从this link 来看,android 似乎在动画和 setVisibility 方面普遍存在问题。

我现在想到的可能解决方案:

也许我会用另一个并行的 postOnAnimation() 任务来改变可见性 (?)

或者因为它基本上只是一步一步地后续调用移动函数mViewDragHelper.continueSettling(),为什么不用postOnAnimation()不做呢?没有它我也可以运行任务。但我猜 postOnAnimation 为具体设备选择了一些正确的动画步骤延迟 + 可能还有其他一些东西。

【问题讨论】:

可以分享代码吗? 嗨,我编辑了代码 【参考方案1】:

您可以将AnimatorListenerAdapter 添加到您的父动画中,并覆盖onAnimationEnd() 方法。在此方法中,您可以调用子动画。但是,我宁愿改变视图的 alpha 而不是可见性。在这种情况下,您可以实现更流畅的效果。

例如,考虑以下代码:

 parentAnimationInstance.addListener(new AnimatorListenerAdapter() 
                                            @Override
                                            public void onAnimationEnd(Animator animation) 
                                                super.onAnimationEnd(animation);
                                                childView.animate()
                                                    .alpha(1.f)
                                                    .setDuration(200)
                                                    .start();
                                            
                                        );

【讨论】:

嗨。是的,等到动画结束是解决方案之一。我想知道在视图动画时是否可以使用孩子的可见性,但是谢谢。 可以达到同样的效果。这要容易得多。

以上是关于在视图动画时调用 setVisibility的主要内容,如果未能解决你的问题,请参考以下文章

仅在用户滚动时调用 Scroll,而不是在 animate()

如何在移动时调整 UIView 的大小,就像 SnapGuide 一样?

UIKeyBoard 在方向更改为横向时调整大小

暂停时调用 UIViewPropertyAnimator 完成

didUpdateUserLocation 未在重新加载视图时调用

动画期间键盘和文本视图之间的间隙