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

时间:2018-04-26 17:35:59

标签: android android-tablayout android-appbarlayout

当在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>

3 个答案:

答案 0 :(得分:5)

从视频中看,好像有三个片段根据TabLayout加载。 MyPhotosFragmentMyAlbumsFragmentMyFavouritesFragment

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

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

答案 1 :(得分:1)

那是怎么回事?

一切似乎都可以正常进行,除了您提到的那个闪光灯。我使用了Chris Banes的 Cheese Square 应用程序,并进行了一些修改以复制您所看到的内容。单击FAB会删除并添加选项卡。

这是我想出的视频。

enter image description here

这是移除TabLayout时问题的屏幕截图。如您所见,RecyclerView覆盖了应用栏。

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,                   过渡过渡)

     

便捷方法,以动画化一个新场景,该场景由在调用此方法和下一个渲染帧之间的给定场景根内的所有更改定义。调用此方法将使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

答案 2 :(得分:0)

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

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

还没有在我这边进行测试。如果对此有任何问题,请发表评论。 可能应该可以。