SwipeRefreshLayout in AppBarLayout not wrapping content - android

I am trying to implement pull to refresh but I'm having an issue with SwipeRefreshLayout not wrapping the child view's height. In the view preview and in a live build it appears to have 0 height.
The layout as as follows:
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
app:layout_collapseMode="pin">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="#layout/child_layout" />
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
I have also tried making the SwipeRefreshLayout the parent of the AppBarLayout without any success as well as putting a singular LinearLayout inside of the SwipeRefreshLayout. The only thing that seems to prevent the height of the swipe layout from being 0 is to set it statically but I want it to be dynamic based upon the height of the child view.
Is there something I'm missing here? It seems like there may be a bug with SwipeRefreshLayout because replacing it with a LinearLayout that also wraps the content works as expected.

The problem is your SwipeRefreshLayout is inside the Toolbar and AppBarLayout. You must wrap AppBarLayout with another layout and put SwipeRefreshLayout below the AppBarLayout. An example is at the below.
<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"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
tools:context="com.vsahin.moneycim.View.MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="250dp"
android:theme="#style/ThemeOverlay.AppCompat.Dark"
android:fitsSystemWindows="true"
app:expanded="false">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:background="#drawable/gradient_background">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>

if your SwipeRefreshLayout height is wrapping the content of your child_layout, then your child_layoutheight should be set to match_parent OR both SwipeRefreshLayout and child_layout height should be set to match_parent as shown in the Android Documentation
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--Child View-->
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>

SwipeRefreshLayout is a transparent View, so best solution to set it match_parent it will not conflict with other Views and don't include View or Layout within it, keep it clean
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
app:layout_collapseMode="pin">
<include layout="#layout/child_layout" />
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
SwipeRefreshLayout has to be in top to overlay other layers and be clickable

Related

How to achieve overlapping in CoordinatorLayout?

I have used CoordinatorLayout for getting Appbar + RecyclerView scroll behavior. But I'm not able to achieve overlapping of Appbar over the RecyclerView within this CoordinatorLayout. I have tried using negative margins which works but I don't know if that is a good practice. Is there any other way to achieve this?
The following code is the original xml without negative margins:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<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="?attr/actionBarSize"
app:elevation="0dp"
android:clipToPadding="false"
android:background="#color/transparent"
app:theme="#style/ThemeOverlay.AppCompat.ActionBar">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="match_parent"
...
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
[Edit] I tried encapsulating Appbar + RecyclerView within RelativeLayout before putting them in CoordinatorLayout (see Overlapping views in coordinatorlayout) but that just breaks the "hide appbar on scroll" behavior.
Here is I am using this Like this
XML:
<android.support.design.widget.CoordinatorLayout
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:layout_width="match_parent"
android:titleTextColor="#color/white"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways|snap"
android:background="?attr/colorPrimary"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
android:id="#+id/toolbar">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_height="match_parent"
>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recycle"
android:layout_marginTop="5dp"
android:layout_gravity="center_horizontal|top" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
You are using layout_scrollFlags according to your requirements.
Please have to look this URL

Android CoordinatorLayout Behaviour with complex layout

I have a simple layout that is a CoordinatorLayout containing a Toolbar in an AppBarLayout and a RecyclerView. To allow for a progress bar while content is loaded into the RecyclerView I've wrapped it in a FrameLayout alongside a ProgressBar which I've included from another file. When the content is loading the ProgressBar is set to VISIBLE and when it's finished it's set to GONE, showing the RecyclerView. I'd like to use a ScrollingViewBehavior so that when I scroll my RecyclerView the Toolbar is hidden. I've tried adding it to the FrameLayout and the RecyclerView and neither seems to work.
What do I have to do to get the behavior I am looking for? Do I need to make a new ViewGroup or something like that in order to show/hide the ProgressBar and define a new Behavior for that, or is there something simpler?
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ToolbarTheme"
android:background="?attr/colorPrimary"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:id="#+id/recycler_view" />
<include layout="#layout/progress_circle" />
</FrameLayout>
<include layout="#layout/floating_action_button"/>
</android.support.design.widget.CoordinatorLayout>
I have almost the same setup you do, but I've included two progress bars. One appears when the activity is loaded, and covers the whole thing. The second one appears on a swipe refresh and only replaces the RecyclerView (well, actually the RecyclerView's parent SwipeRefreshLayout).
<RelativeLayout
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:focusableInTouchMode="true">
<include layout="#layout/loading_progress"/>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator_layout"
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="false">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="#dimen/app_bar_height"
android:fitsSystemWindows="false"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_landing_page"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_collapseMode="pin"
app:popupTheme="#style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<include layout="#layout/loading_progress"/>
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/landing_page_top_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
And my progress bar is just:
<ProgressBar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/loading_progress"
style="#android:style/Widget.ProgressBar.Inverse"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
When it's time to show the progress bar I set it to View.VISIBLE and the SwipeRefreshLayout (or the CoordinatorLayout for when the Activity is loaded) to View.GONE. Then reverse the VISIBLE and GONE when the data is loaded.

Content inside toolbar not collapsing/scrolling if content height higher than display

If i have such a configuration as shown below, like a custom View inside a CollapsingToolbarLayout with height more than a screen height, i cannot collapse it.
What for i need to do it? I need to have a content which will scroll up with a recyclerview below it. Without parallax or other effect, just scroll.
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/refresher"
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:background="#color/accent_material_light"
android:isScrollContainer="false">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:fitsSystemWindows="true"
app:layout_collapseMode="pin"/>
<View android:layout_width="match_parent"
android:layout_height="1500dp"
android:background="#color/green_A100"
app:layout_scrollFlags="scroll"
/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/cardview_light_background"
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.SwipeRefreshLayout>
Per the Support Library 23.1 release blog post:
You’ll also find that AppBarLayout now allows users to start scrolling from within the AppBarLayout rather than only from within your scrollable view
If you'd like to start scrolling from within your AppBarLayout/CollapsingToolbarLayout, you'll want to update to at least version 23.1.0 of the Design Library.

How can I provide auto-hide/show toolbar, when scroll my recyclerview with coordinator layout?

This is my layout file
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.moskart.mosfake.activity.MainActivity">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="?attr/actionBarSize"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
local:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
local:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin"
/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
>
<FrameLayout
android:id="#+id/fragment_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="#drawable/toolbar_dropshadow" />
</FrameLayout>
</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:headerLayout="#layout/navigation_drawer_header"
app:itemIconTint="#color/navItemIconTintColor"
app:itemTextColor="#color/navItemTextColor"
app:menu="#menu/menu_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
I set app:layout_scrollFlags for my CollapsingToolbarLayout to scroll|enterAlways and expected that toolbar will work like in gapps (e.g. Google Play or Google Magazine) with auto-hide/show like on this sample:
Google Magazine
But I only got scrolling toolbar that does not retract automatically, but only if user completely scrolled it himself. See sample: my app
Here is my fragment with recyclerview, which I replace with fragment_placeholder
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.moskart.mosfake.fragment.CategorySelectionFragment"
>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/card_horizontal_margin"
android:paddingRight="#dimen/card_horizontal_margin"
/>
</LinearLayout>
Thanks for advice!
You should measure if the bottom and top offset of the AppBarLayout is offset for more than the half the the height of the AppBarLayout and user has released the scroll. When this condition is fulfilled just start animating the translationY of the Toolbar or the offsetting of the AppBarLayout.
This could be achieved with custom CoordinatorLayout.Behavor or with inheriting existing AppBarLayout.Behaviour and tweaking it to do so.
i think you want to do like this
take a look of this library
https://github.com/ksoichiro/Android-ObservableScrollView
here is the example about how to implement it
https://snow.dog/blog/material-design-flexible-space-header-with-image/
You need to use NestedScrollView
<android.support.v4.widget.NestedScrollView ...>
<LinearLayout ...>
//Your Code Here
</LinearLayout>
Check this Example

CoordinatorLayout with Toolbar and fragment

I'm using the layout below, The CoordinatorLayout holds inside it AppBarLayout (With Toolbar and TabLayout inside it) and a placeholder RelativeLayout, so I could add and replace fragments on it.
I'm experiencing margin errors, the fragments I add on the RelativeLayout will always over expand beyond the bottom of the screen (in the amount similar to the size of the AppBarLayout height), I've tried setting it's height to wrap_content and match_parent, in both cases it goes overboard.
if I remove the app:layout_behavior="#string/appbar_scrolling_view_behavior" from the RelativeLayout the top of it will be under the AppBarLayout which is also not the desired outcome.
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="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/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
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:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
app:tabIndicatorHeight="4dp"
app:tabIndicatorColor="#ffffff"
app:tabMode="scrollable"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<RelativeLayout
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:id="#+id/main_fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="20dp"
android:src="#drawable/ic_done" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/drawer_view"/>
</android.support.v4.widget.DrawerLayout>
I have figured out the problem on showing fragment below toolbar when using the coordinator layout. The problem in my case is:
In this image it shows the Fragment is overlapped by Toolbar.
Now just put your AppBarLayout and FrameLayout inside LinearLayout like below,
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="#+id/mainappbar"
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:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Now your problem is solved. And it will be like this.
The final image.
You will also see this issue if you have a ScrollView inside the fragment. So make sure you use a NestedScrollView instead:
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
Had the same issue. Changing RelativeLayout to FrameLayout with parameter app:layout_behavior="#string/appbar_scrolling_view_behavior" solved my problem.
<FrameLayout
android:id="#+id/main_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
The issue has been solved by updating the recyclerview library (to com.android.support:recyclerview-v7:22.2.0)
The fragment I was loading had a recyclerview in it.

Categories

Resources