使用removeView()从AppBarLayout中删除TabLayout时出现故障

问题描述 投票:4回答:3

在recyclerview中单击某个项目时,我会调用它

appbar.removeView(tabs)

This视频显示了会发生什么

它似乎完全删除TabLayout没有动画,然后将其添加回来,然后使用动画删除它。我放慢了转变速度,以显示它的作用。

当像这样添加它们时也会发生这种情况

if (tabs.parent != null) {
        (tabs.parent as ViewGroup).removeView(tabs)
    }
    appbar.addView(tabs)
    appbar.setExpanded(true, true)

这是我的布局

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinator_main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:theme="@style/Theme.AppCompat.Light.NoActionBar">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:animateLayoutChanges="true"
        app:elevation="0dp"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar">

        <android.support.v7.widget.Toolbar
            xmlns:android="http://schemas.android.com/apk/res/android"
            style="@style/MyToolbar"
            android:id="@+id/toolbar"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            app:layout_scrollFlags="scroll|enterAlways|snap"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabTextAppearance="@style/TabText"
            android:layout_marginRight="@dimen/small_spacing"
            android:layout_marginLeft="@dimen/small_spacing"
            app:tabMode="fixed"
            app:tabGravity="fill"
            app:tabIndicatorHeight="2dp"
            app:layout_scrollFlags="enterAlways"/>

    </android.support.design.widget.AppBarLayout>


    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/appbar"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" >

        <***.***.CustomViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </FrameLayout>

</android.support.design.widget.CoordinatorLayout>
android android-tablayout android-appbarlayout
3个回答
1
投票

那么发生了什么?

除了你提到的闪光之外,一切似乎都能正常工作。我带了Chris Banes的Cheese Square应用程序并进行了一些修改以复制你所看到的内容。单击FAB将删除并添加选项卡。

这是我想出的视频。

enter image description here

这是删除TabLayout时问题的屏幕截图。如您所见,RecyclerView覆盖了appbar。

enter image description here

这是当TabLayout重新加入时问题的屏幕截图。在这里你可以看到RecyclerView在添加视图后向下移动到它的位置。

enter image description here

消失的TabLayout的布局过渡正在与LayoutTransition完成。要进行有效的过渡,LayoutTransition必须确定最终布局的样子,以便构建一组动画。这需要在过渡后布置屏幕的样子。似乎在动画运行之前短暂显示最终布局。 (我的猜测。)这可能是竞争条件,也可能与this caveat有关:

此类以及容器的关联XML标志animateLayoutChanges =“true”,提供了一个简单的实用程序,用于在简单情况下自动更改。由于各种布局级别的相互关系,在嵌套视图层次结构的多个级别使用LayoutTransition可能不起作用。此外,在添加或删除项目的同时滚动的容器可能不适合此实用程序,因为LayoutTransition计算的前/后位置可能与动画完成时的实际位置不匹配在动画运行时滚动容器。您可以通过将CHANGE_APPEARING和CHANGE_DISAPPEARING动画设置为null来禁用“更改”动画,并适当地设置其他动画的startDelay来解决该特定问题。

对能够弄清楚发生了什么的人的称赞和声誉。 (这个问题可能是LayoutTransition代码中以下神秘评论中提到的工件:)

/**
 * Controls whether changing animations automatically animate the parent hierarchy as well.
 * This behavior prevents artifacts when wrap_content layouts snap to the end state as the
 * transition begins, causing visual glitches and clipping.
 * Default value is true.
 */
private boolean mAnimateParentHierarchy = true;

怎么解决?

我建议你完全抛弃LayoutTransitionsandroid:animateLayoutChanges="false")并继续使用TransitionManager

我们将使用方便的方法TransitionManager#beginDelayedTransition

beginDelayedTransition

void beginDelayedTransition(ViewGroup sceneRoot,Transition transition)

在调用此方法和下一个渲染帧之间,为给定场景根中的所有更改定义的新场景设置动画的便捷方法。调用此方法会导致TransitionManager捕获场景根中的当前值,然后发布请求以在下一帧上运行转换。此时,将捕获场景根中的新值,并且将更改动画的更改。无需创建场景;它是由调用此方法与转换开始时的下一帧之间发生的更改所暗示的。

这是我删除和添加选项卡的代码。确保设置animateLayoutChanges="false"

fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (mTabsAdded) {
            // Get rid of the indicator due to an on-screen artifact.
            tabs.setSelectedTabIndicatorHeight(0);
            TransitionSet set = new TransitionSet()
                .addTransition(new Fade(OUT))
                .addTransition(new ChangeBounds());
            TransitionManager.beginDelayedTransition(layout, set);
            mAppBar.removeView(tabs);
        } else {
            // Add tab indicator back in.
            int indicatorHeight = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, 2,
                getResources().getDisplayMetrics());
            tabs.setSelectedTabIndicatorHeight(indicatorHeight);
            TransitionSet set = new TransitionSet()
                .addTransition(new Fade(IN))
                .addTransition(new ChangeBounds());
            TransitionManager.beginDelayedTransition(layout, set);
            mAppBar.addView(tabs);
        }
        mTabsAdded = !mTabsAdded;
    }
});

enter image description here


5
投票

从视频看,根据TabLayout看起来有三个片段加载。 MyPhotosFragmentMyAlbumsFragmentMyFavouritesFragment

如果我理解正确,你将TabLayout放在活动中,这三个片段直接加载到活动中。当抽屉上选择“隐藏相册”时,会显示/添加appbar,并在选择其他项目时隐藏/删除它。

你应该做的是制作一个充当容器的新片段。我们称之为HiddenAlbumsFragment。然后你应该从活动中删除TabLayoutViewPager并将其放在HiddenAlbumsFragment内。单击选项卡项时,HiddenAlbumsFragment应将相应的片段加载为子片段。然后,当您从抽屉中选择一个时,将HiddenAlbumsFragment替换为另一个,则tablayout将自动消失。


0
投票

你可以用这样的动画隐藏标签布局。

tabLayout.animate().scaleY(0).setInterpolator(new AccelerateInterpolator()).start();

我还没有测试过。如果您对此有任何疑问,请发表评论。可能这应该工作。

© www.soinside.com 2019 - 2024. All rights reserved.