android - 工具栏 animateLayoutChanges 奇怪的行为

标签 android

我在我的代码中设置了 animateLayoutChanges=true 来为我的 fragment 中的选项项目设置动画。

当我打开 PreferenceFragment 时,我启用向上导航图标,然后在关闭它时将其禁用,但它的行为很奇怪,在标题左侧(NavigationIcon 所在的位置)留下了一种填充。

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

img

你们知道为什么会这样吗? 我在互联网上四处搜索,但一无所获。

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

最佳答案

备注:我知道这个帖子已经一年多了,但很多人仍然遇到这个问题。

我花了好几个小时才最终深入研究这个问题,解决方案实际上相对容易。

场景

当你调用 ActionBar.setDisplayHomeAsUpEnabled() 或 Toolbar.setNavigationIcon() 时,Toolbar 将根据指定的值动态添加或删除导航 View

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
}

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

要检查 View 是否应该布局,它使用辅助函数:

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
}

你有没有提到当我们设置了过渡时, child 的 parent 没有被清空?这很重要!

另外请记忆一下上面的 shouldLayout 做了什么——它只检查三种情况:

  1. View 不为空
  2. View 的父级是工具栏
  3. View 没有消失

这就是问题的根源 - 导航按钮已从工具栏中删除,但它并不知道这一点。

解决方案

为了解决这个问题,我们需要强制工具栏认为不应布局 View 。理想情况下,重写 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)
    }
}

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

关于android - 工具栏 animateLayoutChanges 奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47231180/

相关文章:

android - 使用来自 sqlite DB 的图像动态填充 galleryview

android - 是否可以将所有客户端信息只写入一个agconnect-services.json文件?

Android App Links - 排除特定的子目录

java - 如何在 Release build 的 android 中使用 Proguard 防止 LOG 打印

java - 文件被删除而没有被复制

android - 尝试执行自定义 ListView ,但当我尝试连接数据库时出现错误

android - 有没有办法释放(干净的)静态字段

android - Listview 的页脚 View 未显示在一台设备上,而是显示在另一台设备上?

android - AdMob 收到广告后 - 连接到广告网址的 IOException

java - 获取当前方向并锁定