是否有任何工具或方法可以测试 Jetpack compose 中一段代码是否发生重组?
android kotlin android-jetpack-compose compose-recomposition
我们有官方文档展示了 Compose 中向后写入的示例:
@Composable
fun BadComposable() {
var count by remember { mutableStateOf(0) }
// Causes recomposition on click
Button(onClick = { count++ }, Modifier.wrapContentSize()) {
Text("Recompose")
}
Text("$count")
count++ // Backwards write, writing to state after it has been read
}
Run Code Online (Sandbox Code Playgroud)
我很清楚,更新State可组合对象内的对象会导致向后写入。这种向后写入的规定效果是我们最终会得到无限的重组循环。
然而,有趣的是,count++可组合项底部的增量操作不会触发无限循环的重组。基本上,在 的第一个组合中,一切看起来都很好,因为即使我们在 的主体末尾BadComposable进行了更新,也没有额外的重新组合。countBadComposable
但是,如果您随后按下Button,则回调count++内的增量操作onClick将触发无限的重组循环。
为什么我们必须按下 来Button触发无限循环的重组?
我期望读取一个值并在可组合项的主体中更新它以获得这样的效果就足够了。
Jorge Castillo(感谢您的帮助)暗示这可能是因为状态对象的第一次更新发生在注册
count初始重组范围之前。这个想法的来源。BadComposable
android android-jetpack android-jetpack-compose compose-recomposition
我正在尝试使用 Jetpack Compose 在我的 Android 应用程序中创建天空视图。我想将它显示在Card带有固定的height. 在晚上,卡片背景变成深蓝色,我希望天空中散布一些闪烁的星星。
为了创建星星闪烁动画,我使用了一个InfiniteTransition对象和一个应用于多个s 的scale属性。这些s 在 a 内部创建,然后使用循环随机传播。我正在使用的完整代码如下所示:animateFloatIconIconBoxWithConstraintsfor
@Composable
fun NightSkyCard() {
Card(
modifier = Modifier
.height(200.dp)
.fillMaxWidth(),
elevation = 2.dp,
shape = RoundedCornerShape(20.dp),
backgroundColor = DarkBlue
) {
val infiniteTransition = rememberInfiniteTransition()
val scale by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = 0f,
animationSpec = infiniteRepeatable(
animation = tween(1000),
repeatMode = RepeatMode.Reverse
)
)
BoxWithConstraints(
modifier = Modifier.fillMaxSize()
) {
for (n in …Run Code Online (Sandbox Code Playgroud) kotlin android-jetpack-compose jetpack-compose-animation compose-recomposition
我正在尝试积极观察软键盘的可见性,目前,我正在尝试使用
WindowInsets.isImeVisible
Run Code Online (Sandbox Code Playgroud)
但我似乎无法观察到它的状态变化。有人提到使用
ViewCompat.setOnApplyWindowInsetsListener()
Run Code Online (Sandbox Code Playgroud)
但我不太明白如何实现这个来观察键盘的可见性。
我已经设法使用
WindowInsets.isImeVisible
Run Code Online (Sandbox Code Playgroud)
但是,它仅适用于我导航到该页面并且键盘自动打开时。
android android-softkeyboard kotlin android-jetpack-compose compose-recomposition
我正在使用 composeLazyColumn和 viewModel 通过在我的 viewModel 中更新列表项:
data class ContactsListUiState(
val contacts: MutableList<Contact>
)
@HiltViewModel
class ContactsViewModel @Inject constructor(savedStateHandle: SavedStateHandle) : ViewModel() {
private val _contactsListUiState = MutableStateFlow(ContactsListUiState(mutableListOf()))
val contactsListUiState: StateFlow<ContactsListUiState> = _contactsListUiState.asStateFlow()
private fun updateContactsList(newContacts: MutableList<Contact>) {
_contactsListUiState.update{ currentState ->
currentState.copy(
contacts = newContacts
)
}
}
Run Code Online (Sandbox Code Playgroud)
这样我的updateContactsList()函数就会更新 stateFlow,并且我应该在collectAsStateWithLifecycle()可组合函数内部收集联系人列表MainActivity
@OptIn(ExperimentalLifecycleComposeApi::class, ExperimentalFoundationApi::class)
@Composable
fun ContactsListScreen(
navController: NavController,
modifier: Modifier = Modifier
) {
Log.d("ViewModel", "ContactsListScreen recomposed")
val uiState by contactsViewModel.contactsListUiState.collectAsStateWithLifecycle()
Box(modifier = modifier) { …Run Code Online (Sandbox Code Playgroud) android kotlin android-jetpack-compose kotlin-stateflow compose-recomposition
我有以下可组合函数。它是一个简单的登录屏幕,包含用户名、密码和提交按钮。
如果用户单击提交按钮时用户名或密码字段为空,则会显示小吃栏。但是,它在第一次点击时有效,但后续点击无效。
我认为单击按钮将强制可组合项重新组合,并且如果需要显示小吃栏,则 LaunchEffect 键将为 true。
@Composable
fun Login() {
var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
val scaffoldState = rememberScaffoldState()
var shouldShowSnackBar by remember { mutableStateOf(false) }
println("LoginScreen")
LaunchedEffect(key1 = shouldShowSnackBar, block = {
println("ShouldShowSnackBar")
scaffoldState.snackbarHostState.showSnackbar(
message = "Please enter a username and password",
duration = SnackbarDuration.Short
)
})
Scaffold(
scaffoldState = scaffoldState
) {
Column(modifier = Modifier.fillMaxWidth()) {
OutlinedTextField(
label = {
Text(text = "Username")
},
value = username,
onValueChange = …Run Code Online (Sandbox Code Playgroud) 我正在尝试Navigation使用单个活动和多个Composable屏幕来实现。
这是我的NavHost:
@Composable
@ExperimentalFoundationApi
fun MyNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
startDestination: String = HOME.route,
viewModelProvider: ViewModelProvider,
speech: SpeechHelper
) = NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
composable(route = HOME.route) {
with(viewModelProvider[HomeViewModel::class.java]) {
HomeScreen(
speech = speech,
viewModel = this,
modifier = Modifier.onKeyEvent { handleKeyEvent(it, this) }
) {
navController.navigateTo(it)
}
}
}
composable(route = Destination.VOLUME_SETTINGS.route) {
VolumeSettingsScreen(
viewModelProvider[VolumeSettingsViewModel::class.java]
) { navController.navigateUp() }
}
} …Run Code Online (Sandbox Code Playgroud) android infinite-loop android-jetpack-compose jetpack-compose-navigation compose-recomposition
mutablestate我有一个ViewModel正在尝试在可组合项中设置和访问的内容。当我使用委托属性时,remember它正在工作,但是在 viewModel 中创建它并在 compose 中访问它之后,变量的状态为空如何在 viewModel 中使用状态
当状态位于组合内部时,一切工作正常
var mSelectedText by remember { mutableStateOf("") }
Run Code Online (Sandbox Code Playgroud)
但是当我从 viewModel 更改中使用它并设置我的 OutlinedTextField value = mainCatTitle 和 onValueChange = {mainCatTitle = it} 时,所选标题不会显示在 OutlinedTextField 中为空
private val _mainCatTitle = mutableStateOf("")
val mainCatTitle: State<String> = _mainCatTitle
Run Code Online (Sandbox Code Playgroud)
我的可组合项
var mSelectedText by remember { mutableStateOf("") }
var mainCatTitle = viewModel.mainCatTitle.value
Column(Modifier.padding(20.dp)) {
OutlinedTextField(
value = mainCatTitle,
onValueChange = { mainCatTitle = it },
modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned { coordinates ->
mTextFieldSize …Run Code Online (Sandbox Code Playgroud) android kotlin android-jetpack-compose compose-recomposition
我正在为我的应用程序创建一个自定义滑块控件,但如果不添加一些丑陋的黑客,我无法避免不必要的重组......
CustomSlider1是一个当值改变时重组其所有子组件的组件;CustomSlider2是我想出的,但代码似乎不正确,所以有人可以告诉我我做错了什么CustomSlider1以及是否CustomSlider2确实正确?
这两个组件之间的区别基本上是我通过 lambda 读取值,并将组件添加到ScopedSlider可组合项中。
我正在使用recomposeHighlighter来显示重组。
这是代码:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestTheme {
Column {
var value by remember {
mutableStateOf(50f)
}
CustomSlider1("Custom Slider", value, 50f, true, { value = it }, 0f..100f, 5)
Spacer(modifier = Modifier.padding(10.dp))
CustomSlider2("Custom Slider 2", { value }, 50f, true, { value = it }, 0f..100f, 5)
}
}
}
}
} …Run Code Online (Sandbox Code Playgroud) 当我修改列表中对象的属性时,UI 不会更新
\n我的代码\xef\xbc\x9a
\n @OptIn(ExperimentalFoundationApi::class)\n @Composable\n fun ContactCard(\n ) {\n var stateList = remember {\n mutableStateListOf<ListViewData>()\n }\n viewModel!!.recordRespListLiveData!!.observe(this) { it ->\n it.forEach {\n stateList.add(ListViewData(false, it))\n }\n }\n LazyColumn() {\n stateList.forEachIndexed { index, bean ->\n stickyHeader() {\n Box(Modifier.clickable {\n stateList[index].visible = true\n }) {\n ContactNameCard(bean.data.contact, index)\n }\n }\n items(bean.data.records) { data ->\n if (bean.visible) {\n RecordItemCard(record = data)\n }\n }\n }\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n当我单击框时,可见设置为 true,但 RecordItemCard 不显示\xef\xbc\x8c为什么\xef\xbc\x9f
\nandroid android-jetpack-compose lazycolumn compose-recomposition