Glitch when removing TabLayout from AppBarLayout with removeView()

Glitch when removing TabLayout from AppBarLayout with removeView()



When a item is clicked in recyclerview i call this



appbar.removeView(tabs)


appbar.removeView(tabs)



This video shows what happens



It seems to remove the TabLayout entirely without animation, then add it back, then use animation to remove it. I have slowed down the transition to show what its doing.



it also happens when adding them back like this


if (tabs.parent != null)
(tabs.parent as ViewGroup).removeView(tabs)

appbar.addView(tabs)
appbar.setExpanded(true, true)



Here is my layout


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





Do you really want remove TabLaoyout on item click or are you trying to hide it on scrolling?
– Anees
Aug 25 at 15:21





May I ask whether you've tried just setting the visibility of the view instead of removing it, and if that would be an adequate solution.
– DrSatan1
Aug 25 at 15:51






I need to remove it because Im using fragment manager to add a new fragment that doesn't require the tabs.
– Bignadad
Aug 25 at 15:53





Try (tabs.parent as ViewGroup).post( (tabs.parent as ViewGroup).removeView(tabs) )
– Patryk Jabłoński
Aug 31 at 7:01



(tabs.parent as ViewGroup).post( (tabs.parent as ViewGroup).removeView(tabs) )




3 Answers
3



So what is going on?



Everything seems to work OK except there is that flash you mention. I took Chris Banes' Cheese Square app and made a few modifications to duplicate what you are seeing. Clicking the FAB removes and adds the tabs.



Here is a video of what I came up with.



enter image description here



Here is a screen capture of the problem when the TabLayout is removed. As you can see, the RecyclerView is overlaying the appbar.


TabLayout


RecyclerView



enter image description here



Here is a screen capture of the problem when the TabLayout is added back in. Here you can see that RecyclerView is shifted down to its position after the view is added.


TabLayout


RecyclerView



enter image description here



The layout transition of the disappearing TabLayout is being done with LayoutTransition. To do an effective transition, LayoutTransition must determine what the final layout looks like so a set of animations can be built. This necessitates laying out what the screen will look like after the transition. It appears that the final layout is being displayed briefly before the animations run. (My guess.) This could be a race condition or it could be related to this caveat:


TabLayout


LayoutTransition


LayoutTransition



This class, and the associated XML flag for containers, animateLayoutChanges="true", provides a simple utility meant for automating changes in straightforward situations. Using LayoutTransition at multiple levels of a nested view hierarchy may not work due to the interrelationship of the various levels of layout. Also, a container that is being scrolled at the same time as items are being added or removed is probably not a good candidate for this utility, because the before/after locations calculated by LayoutTransition may not match the actual locations when the animations finish due to the container being scrolled as the animations are running. You can work around that particular issue by disabling the 'changing' animations by setting the CHANGE_APPEARING and CHANGE_DISAPPEARING animations to null, and setting the startDelay of the other animations appropriately.



Kudos and reputation to someone who can figure out exactly what is going on. (This issue may be the artifacts mentioned in the following cryptic comment in the code for LayoutTransition:)


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;



How to fix it?



I suggest that you abandon LayoutTransitions altogether (android:animateLayoutChanges="false") and proceed with TransitionManager.


LayoutTransitions


android:animateLayoutChanges="false"


TransitionManager



We'll make use of the convenience method TransitionManager#beginDelayedTransition:


TransitionManager#beginDelayedTransition



beginDelayedTransition



void beginDelayedTransition (ViewGroup sceneRoot,
Transition transition)



Convenience method to animate to a new scene defined by all changes within the given scene root between calling this method and the next rendering frame. Calling this method causes TransitionManager to capture current values in the scene root and then post a request to run a transition on the next frame. At that time, the new values in the scene root will be captured and changes will be animated. There is no need to create a Scene; it is implied by changes which take place between calling this method and the next frame when the transition begins.



Here is my code for removing and adding the tabs. Make sure to set animateLayoutChanges="false".


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





This does work but i took a different way to achieve it. I kept the animate layout changes, i just timed everything to make it happen. i faded out the fragment content, then removed the tabs. then reversed it when coming back. works beautifully this way
– Bignadad
Sep 1 at 18:37





@Bignadad Many ways to do the transition. I wanted to duplicate the transition.s that LayoutTransition was attempting as closely as possible.
– Cheticamp
Sep 1 at 19:06


LayoutTransition



From the Video, it looks like there are three fragments which loads according to the TabLayout.
MyPhotosFragment, MyAlbumsFragment and the MyFavouritesFragment.


TabLayout


MyPhotosFragment


MyAlbumsFragment


MyFavouritesFragment



If I understand correctly, you are placed the TabLayout inside the activity and these three fragments loads directly into the activity. When “Hidden albums” is selected on the drawer, the appbar is shown/added and it is hidden/removed when another item is selected.


TabLayout



What you should do is to make a new fragment which act as a container. Let’s call it HiddenAlbumsFragment. Then you should remove the TabLayout and the ViewPager from the activity and place it inside the HiddenAlbumsFragment. When a tab item is clicked the HiddenAlbumsFragment should load corresponding fragment as subfragment.
Then when you replace HiddenAlbumsFragment from another by selecting one from the drawer, the tablayout will be automatically gone.


HiddenAlbumsFragment


TabLayout


ViewPager


HiddenAlbumsFragment


HiddenAlbumsFragment



you can hide the tab layout with animation like this.


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



haven't tested yet on my side. Please comment if you have any issue on this.
Probably this should work.



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Some of your past answers have not been well-received, and you're in danger of being blocked from answering.



Please pay close attention to the following guidance:



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)