gcantoni
gcantoni

Reputation: 787

Transparent toolbar on scrolling with shadow effect

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:enter image description here

And this is what I can get: enter image description here

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>

Upvotes: 4

Views: 1805

Answers (2)

gcantoni
gcantoni

Reputation: 787

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. enter image description here

When the user scrolls, toolbar elevation is changed and the entire toolbar and status bar (notice status bar) are transparent!

enter image description here

How does mine look? enter image description here

enter image description here

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!

Upvotes: 2

Mindgamer
Mindgamer

Reputation: 239

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>

Upvotes: 1

Related Questions