• Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
  • This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

1. Introduction

For example, for composing, I’m not using XML very much. For example, for composing, I don’t know how to handle the status bar, navigation bar immersion, and keyboard occlusion. For those of you who are not aware of these problems, please scroll down to see how to handle them. Must remember to collect, rowed away can never find 😅😅🙈🙈

2. The initial state

Create a project by default, add the following code to the page, in addition to the “content area”, “navigation bar, status bar”

setContent {
      Surface(color = Color(0xFFF74C4C),modifier = Modifier.fillMaxSize()){}
}
Copy the code

For example, for Compose, the color of the status bar is black. For example, for Compose, the color of the status bar is black

3. Think and solve

3.1- Content extends to the status bar

The red background above is a bit obtrusive and inconvenient for comparison, so we use pictures instead of the red background to make the color of the status bar transparent first. Here are three simple ways to set the color of the status bar, the principle is the same, you can use any way

  • Style.xml sets the status bar transparent color
<item name="android:statusBarColor">@android:color/transparent</item>
Copy the code
  • Two: Window set the status bar transparent color
window.statusBarColor = ResourcesCompat.getColor(resources,android.R.color.transparent,null)
Copy the code
  • Three: Systemuicontroller set status bar transparent color

We need this component library: Jetpack comement-STRINGS IST component library

implementation "com.google.accompanist:accompanist-systemuicontroller:<version>"
Copy the code

The code uses the following, and the principle is the same

val systemUiController = rememberSystemUiController()
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = false)
Copy the code

To extend the content to the status bar, use the following method:

WindowCompat.setDecorFitsSystemWindows(window,false)
Copy the code

3.2- Status bar occlusion list problem

Above we use the image to see, the effect is still good, if not the image, we are the list, this time the first content is not out of the screen? If the list is long enough, the last item won’t be fully displayed because the first item pops out of the status bar





The list of“The First” and “The Last”
They don’t display properly

Let’s solve this problem step by step. Let’s solve the problem of the status bar blocking the content of the first item; We need to have a status bar as high as the padding to keep the margin safe. When we use the LazyColumn, we see the contentPadding property inside: padding for the entire content, not the individual item;

For Compose, how to convert px to DP and dp to px

So how do we get the height of the status bar? In Compose there are two ways to get it:

// Method 1: Height of the system status bar
fun Resources.getStatusBarHeight(a):Int {
    var statusBarHeight = 0
    val resourceId = getIdentifier("status_bar_height"."dimen"."android")
    if(resourceId >0 ){
        statusBarHeight = getDimensionPixelSize(resourceId)
    }
    return statusBarHeight
}

// Method 2: Height of the system status bar
//1. Rely on the lib library first
implementation "com.google.accompanist:accompanist-insets:<version>"
/ / 2. Rely on lib library, using ProvideWindowInsets can access LocalWindowInsets. Current value
// The value is essentially passed through CompositionLocalProvider
ProvideWindowInsets {
    // The return type is PaddingValues. Print to see the height of the status bar
    rememberInsetsPaddingValues(LocalWindowInsets.current.statusBars)
}
Copy the code

The following is an example:

ProvideWindowInsets {
    // The height of the status bar
    // Note: PaddingValues are set for all four directions
    /*val sbPaddingValues = PaddingValues(with(LocalDensity.current) { LocalContext.current.resources.getStatusBarHeight().toDp() })*/
    
    // Status bar height obtained in Method 2
    PaddingValues = 0; PaddingValues = 0; PaddingValues = 0
    val sbPaddingValues = rememberInsetsPaddingValues(LocalWindowInsets.current.statusBars)
    LazyColumn(modifier = Modifier.fillMaxSize()
        .background(Color(0xFFDA8E70)),
        contentPadding = sbPaddingValues
    ) {
        items(12) { index ->
            Text(
                text = "Item:$index", color = Color.Black, fontSize = 20.sp,
                modifier = Modifier.padding(5.dp).height(60.dp)
            )
            Divider()
        }
    }
}
Copy the code



Troubleshoot the status bar occlusion problem

We can see the status bar will no longer keep out, but the navigation bar will keep out, we are using the above way two, only the top value, setting is not recommended four directions are the status bar height, set margins will affect other interface element, so how to correctly make the navigation bar at the bottom of the list is not covered in the last item? Please look down

3.3- Navigation bar occlusion list problem

After seeing the status bar occlusion above, isn’t the navigation bar the same way? Slightly different, we can’t access the status bar any more with resId, so we’ll use LocalWindowInsets instead

ProvideWindowInsets {
    // Get the height of the navigation bar
    val navPaddingValues = rememberInsetsPaddingValues(LocalWindowInsets.current.navigationBars)
    LazyColumn(modifier = Modifier
        .fillMaxSize()
        .background(Color(0xFFDA8E70)), contentPadding = navPaddingValues ) { ...... }}Copy the code



Handle the navigation bar occlusion problem

Some of you might see here and suddenly say, why is the bottom so far away? Normal? Please take a closer look. Each item has the same height. It is normal to take a closer look.

Let’s set the background color of the navigation bar to transparent color, and see the effect again, the effect is more obvious

val systemUiController = rememberSystemUiController()
// Set the navigation bar transparent color
systemUiController.setNavigationBarColor(Color.Transparent, darkIcons = false)
Copy the code



Handle the navigation bar occlusion problem

3.4- Handle status bar and navigation bar occlusion simultaneously

We use LocalWindowInsets. Current. SystemBars to contentPadding assignment, it can obtain “the status bar, a navigation bar” at the same time of the height, to prevent the shade, this method does not contain the keyboard height




At the same time processing
Status bar and navigation barKeep out the problem

3.5 Modifier

Why use this method? NavigationBarPadding () and statusBarsPadding() are both navigationBarPadding() and statusBarsPadding(). Or just add systemBarsPadding()(this method does not contain keyboard height) to handle occlusion, essentially using Modifier.padding internally

ProvideWindowInsets {
    LazyColumn(modifier = Modifier
        .fillMaxSize()
        .background(Color(0xFFDA8E70)).systemBarsPadding() ) { ...... }}Copy the code

However, the Modifier does not extend the content below the Status bar and navigation bar. The overall view is above the status bar and navigation bar





Modifier.systemBarsPadding()The effect

3.6- Handle keyboard occlusion

We mentioned keyboard height, so what’s wrong with the keyboard? Let’s take a look at an example like this, taking the classic text input field as an example

@Composable
fun LoginTextField(
    name : String,
    updateName : (String) - >Unit,
    pwd : String,
    updatePwd : (String) - >Unit
){
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Bottom,
        // Make it appear above the navigation bar first, otherwise it will appear below it
        // Because we set the content extension above the article
        modifier = Modifier.fillMaxSize().navigationBarsPadding()
    ) {
        OutlinedTextField(
            value = name,
            onValueChange = updateName ,
            label = { Text("Username") },
            placeholder = { Text(text = "Please enter user name")},...) OutlinedTextField( value = pwd, onValueChange = updatePwd , label = { Text("Password") },
            placeholder = { Text(text = "Please enter your password")},... keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword),// Hide the password content
            visualTransformation = PasswordVisualTransformation(The '*'))}}// Use:
ProvideWindowInsets {
    var name by rememberSaveable { mutableStateOf("")}val updateName = { _name : String ->
        name = _name
    }
    var password by rememberSaveable { mutableStateOf("")}val updatePassword = { _pwd : String ->
        password = _pwd
    }
    LoginTextField(
        name = name,
        updateName = updateName,
        pwd = password,
        updatePwd = updatePassword
    )
}
Copy the code

Take a look at the GIF of the problem with the above example:




Keyboard occlusion problem

It is obvious that we need to know the height of the keyboard, can not keep out, we can use the Modifier. NavigationBarsWithImePadding () to achieve security does not keep out, automatically calculate the keyboard a maximum opening and closing and the height of the navigation bar;

When we look at the effect of the substitution, one thing to keep in mind is that you should not forget the androidmanifest.xml because you are using Compose. Be sure to configure the following properties for your Activity:

android:windowSoftInputMode="adjustResize"
Copy the code

If you have any doubts, you can leave a message in the comments section




Keyboard occlusion problem
repair

4. To summarize

(1). We need the following two Lib libraries to help us

implementation "com.google.accompanist:accompanist-systemuicontroller:<version>"
implementation "com.google.accompanist:accompanist-insets:<version>"
Copy the code

(2). The status bar and navigation bar change color

val systemUiController = rememberSystemUiController()
// We need to dynamically update the icon color to take into account the background color
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = true)
systemUiController.setNavigationBarColor(Color.Transparent, darkIcons = false)

// Or use, directly unify the two columns
systemUiController.setSystemBarsColor(.....)
Copy the code

(2). If it’s a list that needs content to extend beyond the status bar and navigation bar, you can use the contentPadding property to set the content margin

ProvideWindowInsets {
    // Both the navigation bar and the status bar can be extended
    val paddingValues = rememberInsetsPaddingValues(LocalWindowInsets.current.systemBars)
    LazyColumn(modifier = Modifier
        .fillMaxSize()
        .background(Color(0xFFDA8E70)), contentPadding = navPaddingValues ) { ...... }}Copy the code

(3). If the Modifier is used to deal with the occlusion problem, the content cannot be extended to the “Status bar and navigation bar”

Modifier.navigationBarsPadding()
Modifier.statusBarsPadding()
Modifier.systemBarsPadding()
Copy the code

(4). Keyboard occlusion problem

AndroidManifer. XML configuration: android: windowSoftInputMode ="adjustResize"
// Prevent keyboard blocking, text input box
Modifier.navigationBarsWithImePadding()
Copy the code

Use the Modifier inside the listing. Use the modifiers inside the listing. Use the modifiers inside the listing. For those of you interested, check out the calculateItemsOffsets method in LazyListMeasure


Previous articles recommended: 1.Android cross-process transmission of the big picture thinking and implementation — attached principle analysis 2. For example, Jetpack Compose is composed for bringToFront, which is composed for Android users. For example, Jetpack Compose is composed for bringToFront 5. How to use and principle of Jetpack App Startup 6.Jetpack comement-STRINGS IST Kit 7 Source code analysis | ThreadedRenderer null pointer, the Choreographer meet 8, by the way. Source code analysis | events is how to the Activity? 9. CountDownLatch source code 10