https://kotlinlang.org logo
#compose-android
Title
# compose-android
b

bryankeltonadams

10/03/2023, 8:49 PM
Is this normal behavior for a Jetpack Compose app when opening and closing a keyboard? It happens on my main app on a dark theme (white background flashing) and then this is an app with just MainActivity.kt not kotlin but kotlin colored
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:06 PM
Please keep long code snippets and attachments to the thread to avoid cluttering the main channel.
🙌 1
b

bryankeltonadams

10/03/2023, 9:07 PM
Copy code
@AndroidEntryPoint
class MainActivity : ComponentActivity() {

    private var backPressedTime = System.currentTimeMillis()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                FishbowlApp()
            }
//            FishbowlDriveTheme {
//                FishbowlApp()
//            }
        }
}

@Composable
fun FishbowlApp(
    viewModel: FishbowlAppViewModel = hiltViewModel(),
    appState: FishbowlAppState = rememberFishbowlAppState(
        drawerState = drawerStateWithKeyboardHiding(),
        clearSession = viewModel::clearSession,
    ),
) {
    val textFieldValue = remember { mutableStateOf("") }
    Scaffold(
        modifier = Modifier
            .fillMaxSize(),
        containerColor = Color.Red
    ) { paddingValues ->
        TextField(
            value = textFieldValue.value,
            onValueChange = { textFieldValue.value = it },
            modifier = Modifier.padding(paddingValues)
        )

    }
}
gratitude thank you 1
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:07 PM
What is your soft input mode and decor fits system windows settings?
b

bryankeltonadams

10/03/2023, 9:07 PM
white flashing.webm
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:08 PM
And are you using compose window insets apis?
b

bryankeltonadams

10/03/2023, 9:08 PM
@Zach Klippenstein (he/him) [MOD]
Copy code
<activity
    android:name=".MainActivity"
    android:exported="true"
    android:theme="@android:style/Theme.Material.Light.NoActionBar"
    android:windowSoftInputMode="adjustResize"
    >

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

</activity>
It seems when I change android:theme to Material.Dark it will flash black instead of white. But my main app is wrapped in a Material Theme like this
Copy code
setContent {
    MaterialTheme {
        Scaffold(containerColor = Color.Red) { paddingValues ->
            val textFieldValue = remember { mutableStateOf("") }
            TextField(value = textFieldValue.value, onValueChange = {
                textFieldValue.value = it
            }, modifier = Modifier.padding(paddingValues))
        }
    }
}
@Zach Klippenstein (he/him) [MOD] I don't believe I am.
@Zach Klippenstein (he/him) [MOD] I created a fresh Jetpack Compose sample proejct and added adjustResize and it does the same thing.
Copy code
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="<http://schemas.android.com/apk/res/android>"
    xmlns:tools="<http://schemas.android.com/tools>">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:windowSoftInputMode="adjustResize"
            android:theme="@style/Theme.Test">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
Copy code
package com.bryankeltonadams.test

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import com.bryankeltonadams.test.ui.theme.TestTheme

class MainActivity : ComponentActivity() {
    @OptIn(ExperimentalMaterial3Api::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                // A surface container using the 'background' color from the theme
                Scaffold(
                    modifier = Modifier.fillMaxSize(),
                    containerColor = Color.Red
                ) { paddingValues ->
                    val textFieldValue = remember { mutableStateOf("") }
                    TextField(
                        value = textFieldValue.value,
                        onValueChange = { textFieldValue.value = it },
                        modifier = Modifier.padding(paddingValues)
                    )
                }
            }
        }
    }
}
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:17 PM
you don’t have to tag me in the thread, i automatically get notifications since i replied 🙂
1
So you’ll want to call
WindowCompat.setDecorFitsSystemWindows(window, false)
in your
onCreate
and then pass
Modifier.imePadding()
to your
Scaffold
b

bryankeltonadams

10/03/2023, 9:23 PM
should I remove the theme in the AndroidManifest, seems like it doesn't really do anything if I'm wrapping my main composable with my AppTheme
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:24 PM
i don’t think you really need it in a fully-compose app, no
actually i think you can also disable decorFitsSystemWindows in XML
b

bryankeltonadams

10/03/2023, 9:27 PM
it looks like everything is working, I haven't done anything with decorFitsSystemWindows.
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:28 PM
so removing the xml theme fixed it?
b

bryankeltonadams

10/03/2023, 9:29 PM
sorry, the theme didn't seem to matter. but adding the setDecorFitsSystemWindows to false and passing the imePadding to the MainApp Scaffold as well as leaving adjustResize in the AndroidManifest seemed to work.
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:29 PM
ok yep that sounds right
it’s unfortunate there are so many steps, but welcome to android 😅
b

bryankeltonadams

10/03/2023, 9:31 PM
Seriously, are there any other things I should look out for? Would you recommend disabling decorFitsSystemWindows in xml? I just did it in MainActivity only.
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:31 PM
it doesn’t really matter
the java api lets you make the decision whether to do it at runtime – for a new, compose-only app i would probably set it in xml just to keep the activity class cleaner
b

bryankeltonadams

10/03/2023, 9:33 PM
is android:windowSoftInputMode="adjustResize" needed in AndroidManifest.xml anymore based on adding the imePadding and the setDecorFitsSystemWindows in MainActivity? I removed it just to see and I can't notice a difference in behavior on my scrollable forms.
I believe the reason I added it in the first place was because I have these really long forms that I have in a scrollable column, and without it I was getting weird behavior, but it seems like the behavior is the same without the flickering with the imePadding + the MainActivity change you mentioned.
without any of the changes you mentioned, and no adjustResize, I'm unable to scroll all the way down my form with the IME open. but with adjustResize I can, but with the changes you mentioned and adjustResize or without I can't. So I'm wondering if I even need adjustResize anymore.
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:41 PM
you should still set soft input mode to be adjustResize
otherwise you might get adjustPan as a default on some devices at least, and that is the worst
b

bryankeltonadams

10/03/2023, 9:41 PM
Okay, sounds good. 🙂 thanks
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:42 PM
1. softInputMode = adjustResize 2. decorFitsSystemWindows = false 3. Modifier.imePadding
b

bryankeltonadams

10/03/2023, 9:42 PM
sweet, that's the magic combo then!
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:42 PM
yep
b

bryankeltonadams

10/03/2023, 9:42 PM
Thanks a ton for your help, the app experience looks a lot less jumpy and choppy when opening and closing the keyboard now
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:43 PM
The window insets animation stuff was also backported all the way down to API 21 so it should look nice all the way back.
b

bryankeltonadams

10/03/2023, 9:44 PM
Sweet, thank goodness Product Owner allowed us to set API 28 as the min. 🙂
😍 1
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 9:44 PM
lucky!
b

bryankeltonadams

10/03/2023, 9:46 PM
Perhaps you might know about this Zach. But in my Theme.kt file
Copy code
if (!view.isInEditMode) {
    SideEffect {
        val activity = view.context as Activity
        activity.window.statusBarColor = colors.backgroundPrimary.toArgb()
        WindowCompat.getInsetsController(activity.window, view).isAppearanceLightStatusBars =
            !darkTheme
        WindowCompat.getInsetsController(
            activity.window,
            view
        ).isAppearanceLightNavigationBars = !darkTheme
    }

}
which has to do with some WindowCompat stuff as well. should I clump the setDecorFitsSystemWindows in there as well, or do you think this stuff is inappropriate to be in the Theme.kt in the first place and should be moved to MainActivity. or are both fine where they are in different places?
z

Zach Klippenstein (he/him) [MOD]

10/03/2023, 10:00 PM
it doesn’t matter technically where it is. It could depend on a number of factors, but in general do whatever makes sense for your codebase. Maybe you want everything in the same place – whether that’s code or xml is up to you
One thing I would note though is it’s probably not necessary to put that configuration code in a
SideEffect
– it will run on every recomposition. Instead use a
DisposableEffect
to only run it once
b

bryankeltonadams

10/03/2023, 10:01 PM
Ah okay!
s

Stylianos Gakis

10/04/2023, 6:29 AM
https://developer.android.com/jetpack/androidx/releases/activity#1.8.0-alpha03 .setupEdgeToEdge() should be doing the decorFitsSystemWindows part for you in the latest activity dependency. Along with making your system bars transparent etc. It's supposed to be a more convenient API rather than making those changes in your theme.xml
👍 1
z

Zoltan Demant

10/04/2023, 1:17 PM
Is
setupEdgeToEdge
the precursor to
enableEdgeToEdge
? Sounds like it, but no mention in the changelog afaik blob thinking upside down
i

Ian Lake

10/04/2023, 1:25 PM
Yes, it was renamed to
enableEdgeToEdge
in one of the later alphas (but you're right that rename missed the release notes)
🙏🏽 1
z

Zach Klippenstein (he/him) [MOD]

10/04/2023, 3:02 PM
Oh nice
z

Zoltan Demant

10/05/2023, 3:36 AM
EdgeToEdge -
ComponentActivity.setUpEdgeToEdge()
has been added to easily set up the edge-to-edge display in a backward-compatible manner. 😄
c

Colton Idle

10/05/2023, 6:29 AM
Yeah, I'm waiting for that to move to stable and the docs to update. But for now, this video pretty much tells you everything you need to do. Thanks alex!

https://www.youtube.com/watch?v=mlL6H-s0nF0

🎉 1
b

bryankeltonadams

10/30/2023, 12:09 AM
Just added EdgeToEdge, is this what I should expect, or should I be doing something to make the color of the bottomBar extend to the Navigation bar at the bottom?
s

Stylianos Gakis

10/30/2023, 12:19 PM
Which bottom bar are you using? The m3 handles this automatically, where the bottom sheet actyally does draw behind the system bars, and it uses the right color, and uses internal padding to move the contents, you could look into that for inspiration Your bottom sheet seems like does not put the system bars padding as content padding, but as padding to the entire composable
c

Colton Idle

10/30/2023, 3:41 PM
As long as you can draw under it then it's working correctly. Like if you have a blank screen with a column and can draw something in the top middle and bottom then you're setup correctly.
b

bryankeltonadams

10/30/2023, 4:01 PM
Stylianos the first screen is not a bottom sheet, I was just in the middle of refactoring from global top app bar to app bar per screen and haven't given the screen an app bar yet. The first screen is a regular page and then the second screen is me extending my drawer.
It also is a material 3 bottom bar.
Actually it's a Material3 scaffold but the content of the bottomBar are all material3 components, I'm not using any bottomBar specific composables.
i

Ian Lake

10/30/2023, 4:42 PM
It is Material3's
NavigationBar
that supports window insets by default (note the
windowInsets
parameters): https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#NavigationBar(androidx.comp[…]ndowInsets,kotlin.Function1)
b

bryankeltonadams

10/30/2023, 4:54 PM
I see. My bottomBar is just a button for allowing the user to confirm their filter selection on the screen and to dismiss the screen and have those filters applied. Does the screenshot look fine, or would you expect the black from the bottomBar to bleed all the way to the bottom so that it's not grey, black, grey.
i

Ian Lake

10/30/2023, 4:55 PM
I would expect the black to bleed all the way to the bottom (that's what
NavigationBar
does - insets in the buttons, but lets the background fill the inset area entirely)
b

bryankeltonadams

10/30/2023, 5:00 PM
Sounds good! I'll give NavigationBar a try, I suppose I wrote it off as I imagined it being used exclusively for a global bar with multiple buttons to swap between screens, but I guess really it can b e used for anything.
I tried replacing my whole bottomBar in my scaffold with a placeholder navigationBar with a button set to fillMaxWidth, it looks the same. Perhaps I have something setup wrong?
Copy code
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    installSplashScreen()
    enableEdgeToEdge()

    setContent {
        FishbowlDriveTheme {
            FishbowlApp()
        }
    }
Copy code
Scaffold(bottomBar = {
        NavigationBar {
            Button(modifier = Modifier.fillMaxWidth(), onClick = onSeeResults) {
                Text(text = stringResource(id = R.string.inventory_filter_see_results))
            }
        }
//            FbBottomPrimaryActionBar(
//                title = stringResource(id = R.string.inventory_filter_see_results),
//                onClick = onSeeResults,
//            )
    },
s

Stylianos Gakis

10/30/2023, 9:20 PM
Good to check that you are not by accident using the material2 NavigationBar, which does not handle insets automatically like that. Also check that you are using the material3 scaffold, since that may be playing a role here too. Also good to check that your Scaffold does not get inset already by some component higher up for whatever reason. I’d put a red border modifier on the scaffold itself to see where its actual bounds are. Same for the NavigationBar.
b

bryankeltonadams

10/30/2023, 9:24 PM
It's the Material 3 scaffold and Material 3 NavigationBar. Okay I'll give that a try.
Red border on the Scaffold of the screen and green border on the NavigationBar
keyboard open, also do you happen to know how to get the navigationBar to be covered by the keyboard? I am using adjustResize for my single activity. But we have a few spots in the app where we have bottomBars that we want to be covered by the ime.
Perhaps I need to just check whether the keyboard is visible, and then hide that ui element if it is?