TextField прерывает создание при использовании с навигацией Jetpack?
Я пытался собрать простое приложение, используя Compose 1.0.0-beta09, Kotlin 1.5.10 и Jetpack Navigation 2.3.4. В приложении есть одно действие и два фрагмента.
Первый (основной) фрагмент / экран (при нажатии на кнопку происходит переход ко второму фрагменту / экрану): Screen One screenshot
Второй фрагмент: / screen: Скриншот второго экрана
Проблема: после взаимодействия (установки курсора) с TextField на первом экране и последующего нажатия кнопки второй экран загружается, но остается пустым (вызывается onCreateView для SecondFragment, но setContent не работает / экран не не перекомпонованы?). Если я не взаимодействую с TextField, проблемы не возникает. Я тестировал эмуляторы с уровнями API 28 и 30, compose 1.0.0-beta0709, Kotlin 1.4.32 и 1.5.10 с аналогичными результатами.
Основные классы:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AndroidViewBinding(ContentMainBinding::inflate)
}
}
}
class FirstFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = ComposeView(inflater.context).apply {
setContent {
FirstScreen( onButtonClick = {
findNavController().navigate(R.id.nav_second_fragment)
})
}
}
}
@Composable
fun FirstScreen(onButtonClick: () -> Unit) {
Column {
Text("Screen One", color = Color.Blue, fontSize = 30.sp)
Button(
onClick = {
onButtonClick() },
content = {
Text(text = "go to Screen Two", color = Color.White)
})
TextField(
value = "",
onValueChange = {},
label = { Text(stringResource(R.string.label_enter_value)) },
)
}
}
class SecondFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = ComposeView(inflater.context).apply {
setContent {
Column {
Text("Screen Two", color = Color.Blue, fontSize = 30.sp)
}
}
}
}
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdk 30
defaultConfig {
applicationId "com.example.composewithnavigation"
minSdk 28
targetSdk 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
useIR = true
}
buildFeatures {
compose true
viewBinding true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
kotlinCompilerVersion '1.5.10'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.5.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation "androidx.compose.ui:ui-viewbinding:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.0-beta01'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.4'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
}
1 ответ
Насколько мне известно, в Compose не рекомендуется использовать фрагменты для навигации. Предполагается, что вы создаете несколько экранов, например, здесь FirstScreen Composable. В любом случае, я думаю, что причина того, что setContent не вызывается, заключается в том, что он вызывается из другого setContent из вашего первого фрагмента. Внутри setContent вы делаете навигационный вызов, который перенаправляет его на второй фрагмент, который снова вызывает setContent. Поскольку второй фрагмент уже будет отображаться внутри setContent Composable FirstScreen, вы фактически вкладываете его, что может не поддерживаться compose (я имею в виду, имеет смысл).
Вот почему мы рекомендуем отказаться от фрагментов и вместо этого использовать Composables, которые не требуют явного вызова setContent.