工具栏animateLayoutChanges奇怪的行为

时间:2017-11-10 21:10:27

标签: android

我在代码中设置了animateLayoutChanges = true,为我片段中的选项项设置动画。

当我打开PreferenceFragment时,我启用向上导航图标,然后在关闭它时禁用它,但它的行为方式很奇怪,在标题左侧留下了一种填充,其中NavigationIcon就是。< / p>

这是一个显示正在发生的事情的GIF:

img

你是否知道为什么会这样? 我在互联网上搜索得很远,但一无所获。

是否有以相同方式为这些项目设置动画的解决方法? 感谢。

2 个答案:

答案 0 :(得分:2)

备注:我知道这个线程已经一年多了,但是很多人仍然迷失在这个问题上。

我花了好几个小时才终于解决这个问题,而解决方案实际上相对容易。

场景

调用ActionBar.setDisplayHomeAsUpEnabled()或Toolbar.setNavigationIcon()时,工具栏将根据指定的值动态添加或删除导航视图

public void setNavigationIcon(@Nullable Drawable icon) {
    if (icon != null) {
        ensureNavButtonView();
        if (!isChildOrHidden(mNavButtonView)) {
            addSystemView(mNavButtonView, true);
        }
    } else if (mNavButtonView != null && isChildOrHidden(mNavButtonView)) {
        removeView(mNavButtonView);
        mHiddenViews.remove(mNavButtonView);
    }
    if (mNavButtonView != null) {
        mNavButtonView.setImageDrawable(icon);
    }
}

然后在onLayout中,它将检查是否存在导航按钮并对其进行布局。

protected void onLayout(boolean changed, int l, int t, int r, int b) {

    // more code before

    if (shouldLayout(mNavButtonView)) {
        if (isRtl) {
            right = layoutChildRight(mNavButtonView, right, collapsingMargins,
                    alignmentHeight);
        } else {
            left = layoutChildLeft(mNavButtonView, left, collapsingMargins,
                    alignmentHeight);
        }
    }

    // more code after. also mTitleTextView is laid out here
}

在布置每个视图后,工具栏还会增加左/右位置。这些值用作每个后续视图的偏移量。

要检查视图是否布局,请使用辅助功能:

private boolean shouldLayout(View view) {
    return view != null && view.getParent() == this && view.getVisibility() != GONE;
}

问题

通过xml中的代码或animateLayoutChanges设置layoutTransition时,我们会稍微改变行为。

让我们从我们从父级移除子级(ViewGroup代码)时发生的事情开始:

private void removeFromArray(int index) {
    final View[] children = mChildren;
    if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
        children[index].mParent = null;
    }

    // more code after
}

您是否提到我们设置了转换后,孩子的父母没有为空?这很重要!

还请回忆一下上面的shouldLayout会做什么-它仅检查三种情况:

  1. 视图不为空
  2. 视图的父级是工具栏
  3. 视图已消失

这是问题的根源-导航按钮已从工具栏中删除,但对此事件一无所知。

解决方案

为了解决此问题,我们需要迫使工具栏认为不应布局视图。理想情况下,重写shouldLayout方法会很好,但是我们没有那么奢侈...因此,实现此目的的唯一方法是更改​​导航按钮的可见性。

class FixedToolbar(context: Context, attrs: AttributeSet?) : MaterialToolbar(context, attrs) {
    companion object {
        private val navButtonViewField = Toolbar::class.java.getDeclaredField("mNavButtonView")
                .also { it.isAccessible = true }
    }

    override fun setNavigationIcon(icon: Drawable?) {
        super.setNavigationIcon(icon)

        (navButtonViewField.get(this) as? View)?.isGone = (icon == null)
    }
}

现在,工具栏将知道不得布置导航按钮,并且所有动画都将按预期进行。

答案 1 :(得分:0)

我找到了一种解决方法来使工作过渡。

调用supportActionBar?.setDisplayHomeAsUpEnabled(false)隐藏后退箭头按钮后,调用TransitionManager.beginDelayedTransition()方法手动触发转换。

// Hide the back arrow button
supportActionBar?.setDisplayHomeAsUpEnabled(false)
// Add a transition listener to the toolbar to set the toolbar title later
mToolbar.layoutTransition.addTransitionListener(object : LayoutTransition.TransitionListener {
    override fun startTransition(transition: LayoutTransition?, container: ViewGroup?, view: View?, transitionType: Int) {}

    override fun endTransition(transition: LayoutTransition?, container: ViewGroup?, view: View?, transitionType: Int) {
        setToolbarTitle("Agenda")
        mToolbar.layoutTransition.removeTransitionListener(this)
    }
})

TransitionManager.beginDelayedTransition(mToolbar)

之前

enter image description here

之后

enter image description here