简体   繁体   中英

Set status bar color gradient matching the content background gradient in Jetpack Compose

My issue is like the pic颜色错误

I set up status bar color like this:

 val systemUiController = rememberSystemUiController()
    SideEffect {
        systemUiController.setStatusBarColor(
            color = Color(0xFFA784FB)
        )
    }

My top bar

@Composable
fun ProminentTopAppBarWithImage() {
    TopAppBar(
        modifier = Modifier.height(200.dp),
        contentPadding = PaddingValues(all = 0.dp) // (1)
    ) {
        Box(modifier = Modifier.fillMaxSize().background(SaveDoneBackGroundGradient)) { // (2)
            Row( // (4)
                modifier = Modifier
                    .fillMaxSize()
                    .padding(horizontal = 4.dp) // (5)
            ) {
                /*...*/
            }
        }
    }
}

Any solutions for this issue?

I think the only way for a status bar to have and match a gradient color of the content is to resort back to old window/drawable config.

Taken the idea from this post , you'll have to create an xml drawable that will match the colors and orientation of your gradient background you use in your composable container/layout.

res/drawable/gradient_horizontal.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:type="linear"
        android:angle="0"
        android:startColor="#9881de"
        android:endColor="#6b50ba"  />
</shape>

and have this window configuration, where you will set the drawable as the window background

fun gradientStatusBar(activity: Activity) {
    val window: Window = activity.window
    val background = ContextCompat.getDrawable(activity, R.drawable.gradient_horizontal)
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)

    window.statusBarColor = ContextCompat.getColor(activity,android.R.color.transparent)
    window.navigationBarColor = ContextCompat.getColor(activity,android.R.color.transparent)
    window.setBackgroundDrawable(background)
}

and then call it in your activity

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        gradientStatusBar(this) // call it here
        setContent {
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .background(
                        brush = Brush.horizontalGradient(
                            colors = listOf(
                                Color(0xFF9881de),
                                Color(0xFF6b50ba)
                            )
                        )
                    )
            )
...

You'll get something like this

在此处输入图像描述

You'll just have to adjust both the drawable and your background gradient colors/orientation if you want to change everything and maintain a uniform look of your status bar and the content.

I don't think SystemUiController allows setting a gradient as status bar color. What you can do instead is draw behind status bar for that particular screen so that the gradient that you use for TopAppBar will be shown behind the status bar also.

@Composable
fun YourScreen() {
    val window = (LocalContext.current as Activity).window
    DisposableEffect(Unit) {
        WindowCompat.setDecorFitsSystemWindows(window, false)
        onDispose {
            WindowCompat.setDecorFitsSystemWindows(window, true)
        }
    }
    YourTopAppBar()
}

Note: LocalContext.current as Activity will work if the current context is an Activity if you have this screen inside a Fragment , this case will fail and you will have to get the activity context from current context. If that's the case, you can use the following extension function to get Activity from current Context :

fun Context.getActivity(): Activity? = when (this) {
    is Activity -> this
    is ContextWrapper -> baseContext.getActivity()
    else -> null
}

So listen, the idea of just having a single screen have a gradient background is not supported in any version of Android, out-of-the-box. Still, in Compose it it often the case that Composables represent entire screens, which begs a standard architecture to be designed. Now, in those screen-representing composable, you could reserve a spot, like on the first line, for example to set the status bar color. If you want maximum control, just set the status bar color of every screen manually. This way you do get full customization, along with the benefits of keeping clean, predictable code. Accompanist shall provide u with the most convenient APIs to do this. As far as the gradient background is concerned, it could be achieved with this:

private fun setStatusBarGradient(vararg colors: Int) {
        val gd = GradientDrawable(
            GradientDrawable.Orientation.LEFT_RIGHT, // change per needs
            colors
        )
//        gd.cornerRadius = 0f // change per needs

        val window: Window = this.window
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)

        window.statusBarColor = ContextCompat.getColor(this, android.R.color.transparent)
        window.navigationBarColor =
            ContextCompat.getColor(this, android.R.color.transparent)
        window.setBackgroundDrawable(gd)
    }

I might have taken this from stack, but that was very long ago. Credits to the appropriate owner, although it was definitely not on Compose and was probably in Java. Still, just mentioning.

You can do something different.

// Turn off the decor fitting system windows
WindowCompat.setDecorFitsSystemWindows(window, false)

setContent {
    //...
}

Them apply to the status bar a Transparent color:

DisposableEffect(systemUiController, useDarkIcons) {
    // Update all of the system bar colors to be transparent, and use
    // dark icons if we're in light theme
    systemUiController.setStatusBarColor(
        color = Color.Transparent,
        darkIcons = useDarkIcons
    )
    onDispose {}
}

Then apply the gradient to TopAppBar content:

TopAppBar(
    modifier = Modifier.height(200.dp),
    contentPadding = PaddingValues(all = 0.dp) 
) {
    Box(Modifier.fillMaxSize().background(gradientGreenRed))
}

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM