If I wanted a ViewPager with several Fragments, and a FloatingActionButton that is used by one one of those Fragments, what would be the ideal layout behavior?
A. Should the FAB be located in the Activity layout, which also contains the CoordinatorLayout holding the AppBarLayout/Toolbar/ViewPager?
or
B. Should the FAB be located in the Fragment layout?
Option A makes sense in that the FAB should be able to animate as necessary within the CoordinatorLayout. For example, if I show a Snackbar, I'd like to the FAB to shift up/down with the showing/hiding of the Snackbar. However, placing the FAB here requires me to hide/show the FAB as necessary, since the other two Fragments will not be using the FAB and should have it hidden.
Option B is essentially the inverse of these benefits/drawbacks.
What is more correct?
Thanks,
Zach
A. Should the FAB be located in the Activity layout, which also
contains the CoordinatorLayout holding the
AppBarLayout/Toolbar/ViewPager?
Yes, exactly.
Look at this example:
<CoordinatorLayout>
<AppbarLayout/>
<scrollableView/>
<FloatingActionButton/>
</CoordinatorLayout>
As you can see, in the above example we used FloatingActionButton inside the CoordinatorLayout which that FloatingActionButton can be on the layout all the time without scrolling or even hiding after scrolling the Fragment or any views.
And finally, you can use this for your Fragment:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator"
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.support.v7.widget.Toolbar
android:id="#+id/dashboard_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.Toolbar"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/dashboard_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
Also, let me mention that i've added that FrameLayout with app:layout_behavior="#string/appbar_scrolling_view_behavior"
which can be under the AppbarLayout.
That's the point for that line.
B. Should the FAB be located in the Fragment layout?
That depends on you but, Using it with CoordinatorLayout is the best way.i mean, you can achieve many MaterialDesign stuffs with it.
Related
Somehow I came across Reddit app, and wondered how their Scrolling mechanism works. As you can see from the gif, there is a Menubar (Up/Downvote-comment-share bar) that always locates within the screen and can’t be scrolled out of the screen when scrolled up/down. When scrolling up, it will be located underneath the Toolbar (the grey bar at the top). When scrolling down, it will be located above the EditTextView (the Add-a-comment bar at the bottom).
Relative layout
|-->Toolbar (android:id="#+id/toolbar")
|-->ScrollView (android:layout_below="#id/toolbar")
|-->Child (This child is located underneath the Toolbar when scrolling up)
|-->Child
|-->Child
If I wanted to write this page, what dependencies, widgets or concepts
would I need to use or look into?
Note: You can give me snippets of codes if you prefer :)
you can use the CoordinatorLayout layout to realize that function. the layout like that. for details, you can see this blog in the medium.
<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/behavior_demo_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: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="scroll|enterAlways|snap"
android:background="?attr/colorPrimary" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/behavior_demo_swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="#+id/behavior_demo_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>
The toolbar (containing the menu) is outside of the ScrollView in the XML.
Or it may not even be a ScrollView at all.
It may just be view recycling- but even so the toolbar is outside of that XML layout used for displaying the content.
For hiding the TopBar and bottomBar (comment box) I recommend you use Animation
Simply call animation like
//on scrollUp
topLayout.animate().translationY(-300).alpha(0.0f).setDuration(300);
// this will make the layout go up and fade to invisible
//on scrollDown
topLayout.animate().translationY(0).alpha(1.0f).setDuration(300);
// this will make the layout come down and fade to be visible
Implement this will both Views using addOnScrollListener() or I suggest you to have a look at this answer for implementing scroll Up/Down using CoordinateLayout
Hope this will help!
I have this xml code in fragment:
<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:id="#+id/coordinatorLayout" android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme"
app:elevation="0dp">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="300dp"
app:layout_scrollFlags="scroll"
android:id="#+id/collapsingToolbarLayout"
app:statusBarScrim="#color/bestColor">
<LinearLayout></LinearLayout> <!--this elements hide then appbar is collapsed-->
</android.support.design.widget.CollapsingToolbarLayout>
<LinearLayout>
<ImageButton>
android:id="#+id/profile_header_trophies"
</ImageButton><!-- this elements like a tab,visible if appbar collapsed-->
</LinearLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/profile_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
in Java Class on Item set ClickListener:
#OnClick(R.id.profile_header_trophies)
public void profile_header_trophies_clicked() {
if (myProfile != null) {
appBarLayout.setExpanded(false, false);
if (myProfile.getBests().size() == 0) {
profile_recyclerView.smoothScrollToPosition(3);
} else {
profile_recyclerView.smoothScrollToPosition(2 + 20);
}
}
When I click to ImageButton, my RecyclerView scrolls to position, everything looks fine.
But if I put finger on AppBarLayout section (ImageButton) which visible(sticky) on top, and drag to bottom I have a bad scrolling.
My appbar start expanded, while my Recycler have some elements on top (they are hidden when scrolled).
I think this problem is setting behavoir. Because if I scrolling recycler first, AppBar doesnt start expanding, while Recycler not rich top of elements.
Thanks for your answers.
The bad scrolling once happened to me, it was happening because I was using RecyclerView inside another RecyclerView.
So when I try to scroll contents in the main RecyclerView it gave me this issue.
To resolve that issue I added this to RecyclerView:
recyclerView.setNestedScrollingEnabled(false);
For doing this in XML you can use:
android:nestedScrollingEnabled="false"
with this, you tell it to "merge" the scrolling of the RecyclerView with the scrolling of its parent
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
if I well understood, you want to have the following scrolling behaviour:
if you are scrolling by touching outside the RecyclerView, it collapses the AppBar
if you are scrolling by touching inside it, it ignores the RecyclerView's scroll and collapses the AppBar, and once the AppBar is collapsed, it scrolls inside the RecyclerView
Could you confirm this is the desired behaviour please?
In such case, you may look at this answer, maybe it will help
I think you need wrap content in NestedScrollView and set app:layout_behavior="#string/appbar_scrolling_view_behavior" in NestedScrollView
If you are using RecyclerView inside ViewPager then add this line to ViewPager: android:nestedScrollingEnabled="false"
It will solve your problem.
It can be tricky and there's a few things you need to have in order for this to work.
You should use app:layout_scrollFlags="scroll|enterAlwaysCollapsed" in your CollapsingToolbarLayout instead of just scroll.
It's not clear where the tabs or buttons are in your XML layout, but if they are supposed to stay on screen then you need to pin them, so you would use app:layout_collapseMode="pin" for that element. Perhaps this is in the LinearLayout or ImageView?
If the LinearLayout holds something else then you should add some scroll flags to that too, probably best would be app:layout_scrollFlags="scroll|enterAlwaysCollapsed" if it is supposed to scroll off screen.
Lastly, make sure you are not disabling nested scrolling in your RecyclerView.
How to make hide/show toolbar when our list scrolling to the top, knowing that the toolbar view is described inside activity_main.xml but recyclerView is described in another fragmet nomed Fragment_main.xml
sorry for my english :)
Since your activity which has the toolbar within its content view is starting the fragment, you can always get a hold of it from your fragment.
MainActivity mainActivity = (MainActivity)getActivity();
I would recommend doing a method for it in your MainActivity:
public void showToolbar(boolean show) {
// If you have your toolbar as a private member of MainActivity
toolbar.setVisiblity(show ? View.VISIBLE : View.GONE);
// But you can also do this
if (show) {
getSupportActionBar().show();
}
else {
getSupportActionBar().hide();
}
}
And then when you actually want to hide it from your fragment, call it:
((MainActivity)getActivity()).showToolbar(false);
To make the UI change more smooth, I recommend translating it instead of just instantly hiding it. Take a look at the top answer here for inspiration:
android lollipop toolbar: how to hide/show the toolbar while scrolling?
If you don't know how to take care of when to actually show or hide it via scroll logic, take a look at this library which handles a lot for you and also gives examples:
https://github.com/ksoichiro/Android-ObservableScrollView
This is kind of simple.
Just put this code in your toolbar
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"/>
This will do the magic : app:layout_scrollFlags="scroll|enterAlways"
remember to add in your xml the app call xmlns:app="http://schemas.android.com/apk/res-auto"
Check this tutorial: https://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout
Use below code:
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
...>
<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"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/rvToDoList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</android.support.design.widget.CoordinatorLayout>
If RecyclerView is in another fragment, then add below line to the View which contain RecyclerView in this CoordinatorLayout.
app:layout_behavior="#string/appbar_scrolling_view_behavior"
Must Use CoordinatorLayout.
Background
I have a viewPager, with 3 fragments and tabs for them. Each fragment has an intro phase (of its own) that doesn't have any scrollable content.
After leaving the intro phase, there is a recyclerView that the user can scroll in.
The problem
I need to use the new design library, so that when scrolling (only via recyclerView), it will hide the actionBar and let the tabs still be shown.
When the user goes to a fragment that doesn't have a scrollable content yet, the actionBar should re-appear, similar to what "Google Play Newsstand" has. In fact, I would even be happy to have what they have: as soon as you start swiping left/right, re-show the action bar.
Thing is, if I follow the guidelines and samples, I have 2 issues:
The non-scrollable phase for fragments gets truncated at the bottom, as if it can get scrolled.
I can't find how to re-show the actionBar, and make it stuck there till I switch to a scrollable content (either by switching to another fragment, or when the content of the current fragment changes to a scrollable content).
What I've tried
Here's a short snippet of the current layout XML file of the activity:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/activity_main__coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/activity_main__appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="?attr/actionBarTheme">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:layoutDirection="ltr"
android:theme="?attr/actionBarTheme"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
tools:ignore="UnusedAttribute"/>
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:tabGravity="fill"
app:tabIndicatorColor="#FFffffff"
app:tabIndicatorHeight="3dp"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<include layout="#layout/fabs"/>
</android.support.design.widget.CoordinatorLayout>
<include
layout="#layout/sliding_menu"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="left"/>
</android.support.v4.widget.DrawerLayout>
The fragments have a layout of a ViewAnimator that just switches between phases, while one of them is the non-scrollable content, and the other is the RecyclerView.
I've tried to add a NestedScrollView/ScrollView the non-scrollable content , and force it to fill itself, using android:fillViewport="true" , but it didn't work. For ScrollView it didn't even allow to scroll.
EDIT: Another thing I've tried is to use addOnPageChangeListener on the viewPager, so that in onPageSelected I could set the flags for the toolbar :
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
params.setScrollFlags(!needScrolling? 0 : LayoutParams.SCROLL_FLAG_SNAP | LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | LayoutParams.SCROLL_FLAG_SCROLL);
It works, but it has a issues too:
while scrolling horizontally, I can see the content of the non-scrollable fragment being truncated, and when going to the new fragment (stop touching the screen, to let it snap to the fragment), only then it shrinks its size to fit the correct space.
The toolbar doesn't get re-shown.
If the toolbar is hidden due to scrolling on another fragment, and I'm now on the non-scrollable fragment, it actually gets less space to fill than it's supposed to, so it has empty space at the bottom.
EDIT: one solution is to add an empty view of the same height of actionbar (layout_height="?actionBarSize") at the bottom of the non-scrollable fragments's content. However, when the action bar is hidden, I can see the view, so there is empty space. I still need to know how to re-show the actionbar on this case.
The question
How do I set a different behavior for the toolbar, so that it will re-show and stuck on certain states, yet be scrollable only when there is a RecyclerView shown on the current fragment?
Overview
I am trying to implement one of the Scrolling Techniques, Flexible space with overlapping content, described in Material Design.
Flexible space with overlapping content
Content can overlap the app bar.
Behavior:
The app bar’s starting position should be located behind the content.
Upon upward scroll, the app bar should scroll faster than the content,
until the content no longer overlaps it. Once anchored in place, the
app bar lifts up to allow content to scroll underneath.
https://www.google.co.in/design/spec/patterns/scrolling-techniques.html#scrolling-techniques-scrolling
Problem
However, the problem is,
the title in my AppBar scrolls down when expanded and hides below the overlapping content.
Here, my toolbar is hidden below the overlapping CardView.
When the appbar is collapsed, the toolbar and hence the Title slides up from below.
Code
Here's my Code:
activity-main.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="200dp"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
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:layout_gravity="top"
android:background="?attr/colorPrimary"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
...
I have also added these in my MainActivity's onCreate function
setSupportActionBar(toolbar);
collapsingToolbarLayout.setTitle("App Name");
I want the toolbar(with the tile and the other contents, which I will add later) to stay at the top irrespective of the appbar being expanded or collapsed.
I have read the documentations, gone through many posts and tutorials, watched a lot of videos but failed to find a working solution or any related solutions at all.
If anyone has some idea on how to fix this, please suggest. Thanks for helping.
I was looking for a solution myself when I found the answer in the comments on a similar issue report.
Basically you call setTitleEnabled() on your CollapsingToolbarLayout like this:
CollapsingToolbarLayout.setTitleEnabled(false);
You can do this in xml as well, by adding this to your CollapsingToolbarLayout:
app:titleEnabled="false"
By setting it to false, you'll get the desired behaviour. The title stays fixed to the top of the screen.
The Toolbar itself was actually already at the top, but this makes the title stay there as well, instead of translating between the bottom of the CollapsingToolbarLayout and the Toolbar.
I have acheived this by adding below code inside Toolbar tag.
app:layout_collapseMode="pin"
In my case I needed to add app:titleEnabled="false" to the CollapsingToolbarLayout AND app:layout_collapseMode="pin" to the android.support.v7.widget.Toolbar
Now the toolbar stays pinned to the top of the screen, irrespective of whether the user scrolls up or down.
To keep title at top, simple put this attribute to your CollapsingToolbarLayout:
app:expandedTitleGravity="top"