In my application I have an issue where I want to have high level navigational control from a navigation drawer, and page level control within a TabLayout within a fragment. This however causes issues with the shadow rendering from the AppBar onto the fragment.
Here's the basics of what my layouts and code does. At the root I have this simple 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=".MainAppActivity">
<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" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
When my navigation drawer is selected I inflate the fragment into "content_main"
this.getSupportFragmentManager()
.beginTransaction()
.addToBackStack(tag)
.replace(R.id.content_main_layout, fragment, tag)
.commit();
The fragment being put into content_main contains a layout with my TabView and a view pager:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_github_issues"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/github_issues_tab_layout"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:layout_gravity="top"
android:background="?attr/colorPrimary"
android:theme="#style/AppTheme.AppBarOverlay"/>
<android.support.v4.view.ViewPager
android:id="#+id/github_issues_viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
What's the a good best practice to fix the issue? Is including TabLayout to live within the top level AppBar and just disabling the view based on the page an acceptable implementation?
First you need to change the view hierarchy to something like this:
FrameLayout
-CoordinatorLayout -> content
-Toolbar
Fix Toolbar elevation to be exact with the AppBarLayout, too get rid of the shadow but keep the z-order of the Toolbar:
int appBarLayoutElevation = ViewCompat.getElevation(mAppBarLayout);
getActivity().getSupportActionBar().setElevation(appBarLayout);
Similar example I have worked in my blog post.
Related
I have a simple CoordinatorLayout with a AppBarLayout and FrameLayout, but the FrameLayout contents are being displayed over the AppBarLayout regardless of the layout_behavior attribute on the FrameLayout. I've tried adding that attribute elsewhere (like on my RecyclerView), but it's the same behavior.
Here's a picture to show what I mean.
Activitiy 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
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"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
Fragment Layout:
<android.support.v7.widget.RecyclerView
android:id="#+id/checkins_recycler_view"
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:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
How I add my fragment in my Activity:
final UserCheckinsFragment fragment = new UserCheckinsFragment();
final Bundle arguments = new Bundle();
UserCheckinsFragment.getArguments(arguments, items);
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction().add(android.R.id.content, fragment,
UserCheckinsFragment.class.getName()).commit();
The FrameLayout ID (#android:id/content) in the xml and the container (android.R.id.content) in the Fragment transaction refer to the system root of layout, then it is laid over the all screen.
To solve, use them without android prefix.
add app:layout_behavior="#string/appbar_scrolling_view_behavior" to the RecyclerView and it will work. The app:layout_behavior should be to the root of the layout's of your Fragment
https://stackoverflow.com/a/24713989/4409113
In AppCompat, there is no native support for ActionBar.
android.R.id.content is the container of entire app screen. This means
- including ActionBar, because ActionBar is emulated there and added as a standard view hierarchy.
You may want to use(In the Layout):
android:id="#+id/content"
And(in Java):
getSupportFragmentManager().beginTransaction().add(R.id.content, fragment,
UserCheckinsFragment.class.getName()).commit();
Then, it should work.
Hi i had the same problem and i fixed it by adding"app:layout_behavior="#string/appbar_scrolling_view_behavior"" into my layout parent which is linear layout and contain the RecylerView Layout and now it works correctly but i have an other problem that the button which is in the boutmn of the page disapear
Screenshot 1 and
Screenshot 2 of my app
The problem is basically this: The PagerTitleStrip and the RecyclerView go below my Toolbar even though I have set layout_behaviour to my ViewPager.
More detail:
I have a main activity that uses the layout below and then from it I launch fragments. Before trying the CoordinatorLayout + ViewPager and all of the other fancy stuff I just had a FrameLayout in which I displayed my fragments. However, I decided that I want to use
app:layout_scrollFlags="scroll|enterAlways"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
so that my Toolbar disappears when I scroll the recyclerview. I found online that FrameLayout had no behaviour in it to allow me to fix the position of the recyclerView going under the Toolbar and that's why I changed to ViewPager + CoordinatorLayout to manage my fragments.
However, that introduced a few problems. What I want to achieve is - A toolbar with a PagerTitleStrip attached to it, when I scroll the toolbar disappears leaving the PagerTitleStrip visible ideally, maybe it hides as well I don't care that much about that. But I want my Navigation Drawer to keep working and it doesn't. It's like it doesn't exist.
Now, this first layout actually has all of the above features working, but the problem is the strip is below the toolbar and it's not visible unless the Toolbar hides when I scroll. Drawer works. Recycler view items are partially hidden below the Toolbar unfortunately - they don't start scrolling from the right point of the screen even though I have that set - appbar_scrolling_view_behavior
Layout m_drawerlayout.xml for my main activity to inflate:
<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/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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.v4.view.PagerTitleStrip
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:layout_gravity="top"
android:textSize="15sp"
android:textColor="#color/tealfifty"
android:background="#color/teal">
</android.support.v4.view.PagerTitleStrip>
</android.support.v4.view.ViewPager>
<ListView
android:id="#+id/drawer_list"
android:background="#color/tealDark"
android:cacheColorHint="#android:color/transparent"
android:choiceMode="singleChoice"
android:divider="#drawable/list_divider"
android:dividerHeight="1dp"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="#layout/app_bar"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
And this is the code for my app_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/top_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/teal"
app:theme="#style/ToolbarTheme"
app:popupTheme="#style/Green.Overlay.LightPopup"
app:layout_scrollFlags="scroll|enterAlways" >
<Spinner android:id="#+id/spinner"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
android:paddingRight="20dp"
/>
</android.support.v7.widget.Toolbar>
I tried moving elements around, in and out of other components but no success. For example, it seems logical that to make the PagerTitleStrip attached to the Toolbar and share one behaviour I'd have to nest the PagerTitleStrip inside the AppBar layout but PagerTitleStrip has to be a direct child of ViewPager to work...Any suggestions guys about all this? I'm new to all these design functionalities and I researched a lot without success, there are similar topics here but not at all what I need. Seems there's almost nothing on the internet about things I'm trying to do above (there are a few) compared to other basic topics.
If anyone is wondering why I'm using ViewPager when I have no tabs, it's because as I said, FrameLayout has no behaviour allowing me to use a disappearing Toolbar correctly and that's what I found is good to use. I also saw NestedScrollView could be used but I haven't used it ever so... I now want to possibly use the ViewPagerTitle which I guess limits me to ViewPager for the Fragments.
The problem is in the:
<android.support.design.widget.CoordinatorLayout
<android.support.v4.widget.DrawerLayout
Which the DrawerLayout should be the root layout.
Please see: http://developer.android.com/training/implementing-navigation/nav-drawer.html#DrawerLayout
To add a navigation drawer, declare your user interface with a
DrawerLayout object as the root view of your layout. Inside the
DrawerLayout, add one view that contains the main content for the
screen (your primary layout when the drawer is hidden) and another
view that contains the contents of the navigation drawer.
Also, it is not recommended to use ListView instead of NavigationView.
And here is the doc suggested way to do(except that ListView:) ):
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
And also:
However, that introduced a few problems. What I want to achieve is - A
Toolbar with a PagerTitleStrip attached to it, when I scroll the
toolbar disappears leaving the PagerTitleStrip visible ideally, maybe
it hides as well I don't care that much about that. But I want my
Navigation Drawer to keep working and it doesn't.
Check my answer about this one:
https://stackoverflow.com/a/35241363/4409113
You just put your Toolbar inside CollapsingToolbarLayout like this:
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsingtoolbarly"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|snap">
<android.support.v7.widget.Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<ImageView
android:layout_width="match_parent"
android:layout_height="190dp"
android:minHeight="190dp"
android:scaleType="fitXY"
android:src="#drawable/header"
app:layout_collapseMode="parallax" />
</android.support.design.widget.CollapsingToolbarLayout>
It should collapsed and the Toolbar will be hided after that.And if you want to keep that PagerTitleStrip(Recommended to use TabLayout Nowadays), just put it below the CollapsingToolbarLayout and above the </android.support.design.widget.AppBarLayout> like this:
</android.support.design.widget.CollapsingToolbarLayout>
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="?attr/colorPrimary" />
</android.support.design.widget.AppBarLayout>
That's pretty much it, Goodluck then.
I was creating a settings activity/layout for my app. I have a CoordinatorLayout with an AppBarLayout and Toolbar, then beneath that it includes content_settings.xml. When the content loads the .xml file is behind the app bar.
I'm using this same setup to load the main content and it works fine, but for some reason isn't rendering correctly within the Settings section.
activity_settings.xml
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
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" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_setting" />
The content_settings.xml is just a FrameLayout that is replaced by a PreferenceFragment
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/settings_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
add this to your Recyclerview :
app:layout_behavior="#string/appbar_scrolling_view_behavior"
In my case the view under the toolbar wasn't scrollable so even though the accepted answer did stop the overlapping it pushed the content down by the height of the toolbar, pushing elements offscreen.
The solution in this case was to also remove the
app:layout_scrollFlags
from the Toolbar that I was including/sharing with other layouts that had scrolling views.
I'm using a single activity - multiple fragments structure.On the activity i'm using v7 toolbar as action bar . I have sever fragments with viewpagers , some with tabs as well.In one of my fragments i have recyclerview . My goal is when i'm scrolling i wanna collapse the bar and hide the floating action button.My floating button is on inside a CoordinatorLayout so it can be displayed properly.But this is inside the layout of the fragment(which is part of a viewpager) , and the activity_main.xml has root element another CoordinatorLayout. Does the fragment CL intercepts the work of the CL inside the layout of the activity,because when i scroll the recycler nothing happens.
Should i use new toolbar for every fragment or i can use one in the
activity and implement different behavior for into fragments?
Can anyone references any examples of using CoordinatorLayout and
collapsing the bar within nested fragments?
activity_main.xml
<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:gravity="center"
android:orientation="vertical">
<android.support.design.widget.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"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />
</android.support.design.widget.CoordinatorLayout>
The work of the main CoordinatorLayout wasn't intercepted.Adding app:layout_behavior to the frame layout which is fragment container did the job.
Looks like this now:
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".MainActivity" />
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.