I got CoordinatorLayout with structure similar to this:
<CoordinatorLayout>
<AppBarLayout>
<CollapsingToolbarLayout
app:layout_scrollFlags="scroll|snap">
...
</CollapsingToolbarLayout>
... almost all elements here have scroll|enterAlways|snap scrollflags
<TabLayout />
</AppBarLayout
<ViewPager />
</CoordinatorLayout>
ViewPager has 2 fragments, first one has just 2 simple TextViews nested in NestedScrollView -> LinearLayout and works perfectly fine.
One of this whole coordinatorLayout feature is collapsible toolbar and a bit more content inside it when scrolling down.
Second one is fragment with google map view inside and behaves weird.
Scenario 1. - Maps fragment has just MapView inside it - Map is full size, however when scrolling down toolbar no longer collapses, instead you scroll inside the map, which is I guess expected, I'm just not sure how to write custom MapView to go around it.
Scenario 2 - MapView is inside LinearLayout which is inside NestedScrollView - Toolbar now collapses when scrolling down, however for some reason it gets really small
Every element inside that map fragment has match parent sizes.
Full Map fragment:
<android.support.v4.widget.NestedScrollView
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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.gms.maps.MapView
android:id="#+id/details_map_view"
android:layout_height="match_parent"
android:layout_width="match_parent" />
</LinearLayout>
ViewPager inside CoordinatorLayout has match_parent sizes as well:
<android.support.v4.view.ViewPager
android:id="#+id/details.viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
Use android:fillViewport="true" on NestedScrollView because it defines whether the NestedScrollView should stretch its content to fill the viewport
Related
I am developing an app that uses a vertical bottom sheet. To be more specific, it is a LinearLayout with bottomSheetBehavior. This bottom sheet comprises two elements: a view pager that displays images and can be scrolled horizontally, and, below the view pager, a Recycler View whose elements can be scrolled vertically.
The good layout file looks like this:
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?android:attr/colorBackground"
android:orientation="vertical">
<!-- works with and without frame layout-->
<FrameLayout
android:id="#+id/play_queue_square_frame"
android:layout_width="match_parent"
android:layout_height="350dp">
<androidx.viewpager.widget.ViewPager
android:id="#+id/play_queue_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/play_queue_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
app:layoutManager="LinearLayoutManager"
android:background="?android:attr/colorBackground"
tools:listitem="#layout/item_view_song_debug" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
With the above layout everything is working as expected. In particular, the view pager scrolls in horizontal direction, the recycler view scrolls in vertical direction, and dragging either the view pager or the recycler view in horizontal direction closes the bottom sheet.
However, when replacing the view pager by androidx.viewpager2.widget.ViewPager2 yields odd behaviour. Scrolling the view pager in horizontal direction is still possible, but vertical scrolling does no longer work. Any swipes downward simply close the bottom sheet.
Using a NestedScrollView yields better results but still has erroneous behaviour.
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?android:attr/colorBackground"
android:orientation="vertical">
<FrameLayout
android:id="#+id/play_queue_square_frame"
android:layout_width="match_parent"
android:layout_height="300dp">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/play_queue_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/play_queue_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
app:layoutManager="LinearLayoutManager"
android:background="?android:attr/colorBackground"
tools:listitem="#layout/item_view_song_debug" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
Scrolling in vertical direction is still possible, and also the horizontal scrolling for the view pager. However, dragging the view pager down does no longer close the bottom sheet, whereas a dragging the recycler view down does.
If I add the following code
viewPager.setUserInputEnabled(false)
the view pager does no longer allow horizontal scrolling (as expected). So my question is simply what I have to do in order to allow horizontal scrolling and make sure that a vertical swipe downwards (on the view pager) closes the bottom sheet.
I know that a somewhat similar question has already been asked (in this post)
but as there is no answer so far I take the liberty to ask this question. What confuses me most is that it is working with the old viewpager but not with viewpager2.
Any help is greatly appreciated!
I am creating a view based on CoordinatorLayout. The view contains two elements: View in CollapsingToolbarLayout and RecyclerView as a content. The whole content is also wrapped in SwipleRefreshLayout - there was a problem with scrolling up, but easily fixed (via OnOffsetChangedListener in AppBar)
My problem is that a view in CollapsingToolbarLayout can be higher than a screen (very rare, but possible), so it has to be scrollable.
See this example:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
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: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.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<View android:id="#+id/very_big_height"
android:layout_width="match_parent"
android:background="#color/design_default_color_primary"
android:layout_height="2000dp"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/dummy_recycler_view"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.SwipeRefreshLayout>
When I scroll via an AppBar I can set my layout in such a state:
The blue area has id very_big_height and that white area is actually an empty space on a screen, as my RecyclerView has a wrap_content height and no items inside.
I still can scroll the AppBar via the blue area, and even over scroll it completely outside the screen. And if I over scroll it, there is no way to see it again.
My expected behaviour is:
AppBar should scroll only to the bottom of the screen. It should not hide if there is no content below.
Also, if content fits screen AppBar should not be scrollable (I've founded solution for disabling scroll when no content, but doesn't work when AppBar doesn't fit the screen.
Thanks for your help!
the scroll issue is caused by the parent view which is SwipetoRefreshLayout , the root view of your xml should be CoordinatorLayout .
i don't know what is the purpose of using SwipetoRefreshLayout , but having to much scrolling element may cause some bad scroll experience
First one the CoordinatorLayout can not send scroll event to SwipeRefreshLayout. You can try the code in ChildCoordinatorLayout
Second is that you can set RecyclerView match parent.
I am trying to place a recyclerview inside a nested scroll view. Following is my layout:
<FrameLayout 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.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/nestedscrollview">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.nestedscrollviewexample.ItemFragment"
android:layout_marginTop="84dp"
android:id="#+id/itemfragment"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</FrameLayout>
The fragment contains a simple Recylerview.
What i notice is that if the recyclerview is outside the NestedScrollView then it retains it edge effects. However when i place the recycler view inside the nestedscrollview the edge effects are gone.
Instead, when i add the following line-
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
I notice that edge effects are visible but only for the edge of nested scrollview. How can i retain the edge effect for the recycler view as well?
For better clarity i am sharing 2 images -
First is Recyclerview edge effect before adding it to nested scroll view.
[]
The one below is when we add recycler view to a nested scroll view-
I would like to have the recyclerview inside the nested scrollview and also keep its edge effects. Is it possible?
I'm facing a tricky situation here and I don't know how to solve this problem.
In my project I have a custom BottomSheetDialogFragment and in the layout a FrameLayout to add or replace Fragments.
Now I have a Fragment and inside I have a RecyclerView with the height:="wrap_content" because I want the BottomSheetDialogFragment only use the necessary space. Everything looks great, the problem appear when I put another view inside of the same layout and set the RecyclerView bellow or above of that view.
The RecyclerView ignores the size of the other view (or views) and always grows to the max screen size, and then it's no possible to see a few elements and even scroll.
I saw a solution, some developers are suggesting to add paddingBottom equals to the height of the view. But in my case doesn't works because I want to have a dynamic solution.
Above I'll share a few images of the problem and GitHub Repository with a sample.
Thanks for your attention!
I've manage to do what you need just need to use this as your fragment_sample.xml:
<LinearLayout 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="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/rclItems"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
<Button
android:id="#+id/btnAddMoreItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/rclItems"
android:text="#string/add_1_item"/>
</LinearLayout>
Explanation
Using a LinearLayout gives you the ability to work with weight, and the vertical orientation allows you to place an item below the other. The weight on the recyclerview will increase the height of it as needed until filling the screen. The next item you add would be added to the recyclerview but you'll need to scroll the list to see it
The android developers blog says that :-
The scrolling containers in your bottom sheet must support nested scrolling .
Try changing your fragment_sample.xml as below to make the recyclerview scroll working and to make the add button persistent.
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:id="#+id/next"
android:layout_above="#id/btnAddMoreItems"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/rclItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</android.support.v4.widget.NestedScrollView>
<Button
android:id="#+id/btnAddMoreItems"
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content"
android:text="#string/add_1_item"/>
</RelativeLayout>
Note: making bottomsheet layout a child view of CoordinatorLayout will allow you to get the implement BottomSheetBehavior and recieve its transitions callbacks .
I am making a Layout where I need to position a Toolbar below a Map Fragment. Well it may hear easy but from my small knowledge I hit upon a tricky problem.
Well I hv achieved how to get the toolbar below the fragment body but I hit on some problems:
When using Linear Layout, I split both the components using weights which was perfect as i needed it but couldnt get the Toolbar to the bottom of the Fragment.
While using Relative Layout, I was able to bring the toolbar below the fragment but since the map is big, i couldnt adjust the height of the map and the toolbar goes out of bounds.
What i need is the combined effect of weights from the LinearLayout and the 'android:Layout_below' effect from the Relative Layout.
I will post my code here:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/app_bar"
layout="#layout/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/map1"
/>
<fragment
android:id="#+id/map1"
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="200dp"
/>
</RelativeLayout>
My toolbar is in a separate Layout 'app_bar'
The Toolbar is just like any View, and can be placed wherever you want. This is a big difference between it, and the ActionBar.
Just place the element wherever you would like inside your layout.
In your case, don't place the Toolbar relative to the fragment, but relative to the parent (RelativeLayout) then you can control it's placement/size independent of your fragment (which you can then place relative to your Toolbar if you want that control)
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/app_bar"
layout="#layout/app_bar"
android:layout_width="match_parent"
android:layout_height="80dp"// or whatever...
android:layout_alignParentBottom="true"
/>
<fragment
android:id="#+id/map1"
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_alignParentTop="true"
android:layout_above="#+id/app_bar"
android:layout_height="fill_parent"
/>