Transparent toolbar on scrolling with shadow effect - android

I'm trying to get an effect similar to that of the toolbar in the google messages app.
Basically the toolbar has a solid color and when the user scrolls it becomes transparent with a shadow at the bottom.
I managed to get a shadow effect but I can't get the transparent effect.
This is what I'm trying to achieve:
And this is what I can get:
This is my XML AppBarLayout with toolbar:
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:liftOnScroll="true">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:minHeight="?attr/actionBarSize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:titleTextColor="#color/colorTextMain"
android:background="#color/colorPrimary">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>

Solution
I managed to get what I wanted! I thought it was easier to get it, however, i write my solution in case it is useful and if someone wants to improve it!
First, google app messages way to do it.
When the user does not scroll, toolbar elevation is 0.
When the user scrolls, toolbar elevation is changed and the entire toolbar and status bar (notice status bar) are transparent!
How does mine look?
Let's create a CoordinatorLayout with inside a ToolBar, NestedScrollView and a LinearLayout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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"
android:orientation="vertical"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:background="#color/colorPrimary">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorToolbar"
android:elevation="0dp"
app:titleTextColor="#color/colorTextMain"
android:fitsSystemWindows="true"/>
<androidx.core.widget.NestedScrollView
android:id="#+id/myScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
... place page content here ...
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Now, inside your class OnCreate method
// find the toolbar view inside the activity layout
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitleTextAppearance(this, R.style.FontStyle);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setTitle(getString(R.string.about));
toolbar.setElevation(1); // required or it will overlap linear layout
toolbar.setBackgroundColor(Color.TRANSPARENT); // required to delete elevation shadow
// status bar height programmatically , notches...
statusBarHeight = getStatusBarHeight();
linearLayout = findViewById(R.id.linear_layout);
linearLayout.setPadding(1,180+statusBarHeight,1,0);
ViewGroup.LayoutParams params = toolbar.getLayoutParams();
params.height = 180+statusBarHeight;
toolbar.setLayoutParams(params);
Since we have notches ( :-( ), we have to calculate status bar height programatically. By default status bar height is 24dp. Unfortunately not all notch phones use 24dp. How to calculate status bar height programatically
Now we need to handle toolbar elevation whether the user moves along the page or not. Inside your class OnCreate method
NestedScrollView scroller = findViewById(R.id.myScroll);
scroller.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) (v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
if (scrollY > oldScrollY) {
// when user scrolls down set toolbar elevation to 4dp
toolbar.setElevation(4);
toolbar.setBackgroundColor(getColor(R.color.colorToolbar));
}
if (scrollY < oldScrollY) {
// when user scrolls up keep toolbar elevation at 4dp
toolbar.setElevation(4);
toolbar.setBackgroundColor(getColor(R.color.colorToolbar));
}
if (scrollY == 0) {
// if user is not scrolling it means
// that he is at top of page
toolbar.setElevation(1); // required or it will overlap linear layout
toolbar.setBackgroundColor(Color.TRANSPARENT); // required to delete elevation shadow
}
});
Almost done! This is a crucial part! Again inside your class OnCreate method
switch (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
case Configuration.UI_MODE_NIGHT_YES:
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
getWindow().setStatusBarColor(Color.TRANSPARENT);
break;
case Configuration.UI_MODE_NIGHT_NO:
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
getWindow().setStatusBarColor(Color.TRANSPARENT);
break;
}
Configuration.UI_MODE_NIGHT_YES and Configuration.UI_MODE_NIGHT_NO: are a way to handle dark and light theme. Since we are going to put all the entire content of the page on the status bar we won't have control anymore of status bar icons colors (obtainable via styles) and so we need to detect if a light or dark theme is enabled for programatically set status bar icons colors!

I think you have to make your appbar lay on a piece of view.
Try something like that:
<androidx.constraintlayout.widget.ConstraintLayout android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#color/transparent_color"
app:liftOnScroll="true">
<androidx.appcompat.widget.Toolbar
android:background="#color/colorPrimary"
android:fitsSystemWindows="true"
android:id="#+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="#color/transparent_color"
android:minHeight="?attr/actionBarSize"
app:titleTextColor="#color/colorTextMain"/>
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:layout_height="match_parent"
android:layout_width="match_parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Related

setOnApplyWindowInsetsListener on BottomNavigationView which is direct child of CoordinatorLayout is not called

This is a very simple layout with BottomNavigationView
<androidx.coordinatorlayout.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:background="#EEEEEE">
<!--
OUTLINE
<CoordinatorLayout>
<AppbarLayout>
<Toolbar/>
<TabLayout/>
<AppbarLayout >
<ViewPager2/>
<BottomNavigationView/>
</CoordinatorLayout>
-->
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f00"
android:theme="#style/ThemeOverlay.MaterialComponents.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="256dp"
android:background="#ff0"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="#android:color/transparent">
<ImageView
android:id="#+id/ivHeader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/header"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
android:background="#55ff0000"
android:layout_gravity="top"
android:layout_marginBottom="?attr/actionBarSize" />
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#android:color/transparent"
app:tabIconTint="#F57C00"
app:tabIndicatorColor="#F57C00"
app:tabIndicatorHeight="4dp"
app:tabMode="scrollable"
app:tabSelectedTextColor="#F5F5F5"
app:tabTextColor="#FFE0B2" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/viewPager2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:menu="#menu/main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I have watched this video from Chris Banes, read this thread, and few others including this one which has top voted answer that says do not use android:fitsSystemWindows which i don't, and have really no idea how exactly insets and setOnApplyListener works and consumes insets.
First of all i set fullscreen with
private fun hideSystemUI(view: View = window.decorView, isFullScreen: Boolean) {
var uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
if (isFullScreen) {
// hide status bar
uiOptions = (
uiOptions
// or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
// Views can use nav bar space if set
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// // Removes Status bar
// or View.SYSTEM_UI_FLAG_FULLSCREEN
// // hide nav bar
// or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
)
}
view.systemUiVisibility = uiOptions
}
by passing root CoordinatorLayout as parameter to this function. Set theme as
#color/status_bar_color
true
#color/nav_bar_color
And initial image without setting any insets
As can be seen in the Toolbar is below statusBar while BottomNavigationView is below NavBar.
So i set setOnApplyWindowInsetsListener
bottomNav.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(bottom = insets.systemWindowInsetBottom)
insets
}
but it does not get called. So i set insets on AppbarLayout, CollapsingLayout, and ImageView like i would do with android:fitsSystemWindows
appbar.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(top = insets.systemWindowInsetTop)
insets
}
collapsingToolbar.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(top = insets.systemWindowInsetTop)
insets
}
ivHeader.setOnApplyWindowInsetsListener { view, insets ->
view.updatePadding(top = insets.systemWindowInsetTop)
insets
}
And i get this
Red background belongs to AppbarLayout, yellow background belongs CollapsingToolbarLayout.
Now, BottomNavigationView's setOnApplyWindowInsetsListener gets called and it's inset get fixed i guess.
My question is why doesn't it get called without calling insets for CollapsingToolbarLayout, and why there is a gap for CollapsingToolbarLayout and AppbarLayout?
I found out that CollapsingToolbarLayout has a bug that prevents receiving insets which is mentioned in issues on github. Setting layouts above AppBarLayout makes sure that other views receive insets.
But i still not be able to find how to apply insets/padding correctly for the layout in the question.

How to apply insets to CollapsingToolbarLayout with an image inside, so image in toolbar is drawn behind status bar?

I'm trying to setup fullscreen activity for Android 10 using insets. I wanted to have an image in toolbar drawn behind status bar. I've tried to use android:fitsSystemWindows flag in different combinations, but it doesn't work, AppBarLayout doesn't have correct padding and status bar slightly overlaps toolbar menu controls. So I've used convenient WindowInsetsCompat wrapper, Insetter library by Chris Banes, to set paddings according to system window insets.
Here is my layout:
<androidx.coordinatorlayout.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:id="#+id/book_activity_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:context="com.bookcrossing.mobile.ui.bookpreview.BookActivity"
>
<androidx.core.widget.NestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
>
...
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/toolbarContainer"
android:layout_width="match_parent"
android:layout_height="220dp"
>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsingToolbarContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:titleEnabled="true"
app:toolbarId="#id/toolbar"
>
<ImageView
android:id="#+id/cover"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/cover_description"
android:scaleType="centerCrop"
android:cropToPadding="true"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.5"
/>
<androidx.appcompat.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"
tools:title="War and Peace"
/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/favorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/default_padding"
android:clickable="true"
android:focusable="true"
android:src="#drawable/ic_turned_in_not_white_24dp"
app:layout_anchor="#id/toolbar_container"
app:layout_anchorGravity="bottom|right|end"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Here is how I set the paddings in code:
Insetter.setOnApplyInsetsListener(toolbarContainer, (view, windowInsets, initial) -> {
view.setPadding(initial.getPaddings().getLeft(),
windowInsets.getSystemWindowInsetTop() + initial.getPaddings().getTop(),
initial.getPaddings().getRight(), initial.getPaddings().getBottom());
});
Insetter.setOnApplyInsetsListener(cover, (view, windowInsets, initial) -> {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
params.topMargin = windowInsets.getSystemWindowInsetTop() + initial.getMargins().getTop();
view.setLayoutParams(params);
});
Insetter.setOnApplyInsetsListener(nestedScrollView, (view, windowInsets, initial) -> {
view.setPadding(initial.getPaddings().getLeft(), initial.getPaddings().getTop(),
initial.getPaddings().getRight(),
windowInsets.getSystemWindowInsetBottom() + initial.getPaddings().getBottom());
});
Insetter.setOnApplyInsetsListener(favorite, (view, windowInsets, initialPadding) -> {
view.setPadding(initialPadding.getPaddings().getLeft(), initialPadding.getPaddings().getTop(),
windowInsets.getSystemWindowInsetRight() + initialPadding.getPaddings().getRight(),
initialPadding.getPaddings().getBottom());
});
I set window flags for the fullscreen mode:
root.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
And this is the result pictured:
Status bar is set to be transparent, blue color is from the toolbar that has top padding.
As a final result, I would like image to be drawn behind the status bar, is it possible at all?
I'm testing on the Android 10 emulator.
Your flags seem to be wrong. You set the flag for the navigation bar while you should be setting the one for the status bar.
Here is the code I use (Kotlin):
requireActivity().window?.decorView?.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
to make the UI draw behind status bar without the status bar getting hidden. Then I use this extension function I use on views that should not overlap with the status bar like buttons and other controls:
fun View.alignBelowStatusBar() {
this.setOnApplyWindowInsetsListener { view, insets ->
val params = view.layoutParams as ViewGroup.MarginLayoutParams
params.topMargin = insets.systemWindowInsetTop
view.layoutParams = params
insets
}
}
So the first flags would ensure your backgrounds/images go under the status bar. The second one is to make sure that your controls are not overlayed by the status bar.
As I remember you don't need to support paddings in CoordinatorLayout manually, please see setupForInsets function in CoordinatorLayout class. To support drawing behind status bar you should set android:fitsSystemWindows="true" for CoordinatorLayout:
<androidx.coordinatorlayout.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:id="#+id/book_activity_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:context="com.bookcrossing.mobile.ui.bookpreview.BookActivity"
>
And as I understand you do not need animateLayoutChanges here. It's responsible for animations in layout changes such as removing/adding and showing/hiding views.
android:fitsSystemWindows="true"

Persistent BottomSheet below ActionBar

I have an app layout with a custom toolbar and a persistent BottomSheet - both inside of a CoordinatorLayout.
On a button click I want to show the BottomSheet. Right now the sheet is displayed fullscreen and overlays the toolbar. By setting the app theme to Theme.AppCompat.Light.DarkActionBar the BottomSheet stays below the ActionBar, but the bar cannot be customized.
Is there a way to limit the height of the persitent BottomSheet to fullscreen - ActionBar height?
This is my code in activity_main.xml
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:attrs="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="com.test.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
app:elevation="20dp"
android:elevation="20dp"
android:layout_height="?attr/actionBarSize">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
app:elevation="20dp"
android:elevation="20dp"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
</android.support.design.widget.AppBarLayout>
</LinearLayout>
<include layout="#layout/bottom_sheet_additem"/>
</CoordinatorLayout>
Here is the code of sheet_bottom.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/bottomSheetLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorAccent"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
android:fitsSystemWindows="true"
app:layout_behavior="#string/bottom_sheet_behavior">
<TextView
android:id="#+id/bottomsheet_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Lorem Ipsum Dolor..."
android:textColor="#FFFFFF" />
</RelativeLayout>
The image on the left hand side shows the BottomSheet which stops below the Toolbar - which is not working with my current code. Currently it looks like the picture on the right.
I had the same problem... I don't know if it's the best solution, but for now, worked for me.
Try to put your include inside another CoordinatorLayout in your activity_main.xml, with a marginTop like this:
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:attrs="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="com.test.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
app:elevation="20dp"
android:elevation="20dp"
android:layout_height="?attr/actionBarSize">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
app:elevation="20dp"
android:elevation="20dp"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
</android.support.design.widget.AppBarLayout>
</LinearLayout>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="56dp">
<include layout="#layout/bottom_sheet_additem"/>
</android.support.design.widget.CoordinatorLayout>
</CoordinatorLayout>
I hope it helps.
We can use app:layout_behavior instead of fixed height
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<include layout="#layout/bottom_sheet_additem"/>
</android.support.design.widget.CoordinatorLayout>
Your sheet_bottom should look like this
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/activity_main">
<RelativeLayout
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:behavior_hideable="true"
app:behavior_peekHeight="?android:attr/actionBarSize"
app:elevation="#dimen/size_5dp"
app:layout_behavior="#string/bottom_sheet_behavior">
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
The accepted answer works when you expand the bottom sheet to the full screen, but when collapsing it, it adds additional margin that makes a part of the collapsing layout hidden below the screen, so I decided to put the margin programmatically by listening to the collapse/hidden status of the BottomSheet.
First add the BottomSheet within a CoordintorLayout in xml
And add below callback listener.
mBottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
CoordinatorLayout bottomSheet = findViewById(..); // inflate the bottom sheet
CoordinatorLayout.LayoutParams layoutParams =
(CoordinatorLayout.LayoutParams) bottomSheet.getLayoutParams();
if (newState == BottomSheetBehavior.STATE_COLLAPSED)
layoutParams.setMargins(0, 0, 0, 0); // remove top margin
else if (newState == BottomSheetBehavior.STATE_EXPANDED) {
layoutParams.setMargins(0, 100, 0, 0); // add top margin
bottomSheet.setLayoutParams(layoutParams);
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
}
});
+1 for updating the margin programmatically. While the hidden part of the BottomSheet can be offset by increasing the peek height, using just the original solution above means the margin projects onto the underlying UI elements so the scroll action area projects off the actual BottomSheet onto the other UI.
Using the onStateChanged method in the BottomSheetCallback means acting on the event that the BottomSheet has already expanded or collapsed. Adding or removing the margin at this stage can result in seeing 'jerky' behaviour where for example the sheet momentarily reaches the fully expanded state covering the appbar before the margin is then programmatically applied to shift the UI components down resulting in a 'flash' as this applies.
Instead I used the onSlide method to detect when the BottomSheet was being slid up or down and added or removed the margins only once the sheet was half way through the transition. If the margins are applied too early in the slide motion then again the user can see the BottomSheet UI jumping up or down not long after initiating the action (they are less likely to notice this at the half way point if they have done a 'fling' up or down motion.
Also I found it worked best to fetch the height of the AppBar and the status bar and use those to set the required padding value for accurate placement in expanded mode.
This challenge can be avoided altogether by using a widget to trigger the BottomSheet state change programmatically.
#Override
public void onSlide(View bottomSheet, float slideOffset) {
boolean inRangeExpanding = oldOffSet < slideOffset;
boolean inRangeCollapsing = oldOffSet > slideOffset;
oldOffSet = slideOffset;
if (inRangeCollapsing && slideOffset < 0.5f) {
//reset padding on top of bottomsheet so there is no padding/overlap onto underlying sheet (which overlaps underlying sheet and so interfers with scrolling behaviour
bSheetView.setPadding(0,10,0,0);
Log.d(TAG,"onSlide STATE_COLLAPSING");
} else if(inRangeExpanding && slideOffset > 0.5f){
//reset padding on top of bottomsheet so there is padding/overlap onto underlying sheet so it does not write over the top of the menu appbar
bSheetView.setPadding(0, topMargin,0,0);
Log.d(TAG,"onSlide STATE_EXPANDING");
}
}

Is it possible to have the Status Bar scroll away along with the toolbar using coordinator layout on Android?

I would like to know if it is possible to scroll the entire status bar (icons and background), not just the background. Almost as if as if it was part of the toolbar.
I am experiencing the same situation as the question below, the difference is I would like to know if I can scroll the entire status bar as appose to making the background opaque - which is what I think was the desired outcome of the below query
Android status bar scrolling up with coordinator layout, leaving status icons overlapping toolbar title
Here is a graphic
Here is my code
<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="me.hugopretorius.wishlizt.MainActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay"
app:contentScrim="#000">
<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"
app:popupTheme="#style/AppTheme.PopupOverlay"
/>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="#id/tabs"/>
<io.github.yavski.fabspeeddial.FabSpeedDial
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:fabGravity="bottom_end"
app:fabMenu="#menu/menu_fab"
app:miniFabBackgroundTint="#android:color/white"
app:miniFabDrawableTint="?attr/colorPrimaryDark"
app:miniFabTitleTextColor="?attr/colorPrimaryDark" />
</android.support.design.widget.CoordinatorLayout>
You should be able to listen to scroll changes, and hide the status bar once the Toolbar collapses. This won't give you actual incremental scrolling, but will leave you with just the tabs as you require.
First, onCreate set the flags so that the layout won't jump when the bar disappears:
//root should be your coordinator/top level layout
mRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
Once the toolbar collapses, change the status bar to hidden:
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (Math.abs(verticalOffset) == appBarLayout.getTotalScrollRange()) {
// Collapsed
mRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_FULLSCREEN); //this one changed
} else if (verticalOffset == 0) {
// Fully Expanded - show the status bar
if (Build.VERSION.SDK_INT >= 16) {
mRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
} else {
// Somewhere in between
// We could optionally dim icons in this step by adding the flag:
// View.SYSTEM_UI_FLAG_LOW_PROFILE
}
}
});
Try adding this to your onResume of your activity
View decorView = getWindow().getDecorView();
int uiFlagFullscreen = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiFlagFullscreen);

Hide Toolbar and BottomBar in CoordinatorLayout when scrolling - visible under transparent status bar

I have main activity with NavigationDrawer Toolbar and BottomBar. Inside the activity is container for fragments. And the fragment has RecyclerView. So when user is scrolling, I want to hide the Toolbar and BottomBar accordingly. I did that using layout behavior on recycler app:layout_behavior="#string/appbar_scrolling_view_behavior" and layout scroll flags app:layout_scrollFlags="scroll|enterAlways|snap" on Toolbar. For BottomBar I'm using this library: https://github.com/roughike/BottomBar
The problem is, that when the Toolbar and BottomBar are scrolled off the view, they are still visible under the StatusBar and NavBar
My code:
STYLE:
<style name="TranslucentStatusTheme" parent="AppTheme">
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowContentOverlay">#null</item>
</style>
MAIN ACTIVITY CONTENT:
<?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:id="#+id/app_bar_main_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.test.activity.MainActivity"
>
<android.support.design.widget.AppBarLayout
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: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|snap"
app:popupTheme="#style/AppTheme.PopupOverlay"
/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/bottomBar"
android:fitsSystemWindows="true"
/>
<com.roughike.bottombar.BottomBar
android:id="#+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="#dimen/bottom_bar_menu_height"
app:bb_activeTabColor="#color/colorAccent"
app:bb_behavior="shifting|shy|underNavbar"
app:bb_inActiveTabColor="#color/bottom_bar_inactive_tab_color"
app:bb_tabXmlResource="#xml/bottombar_tabs"
app:layout_anchor="#id/container"
app:layout_anchorGravity="bottom"
android:layout_gravity="bottom"
/>
</android.support.design.widget.CoordinatorLayout>
AND IMAGES OF MY PROBLEM:
When no fitsSystemWindows flag is set - the toolbar is below stauts bar
When no fitsSystemWindows flag is set and content is scrolled - the toolbar is hide properly, but the bootom bar is still visible below nav bar
When fitsSystemWindows flag is set to root coordinator - the normal state looks ok
When fitsSystemWindows flag is set to root coordinator and content is scrolled - the status bar and bottom bare are visible below the transparent status bar and nav bar
Can anybody help me what I'm doing wrong? I already tried all possible combinations of fitsSystemWindows on different views.
EDIT:
I fixed the Toolbar below status bar issue, but I don't think that the solution is clean. I'm still looking for better one. And I still cannot solve the bottom bar issue
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
toolbar.setPadding(0, getStatusBarHeight(), 0, 0);
}
.....
// A method to find height of the status bar
private int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
To hide BottomBar on scroll, you need to set app:bb_behavior="shy"
<com.roughike.bottombar.BottomBar
android:id="#+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="#dimen/bottom_bar_menu_height"
app:bb_activeTabColor="#color/colorAccent"
app:bb_behavior="shy"
app:bb_inActiveTabColor="#color/bottom_bar_inactive_tab_color"
app:bb_tabXmlResource="#xml/bottombar_tabs"
app:layout_anchor="#id/container"
app:layout_anchorGravity="bottom"
android:layout_gravity="bottom"
/>

Categories

Resources