Why does my RecyclerView not scroll when placed inside an AppBarLayout? - android

I have an AppBarLayout in my app along with a FrameLayout that I use as a placeholder to load in fragments:
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay"/>
<FrameLayout android:id="#+id/main_content_fragment"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="#color/white" />
</android.support.design.widget.AppBarLayout>
The fragment in question looks like this:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar android:id="#+id/loading_downloaded"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id = "#+id/items_downloaded"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layout_constraintEnd_toEndOf="parent"
/>
</LinearLayout>
The Fragment is substituted in from code as you might anticipate:
val fragMan: FragmentManager = getSupportFragmentManager()
fragMan.beginTransaction().add(R.id.main_content_fragment, fragment).commit()
The problem is that I cannot scroll my RecyclerView when I format it this way. If I move the FrameLayout outside of the AppBarLayout it works perfectly but then the fragment lies behind the app bar, which is very untidy. This confirms for me that the fragment is working correctly, I just can't figure out why the fragment's scroll behaviour changes when it's within the AppBarLayout.
What do I need to do to be able to scroll my content? Or have I misunderstood and I need to display my fragments outside the AppBarLayout where they scroll correctly and shift everything down by the height of the app bar?

Your fragment's content is meant to be placed as a sibling of the AppBarLayout. You should wrap everything inside a CoordinatorLayout and set this attribute in your FrameLayout where your fragment resides: app:layout_behavior="#string/appbar_scrolling_view_behavior".
Here's your XML structure would be:
<CoordinatorLayout>
<FrameLayout
app:layout_behavior="#string/appbar_scrolling_view_behavior" ... >
...
</FrameLayout>
<AppBarLayout> ... </AppBarLayout>
</CoordinatorLayout>
Having this setup would allow your fragment to show all of it's views with your AppBarLayout. CoordinatorLayout will take care of everything for you.
Here's the official documentation:
AppBarLayout also requires a separate scrolling sibling in order to
know when to scroll. The binding is done through the
AppBarLayout.ScrollingViewBehavior behavior class, meaning that you
should set your scrolling view's behavior to be an instance of
AppBarLayout.ScrollingViewBehavior. A string resource containing the
full class name is available.
See this link for more details: https://developer.android.com/reference/android/support/design/widget/AppBarLayout.html

Related

CoordinatorLayout content child overlaps BottomNavigationView

I'm trying to use a CoordinatorLayout with a BottomNavigationView, an AppBarLayout, and a ViewPager. Here is my layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="#style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:menu="#menu/navigation"/>
</android.support.design.widget.CoordinatorLayout>
The problem is that the CoordinatorLayout places the ViewPager to extend to the bottom of the screen, so the bottom is obscured by the BottomNavigationView, like this:
This happens even though the CoordinatorLayout itself doesn't extend down so far:
I've tried adding app:layout_insetEdge="bottom" to the BottomNavigationView and app:layout_dodgeInsetEdges="bottom" to the ViewPager, but that has a different problem: it shifts the bottom of the ViewPager up, but it keeps the same height, so the top is now chopped off:
I tried two other experiments. First, I tried removing the BottomNavigationView from the CoordinatorLayout and making them siblings under a vertical LinearLayout. Second, I put the ViewPager and BottomNavigationView together under a LinearLayout, hoping they would layout out correctly. Neither helped: in the first case, the CoordinatorLayout still sized the ViewPager with respect to the entire screen, either hiding part of it behind the BottomNavigationView or chopping off the top. In the second case, the user needs to scroll to see the BottomNavigationView.
How do I get the layout right?
P.S. When I tried the layout suggested by #Anoop S S (putting the CoordinatorLayout and the BottomNavigationView as siblings under a RelativeLayout), I get the following (with the ViewPager still extending down behind the BottomNavigationView):
As before, the CoordinatorView itself only extends down to the top of the BottomNavigationView.
I came up with a different approach (not battle tested yet though):
I subclassed AppBarLayout.ScrollingViewBehavior to adjust the bottom margin of the content view based on the height of the BottomNavigationView (if present). This way it should be future proof (hopefully) if the height of the BottomNavigationView changes for any reason.
The subclass (Kotlin):
class ScrollingViewWithBottomNavigationBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.ScrollingViewBehavior(context, attrs) {
// We add a bottom margin to avoid the bottom navigation bar
private var bottomMargin = 0
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
return super.layoutDependsOn(parent, child, dependency) || dependency is BottomNavigationView
}
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
val result = super.onDependentViewChanged(parent, child, dependency)
if(dependency is BottomNavigationView && dependency.height != bottomMargin) {
bottomMargin = dependency.height
val layout = child.layoutParams as CoordinatorLayout.LayoutParams
layout.bottomMargin = bottomMargin
child.requestLayout()
return true
} else {
return result
}
}
}
And then in the layout XML you put:
app:layout_behavior=".ScrollingViewWithBottomNavigationBehavior"
instead of
app:layout_behavior="#string/appbar_scrolling_view_behavior"
Basically what you have to do is create a Relativelayout as parent and put BottomNavigationView and CoordinatorLayout as children. Then align BottomNavigationView at the bottom and set CoordinatorLayout above that. Please try the below code. It might have few attribute erros, because I wrote it here itself. And sorry for the messed up indentation.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/navigation"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="#style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:menu="#menu/navigation"/>
</RelativeLayout>
This is caused by app:layout_behavior="#string/appbar_scrolling_view_behavior" in your ViewPager. If you remove this line, you will see now it fits the CoordinatorLayout container (unfortunately, this includes now being underneath the Toolbar).
I found it helped to treat CoordinatorLayout as just a FrameLayout, with a few extra tricks. The app:layout_behavior attribute above is necessary to allow the toolbar to appear to scroll in and out... in reality, the layout is doing this by having the view linked to the collapsing toolbar (in your case, your ViewPager) be exactly a toolbar's height larger than the bounds. Scrolling up brings the view up to the bottom within the bounds, and pushes the toolbar up extending beyond the bounds. Scrolling down, vice versa.
Now, onto the BottomNavigationView! If, as I did, you want the BottomNavigationView visible the whole time, then move it outside the CoordinatorLayout, as Anoop said. Use CoordinatorLayout only for things that need to coordinate, everything else outside. I happened to use a ConstraintLayout for my parent view (you could use RelativeLayout or whatever works for you though). With ConstraintLayout, for you it would look like this:
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.CoordinatorLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#id/navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="enterAlways|scroll"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
app:itemIconTint="?colorPrimaryDark"
app:itemTextColor="?colorPrimaryDark"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/navigation" />
</android.support.constraint.ConstraintLayout>
In Android Studio design view, you're still going to see the ViewPager appear to be larger than the container (probably looks like it's behind the Bottom Nav still). But that's ok, when you get to the bottom of the ViewPager's content, it will show (i.e. won't be behind the bottom navigation). This quirk in the design view is just the way the CoordinatorLayout makes the toolbar show/hide, as mentioned earlier.
I had a similar problem with a layout very close to OP's and a ViewPager with 3 pages but only page 2 and 3 which should be affected by appbar_scrolling_view_behavior.
After struggling for hours exploring dead-end possible solutions (layout_dodgeInsetEdges, Window insets, attempting to modify ViewPager's page measured size, android:clipChildren, fitSystemWindows, ...), I finally found an easy solution detailed below.
As Vin Norman explained, ViewPager overlapping BottomNavigation is entirely caused by appbar_scrolling_view_behavior set on the ViewPager. AppBarLayout will just make fullscreen the sibling that has appbar_scrolling_view_behavior. That's how it works.
If you only need this behavior on certain ViewPager pages, there is a simple fix than you can apply on the ViewPager's OnPageChangeListener to dynamically change the Behavior and add/remove required padding:
public class MyOnPageChangeListener extends ViewPager.SimpleOnPageChangeListener {
#Override
public void onPageSelected(int position) {
...
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) _viewPager.getLayoutParams();
if(position == 0) {
params.setBehavior(null);
params.setMargins(params.leftMargin, _appBarLayoutViewPagerMarginTopPx,
params.rightMargin, _appBarLayoutViewPagerMarginBottomPx);
} else {
params.setBehavior(_appBarLayoutViewPagerBehavior);
params.setMargins(params.leftMargin, 0, params.rightMargin, 0);
}
_viewPager.requestLayout();
}
}
For page at position 0 (the one we want the ViewPager to extend exactly below the Toolbar and above the BottomNavigationView), it removes the behavior and adds top and bottom padding, respectively _appBarLayoutViewPagerMarginTopPx and _appBarLayoutViewPagerMarginBottomPx that are constants easy to compute beforehand (respectively the value in pixel for R.attr.actionbarSize and the height for the NavigationBottomView. Usually both are 56dp)
For all other pages needing appbar_scrolling_view_behavior we restore the associated scrolling behavior (stored beforehand in _appBarLayoutViewPagerBehavior) and remove top and bottom padding.
I tested this solution and it works fine without caveat.
In case anyone is still searching for a solution of this problem:
Cause of the problem is that CoordinatorLayout is not calculating correctly size of AppBarLayout because it has Toolbar with app:layout_scrollFlags="enterAlways|scroll" setting. It thinks that Toolbar will hide when scrolling so it leaves all available space to ViewPager, but actually what happens is that toolbar shows so ViewPager moves down, behind NavigationBar.
Easiest way to solve this is just to add android:minHeight="?attr/actionBarSize" (or whatever toolbar height you are using) to AppBarLayout. This way CoordinatorLayout will know properly how much space it needs to leave for ViewPager.
If it still matters to someone:
In the answer of Anoop SS above, trying replacing the RelativeLayout with LinearLayout. Also set layout_height of CoordinatorLayout to 0dp and set layout_weight to 1.
I had almost the same problem....just that i wanted to have a static AdView at the bottom instead of the BottomNavigationView. Trying Anoop SS suggestions, at first, I got the same behaviour as OP: ViewPager extended behind the AdView. But then I did what I suggested about and everything worked fine.
Android layouts behave in weird manner or may be it is the lack of good documentation or the lack of knowledge on our part....but making a layout is just too annoying most of the time.
If you are using Androidx try this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:layout_above="#+id/bottomNavView">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/mobile_navigation" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?android:attr/windowBackground"
app:menu="#menu/bottom_nav" />

How to fix footer properly which is inside CoordinatorLayout

I tend to further elaborate from this
Android - footer scrolls off screen when used in CoordinatorLayout
and
https://code.google.com/p/android/issues/detail?id=177195
I wish to hide TabLayout while performing scrolling on RecyclerView. That's why I have the following layout.
<CoordinatorLayout>
<CollapsingToolbarLayout>
<TabLayout>
<ViewPager>
<RecyclerView>
<Footer>
For my situation, I have a ViewPager which contains multiple fragments.
Most of the fragments, contains RecyclerView and footer. They look like the following
<LinearLayout>
<RecyclerView />
<LinearLayout id="#+id/footer" />
</LinearLayout>
Unfortunately, the footer is movable when scrolling, although I would like it to be static.
Note, it is important to have app:layout_behavior to place in ViewPager instead of RecyclerView. If not, TabLayout will not appear.
My implementation is as follow
my_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<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_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" >
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways|snap">
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="?attr/portfolioTabIndicatorColor" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="org.yccheok.xxx.CustomScrollingViewBehavior"
/>
</android.support.design.widget.CoordinatorLayout>
The very key class is org.yccheok.xxx.CustomScrollingViewBehavior, which is copied and pasted from https://stackoverflow.com/a/33396965/72437
org.yccheok.xxx.CustomScrollingViewBehavior is the best solution I can find so far. However, it is far from perfect, as it yields the following behavior.
It causes flickering, when you scroll up a little, and release your finger. Please refer to the following video.
https://youtu.be/8RvCZJeQvS0
I was wondering, based on proposed solution at https://stackoverflow.com/a/33396965/72437, is there any further improvement I can done on CustomScrollingViewBehavior class, to avoid flickering effect?
I was able to achieve what I want, by following tutorial at
https://mzgreen.github.io/2015/02/15/How-to-hideshow-Toolbar-when-list-is-scroling%28part1%29/
http://mzgreen.github.io/2015/02/28/How-to-hideshow-Toolbar-when-list-is-scrolling%28part2%29/
The key ideas are
Don't use CoordinatorLayout
Place TabLayout and RecyclerView within FrameLayout, so that TabLayout will overlay on the top of RecyclerView
Add top padding on RecyclerView. Having android:clipToPadding="false" is important as well.
To hide/ show TabLayout during scrolling, attach HidingScrollListener to RecyclerView.
The shortcoming for this solution is that, requiresFadingEdge will no longer work on RecyclerView, due to the top padding.

Scroll second child in AppBarLayout

I'm trying to obtain this effect where if the user scroll a RecyclerView a certain layout scroll up together with the recycler and disappear behind a Toolbar.
A similar behavior could be obtained using the CoordinatorLayout, this would be possible by setting
app:layout_behavior="#string/appbar_scrolling_view_behavior"
on the said Recycler, and doing
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
Also, If I put a second child inside the AppBarLayout, and set app:layout_scrollFlags to it, the effect obtained is the same, with both layout scrolling together with the Recycler.
What I'm trying to achieve is to keep the first child (The toolbar) fixed in position, and let the second child (a LinearLayout) to scroll and hide behind the toolbar. Unfortunately I couldn't get to this behavior.
Is it possible without using 3rd part library?
Thanks in advance and sorry for my english.
Finally I figured out a way to achieve this behavior, by including the CoordinatorLayout in an LinearLayout and making the second child(LinearLayout) become the first, by moving the Toolbar to the extrnal(root) level
Hierarchy before:
<CoordinatorLayout>
<AppBarLayout>
<ToolBar>
<LinerarLayout>
Hierarchy after:
<LinearLayout>
<ToolBar>
<CoordinatorLayout>
<AppBarLayout>
<LinearLayout>
An exmaple:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="48dp" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorSecondaryLight"
android:orientation="vertical"
app:layout_scrollFlags="scroll"/>
</com.google.android.material.appbar.AppBarLayout>
.
.
.
.
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
Hope that helps!

CoordinatorLayout overlapping

Have a look at the following layout. You will see, that the floating button is too far to the bottom. This is because the Toolbar and the Tabs are shown and the height of the ViewPager is wrong. So somehow I'm doing something wrong with the layout_height. But how can I fix that?
Remark: The ViewPager is the main content and it contains a fragment with a ListView and a Google Map V2 in the second tab.
That's the layout XML:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager_list_views"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="fill_parent">
</android.support.v4.view.ViewPager>
</android.support.design.widget.CoordinatorLayout>
Here's the layout for the fragment in the first tab (the list):
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/preview_list"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="singleChoice"
android:orientation="vertical" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/action_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:src="#mipmap/ic_add_white_48dp" />
</android.support.design.widget.CoordinatorLayout>
Just to make sure; it's not a problem with the FAB. See this picture. It's a similar layout. A CoordinatorLayout with a ToolBar and a ViewPager which swipes through all detail-entries (therefore no tabs are needed). And again, the inner view seems to be too long (the same height as the ToolBar).
You should use android.support.v7.widget.RecyclerView and not ListView
Although you are already using android.support.v7.widget.RecyclerView be 100% sure that you have declard compile 'com.android.support:recyclerview-v7:23.0.0' in your build.gradle dependencies. I encountered the same issue where the viewpager overlaps the system buttons. I fixed it by simply adding this dependency.
Anything you what to be "coordinate" need to be direct child of CoordinatorLayout, Including the AppBar, RecyclerView (ListView in API21+ or other view support nested scroll is OK), or FAB, etc.
The reason why your FAB is offset out of screen, is that:
ViewPager has a #string/appbar_scrolling_view_behavior, the implement of this behavior will offset view when you scroll.
you put FAB inside ViewPager.
So when the offset of ViewPager changed, anything inside ViewPager will offset together (extra CoordinatorLayout has no help to change offset).
To fix this, don't use CoordinatorLayout outside ViewPager.
Or:
Put your FAB out of ViewPager so it won't scroll with ViewPager.
If the FAB only work with some of your page, hide() it when need.
BTW, there is very good App, Cheesesquare Sample, to demo the design library.

Toggling visibility AppBarLayout views causes spacing issues for loaded Fragments

I encountered a strange problem with the new Android Design Support Librar (http://android-developers.blogspot.com.ar/2015/05/android-design-support-library.html). If I place additional content (like a LinearLayout) in an AppBarLayout along with the ToolBar and toggle the visibility of that content then switching fragments will have show a dead space at the top of the fragment content.
It appears that AppBarLayout isn't resizing the parent CoordinatorLayout correctly when visibility of the content is toggled. I have my CoordinatorLayout wrapped in the DrawerLayout. I want to toggle the visibility of the extra LinearLayout in the AppBarLayout depending on the which fragment shown.
Here is my main.xml file for the MainActivity:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.CoordinatorLayout
android:layout_height="match_parent"
android:layout_width="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical"">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:text="Hello"/>
</LinearLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/drawer"/>
</android.support.v4.widget.DrawerLayout>
I had a similar problem using the support design widget. I had a CoordinatorLayout inside a DrawerLayout and an AppBarLayout inside the CoordinatorLayout. I had two toolbars inside the AppBarLayout. My aim was to display a toolbar with a ViewPager displaying a recyclerview content. I wanted to swop between the toolbars when selecting items. In other words, I made one toolbar GONE while the other was visible and vise versa. Scrolling the content up would push the toolbar up off the top of the screen. Everything worked perfectly except that changing orientation would show a space for the toolbar that should be gone. I tried every hack I could think of to get rid of it but did not succeed. I then came across this post and realized that it was a bug in the support library. I then tried putting a FrameLayout in the AppBarLayout and then put the two toolbars inside the FrameLayout and NO MORE SPACE! everything now works as I intend it to work. GONE toolbars are GONE and only the visible toolbar shows, even when changing the orientation.
Hope this helps someone.

Categories

Resources