How to make toolbar and statusbar color gradient from top to bottom

Viewed 760

I'm trying to implement gradient color to the toolbar and status bar so that it would look something like this: enter image description here

But instead I'm getting this:enter image description here

I have set a custom background for the toolbar with the gradient color and also set windowTranslucentStatus=true in styles. But the color looks different on the toolbar and status bar. How to resolve this to get the desired effect.

Toolbar:

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/relativeLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/my_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@drawable/toolbar_gradient"
        app:popupTheme="@style/AppTheme.PopupOverlay"
        android:elevation="4dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent">


        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">


            <ImageView
                android:id="@+id/imageViewToolbar"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginEnd="16dp"
                android:visibility="invisible"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@drawable/logo_transparent" />

            <TextView
                android:id="@+id/textView4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                android:text="TestApp"
                android:textColor="@color/colorSplashText"
                android:textSize="18sp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

        </androidx.constraintlayout.widget.ConstraintLayout>


    </androidx.appcompat.widget.Toolbar>

toolbar_gradient

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">

    <gradient
        android:endColor="#00008A5B"
        android:startColor="@color/colorPrimary"
        android:angle="270"
        />

</shape>

styles.xml

    <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="fontFamily">@font/bukra_light</item>
    <item name="android:windowTranslucentStatus">true</item>
</style>

Activity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity);
    Toolbar toolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(toolbar);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimary));
.....
}
1 Answers

See my answer in Create Linear gradient from top to bottom to status bar and toolbar in android for a detailed explanation.

Taking your code and applying the same process, I get the following code:

res/values/styles.xml:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowTranslucentStatus">true</item>
    </style>

</resources>

res/values/styles-v21.xml:

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>

</resources>

res/drawable/statusbar_gradient.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">

    <gradient
        android:startColor="#ff008A5B"
        android:endColor="#b0008A5B"
        android:angle="270"
        />
</shape>

Note the gradient endColor matches the gradient startColor in the following toolbar_gradient.xml.

res/drawable/toolbar_gradient.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="#b0008A5B"
        android:endColor="#00008A5B"
        android:angle="270"
    />
</shape>

res/layout/activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/relativeLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="false">

    <View
        android:id="@+id/status_bar_scrim"
        android:layout_width="match_parent"
        android:layout_height="26dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/my_toolbar"
        android:background="@drawable/status_bar_gradient" />

    <androidx.appcompat.widget.Toolbar
        android:id="@id/my_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@drawable/toolbar_gradient"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/status_bar_scrim" />


</androidx.constraintlayout.widget.ConstraintLayout>

Note the use of android:fitsSystemWindows="false" to ensure the scrim overlays the status bar area.

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Window window = getWindow();
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            // ensure the layout fills the screen
            final int layoutFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
            window.getDecorView().setSystemUiVisibility(layoutFlags);
            // make the status bar translucent
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                window.setStatusBarColor(0x00000000);
            }
        } else {
            window.setDecorFitsSystemWindows(false);
        }

        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.my_toolbar);
        setSupportActionBar(toolbar);

        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
            // set the height of the scrim to standard status bar height for this device (normally 26dp)
            View statusBarScrim = findViewById(R.id.status_bar_scrim);
            if (statusBarScrim != null) {
                int height;
                int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
                if (resourceId > 0) {
                    height = getResources().getDimensionPixelSize(resourceId);
                    ViewGroup.LayoutParams lp = statusBarScrim.getLayoutParams();
                    lp.height = height;
                    statusBarScrim.setLayoutParams(lp);
                    statusBarScrim.setVisibility(View.VISIBLE);
                }
            }
        }
    }
}

This is what I get:

Example output

N.B. Answer updated to take account of deprecation of WindowManager UI flags in Android 11. The UI flags are still required for versions prior to Android 10 (Q), so it's not possible to completely get rid of deprecation warnings, but they can be guarded by version checks.

Tested successfully on KitKat (19), Marshmallow (23), Nougat (24) and R (30).

Related