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.
Related
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
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.
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!
I have following layout:
What I would like to achieve is to scroll out the ViewPager out of the screen when you scroll in any of the listviews at the half bottom of the screen. As the ViewPager would be getting out of the screen the ListViews should take up more and more screen. Toolbar should stay pinned.
I was having look at the Support Design Library.
In my case from the examples the most interesting piece of code was this:
<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">
<! -- Your Scrollable View -->
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
...
app:layout_scrollFlags="scroll|enterAlways">
<android.support.design.widget.TabLayout
...
app:layout_scrollFlags="scroll|enterAlways">
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Do I need to change my ListViews to RecyclerViews in order to achieve scrolling out the ViewPager from the screen - while the ListViews would increase their height as the ViewPager would getting out of the screen? Is that even possible with the Coordinator Layout?
My activity contains 2 Toolbars at the top of screen, and I'm using a CoordinatorLayout to make the top one exit/enter the screen on scroll of a RecyclerView, and the other Toolbar will always follow it but not exiting the screen.
Another layout containing the RecyclerView forementioned is added into a FrameLayout container dynamically. The layout is from another package so I must add app:layout_behavior="#string/appbar_scrolling_view_behavior" to the FrameLayout container to work with the CoordinatorLayout. And it works fine with no problem.
However, when I added another layout to the FrameLayout(a centered ProgressBar for example) instead of the RecyclerView , the bug showed. The FrameLayout, which match_parent, did not fill the screen, and its height was the same as ProgressBar.
After I deleted the line app:layout_behavior..., the FrameLayout succeeded to fill the screen. But at runtime when i want to add a RecyclerView, part of its 1st item is blocked by the Toolbar, because of the lack of app:layout_behavior... attribute.
In a word, if I add a app:layout_behavior.. attribute to the FrameLayout which match_parent, the RecyclerView in it shows correctly but the FrameLayout only wrap_content in height; if not, it match_parent while the RecyclerView is blocked by the 2nd Toolbar.
Note that I can't add this attribute to RecyclerView directly, which is in another package.(but i can get the reference of it at runtime)
Below is the 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.support.v7.widget.Toolbar
android:id="#+id/mainToolbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
style="#style/Toolbar"
app:theme="#style/Toolbar" />
<android.support.v7.widget.Toolbar
android:id="#+id/subToolbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="#style/Toolbar" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
UPDATE: I have solved the problem by adding an invisible new View(this) object , which fills the screen by default, to the FrameLayout at runtime before the ProgressBar is added. But I still don't know why the bug occurs. And I think this solution is a hack.