perf(about): eliminate all-row recomposition on library expand

This commit is contained in:
OneWay committed 2026-09-14 20:04:51 +08:00
1 parent edf6a6074e
commit 214b9f91e4
1 file changed
+25 -15
@@ -1,5 +1,6 @@
package com.example.research.ui.about package com.example.research.ui.about
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
@@ -66,6 +67,15 @@ fun AboutScreen(
} }
var expandedLibraryId by remember { mutableStateOf<String?>(null) } var expandedLibraryId by remember { mutableStateOf<String?>(null) }
var dialogLicense by remember { mutableStateOf<AboutLicense?>(null) } var dialogLicense by remember { mutableStateOf<AboutLicense?>(null) }
val onToggleLibrary = remember {
{ uniqueId: String ->
expandedLibraryId = if (expandedLibraryId == uniqueId) {
null
} else {
uniqueId
}
}
}
Scaffold( Scaffold(
topBar = { topBar = {
@@ -93,24 +103,19 @@ fun AboutScreen(
.semantics { testTagsAsResourceId = true } .semantics { testTagsAsResourceId = true }
.padding(padding) .padding(padding)
) { ) {
item(key = "about_header") { item(key = "about_header", contentType = "about_header") {
AboutHeader(versionName = versionName) AboutHeader(versionName = versionName)
} }
items( items(
items = librariesData?.libraries.orEmpty(), items = librariesData?.libraries.orEmpty(),
key = AboutLibrary::uniqueId, key = AboutLibrary::uniqueId,
contentType = { "about_library" },
) { library -> ) { library ->
AboutLibraryRow( AboutLibraryRow(
library = library, library = library,
licenses = librariesData?.licenses.orEmpty(), licenses = librariesData?.licenses.orEmpty(),
expanded = expandedLibraryId == library.uniqueId, expanded = expandedLibraryId == library.uniqueId,
onToggle = { onToggle = onToggleLibrary,
expandedLibraryId = if (expandedLibraryId == library.uniqueId) {
null
} else {
library.uniqueId
}
},
onLicenseClick = { dialogLicense = it }, onLicenseClick = { dialogLicense = it },
) )
} }
@@ -174,24 +179,29 @@ private fun AboutLibraryRow(
library: AboutLibrary, library: AboutLibrary,
licenses: Map<String, AboutLicense>, licenses: Map<String, AboutLicense>,
expanded: Boolean, expanded: Boolean,
onToggle: () -> Unit, onToggle: (String) -> Unit,
onLicenseClick: (AboutLicense) -> Unit, onLicenseClick: (AboutLicense) -> Unit,
) { ) {
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val website = library.website?.takeIf(String::isNotBlank) val website = library.website?.takeIf(String::isNotBlank)
val source = library.scm?.url?.takeIf(String::isNotBlank) val source = library.scm?.url?.takeIf(String::isNotBlank)
val background by animateColorAsState(
targetValue = if (expanded) {
MaterialTheme.colorScheme.surfaceContainerHighest
} else {
MaterialTheme.colorScheme.surface
},
label = "aboutLibraryRowBackground",
)
Surface( Surface(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.testTag("about_library_row") .testTag("about_library_row")
.semantics { testTagsAsResourceId = true }, .semantics { testTagsAsResourceId = true },
color = if (expanded) { color = background,
MaterialTheme.colorScheme.surfaceContainerHighest onClick = { onToggle(library.uniqueId) }
} else {
MaterialTheme.colorScheme.surface
},
onClick = onToggle
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier