Skip to content

Commit 2ccc40d

Browse files
committed
library: Optimize some recomposition issues
1 parent 0df892c commit 2ccc40d

File tree

8 files changed

+263
-269
lines changed

8 files changed

+263
-269
lines changed

example/build.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ android {
150150
(this as BaseVariantOutputImpl).outputFileName = "$appName-v$versionName($versionCode)-$name.apk"
151151
}
152152
}
153-
resources.excludes += "**"
154153
}
155154
buildTypes {
156155
release {
@@ -166,6 +165,12 @@ android {
166165
}
167166
}
168167

168+
androidComponents {
169+
onVariants(selector().withBuildType("release")) {
170+
it.packaging.resources.excludes.add("**")
171+
}
172+
}
173+
169174
compose.desktop {
170175
application {
171176
mainClass = "Main_desktopKt"

iosApp/iosApp/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<key>CFBundleShortVersionString</key>
1818
<string>1.0.4</string>
1919
<key>CFBundleVersion</key>
20-
<string>484</string>
20+
<string>485</string>
2121
<key>LSRequiresIPhoneOS</key>
2222
<true/>
2323
<key>CADisableMinimumFrameDurationOnPhone</key>

miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/basic/ListPopup.kt

Lines changed: 90 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -75,53 +75,56 @@ fun ListPopup(
7575
) {
7676
if (!show.value) return
7777

78-
val currentOnDismissRequest by rememberUpdatedState(onDismissRequest)
79-
val currentContent by rememberUpdatedState(content)
80-
81-
var offset by remember { mutableStateOf(IntOffset.Zero) }
8278
val density = LocalDensity.current
8379
val layoutDirection = LocalLayoutDirection.current
8480

85-
val getWindowSizeState = rememberUpdatedState(getWindowSize())
86-
var windowSize by remember { mutableStateOf(IntSize(getWindowSizeState.value.width, getWindowSizeState.value.height)) }
81+
val currentWindowSize = getWindowSize()
82+
var windowSize by remember { mutableStateOf(IntSize(currentWindowSize.width, currentWindowSize.height)) }
8783
var parentBounds by remember { mutableStateOf(IntRect.Zero) }
8884

89-
val windowBounds = with(density) {
90-
IntRect(
91-
left = WindowInsets.displayCutout.asPaddingValues(density).calculateLeftPadding(layoutDirection).roundToPx(),
92-
top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding().roundToPx(),
93-
right = windowSize.width -
94-
WindowInsets.displayCutout.asPaddingValues(density).calculateRightPadding(layoutDirection).roundToPx(),
95-
bottom = windowSize.height -
96-
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding().roundToPx() -
97-
WindowInsets.captionBar.asPaddingValues().calculateBottomPadding().roundToPx()
98-
)
99-
}
100-
101-
var popupContentSize by remember { mutableStateOf(IntSize.Zero) }
85+
Layout(
86+
modifier = Modifier.onGloballyPositioned { childCoordinates ->
87+
childCoordinates.parentLayoutCoordinates?.let { parentLayoutCoordinates ->
88+
val positionInWindow = parentLayoutCoordinates.positionInWindow()
89+
parentBounds = IntRect(
90+
left = positionInWindow.x.toInt(),
91+
top = positionInWindow.y.toInt(),
92+
right = positionInWindow.x.toInt() + parentLayoutCoordinates.size.width,
93+
bottom = positionInWindow.y.toInt() + parentLayoutCoordinates.size.height
94+
)
95+
}
96+
}
97+
) { _, _ -> layout(0, 0) {} }
10298

103-
val popupMargin = remember(popupPositionProvider, density, layoutDirection) {
104-
val popupMarginsPd = popupPositionProvider.getMargins()
99+
val popupMargin = remember(popupPositionProvider, layoutDirection, density) {
100+
val pd = popupPositionProvider.getMargins()
105101
with(density) {
106102
IntRect(
107-
left = popupMarginsPd.calculateLeftPadding(layoutDirection).roundToPx(),
108-
top = popupMarginsPd.calculateTopPadding().roundToPx(),
109-
right = popupMarginsPd.calculateRightPadding(layoutDirection).roundToPx(),
110-
bottom = popupMarginsPd.calculateBottomPadding().roundToPx()
103+
left = pd.calculateLeftPadding(layoutDirection).roundToPx(),
104+
top = pd.calculateTopPadding().roundToPx(),
105+
right = pd.calculateRightPadding(layoutDirection).roundToPx(),
106+
bottom = pd.calculateBottomPadding().roundToPx()
111107
)
112108
}
113109
}
114110

115-
val transformOrigin = remember(parentBounds, popupMargin, windowSize, density, alignment) {
116-
val xInWindow = if (alignment in listOf(
117-
PopupPositionProvider.Align.Right,
118-
PopupPositionProvider.Align.TopRight,
119-
PopupPositionProvider.Align.BottomRight,
120-
)
121-
) {
122-
parentBounds.right - popupMargin.right - with(density) { 64.dp.roundToPx() }
123-
} else {
124-
parentBounds.left + popupMargin.left + with(density) { 64.dp.roundToPx() }
111+
val windowBounds = with(density) {
112+
IntRect(
113+
left = WindowInsets.displayCutout.asPaddingValues().calculateLeftPadding(layoutDirection).roundToPx(),
114+
top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding().roundToPx(),
115+
right = windowSize.width - WindowInsets.displayCutout.asPaddingValues().calculateRightPadding(layoutDirection).roundToPx(),
116+
bottom = windowSize.height - WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
117+
.roundToPx() - WindowInsets.captionBar.asPaddingValues().calculateBottomPadding().roundToPx()
118+
)
119+
}
120+
121+
val transformOrigin = remember(parentBounds, popupMargin, windowSize, alignment, density) {
122+
val xInWindow = when (alignment) {
123+
PopupPositionProvider.Align.Right,
124+
PopupPositionProvider.Align.TopRight,
125+
PopupPositionProvider.Align.BottomRight -> parentBounds.right - popupMargin.right - with(density) { 64.dp.roundToPx() }
126+
127+
else -> parentBounds.left + popupMargin.left + with(density) { 64.dp.roundToPx() }
125128
}
126129
val yInWindow = parentBounds.top + parentBounds.height / 2 - with(density) { 56.dp.roundToPx() }
127130
safeTransformOrigin(
@@ -130,96 +133,69 @@ fun ListPopup(
130133
)
131134
}
132135

133-
// Anchor point for the popup
134-
Layout(
135-
modifier = Modifier.onGloballyPositioned { childCoordinates ->
136-
val parentLayoutCoordinates = childCoordinates.parentLayoutCoordinates
137-
if (parentLayoutCoordinates != null) {
138-
val positionInWindow = parentLayoutCoordinates.positionInWindow()
139-
parentBounds = IntRect(
140-
left = positionInWindow.x.toInt(),
141-
top = positionInWindow.y.toInt(),
142-
right = positionInWindow.x.toInt() + parentLayoutCoordinates.size.width,
143-
bottom = positionInWindow.y.toInt() + parentLayoutCoordinates.size.height
144-
)
145-
}
146-
val newUtilWindowSize = getWindowSizeState.value
147-
val newIntSize = IntSize(newUtilWindowSize.width, newUtilWindowSize.height)
148-
if (windowSize != newIntSize) {
149-
windowSize = newIntSize
150-
}
151-
}
152-
) { _, _ ->
153-
layout(0, 0) {}
154-
}
155-
156-
PopupLayout(
157-
visible = show,
158-
enableWindowDim = enableWindowDim,
159-
transformOrigin = { transformOrigin },
160-
) {
161-
val shape = remember { SmoothRoundedCornerShape(16.dp) }
162-
val elevationPx = with(density) { shadowElevation.toPx() }
136+
if (parentBounds != IntRect.Zero && windowSize != IntSize.Zero) {
137+
PopupLayout(
138+
visible = show,
139+
enableWindowDim = enableWindowDim,
140+
transformOrigin = { transformOrigin },
141+
) {
142+
val shape = remember { SmoothRoundedCornerShape(16.dp) }
143+
val elevationPx = with(density) { shadowElevation.toPx() }
163144

164-
Box(
165-
modifier = popupModifier
166-
.pointerInput(currentOnDismissRequest) {
167-
detectTapGestures {
168-
currentOnDismissRequest?.invoke()
169-
}
170-
}
171-
.layout { measurable, constraints ->
172-
val placeable = measurable.measure(
173-
constraints.copy(
174-
minWidth = if (minWidth.roundToPx() <= windowSize.width) minWidth.roundToPx() else windowSize.width,
175-
minHeight = if (50.dp.roundToPx() <= windowSize.height) 50.dp.roundToPx() else windowSize.height,
176-
maxHeight = maxHeight?.roundToPx()?.coerceAtLeast(50.dp.roundToPx())
177-
?: (windowBounds.height - popupMargin.top - popupMargin.bottom).coerceAtLeast(
178-
50.dp.roundToPx()
179-
),
180-
maxWidth = if (minWidth.roundToPx() <= windowSize.width) windowSize.width else minWidth.roundToPx()
145+
Box(
146+
modifier = popupModifier
147+
.pointerInput(onDismissRequest) {
148+
detectTapGestures(
149+
onTap = { onDismissRequest?.invoke() }
181150
)
182-
)
183-
val measuredSize = IntSize(placeable.width, placeable.height)
184-
if (popupContentSize != measuredSize) {
185-
popupContentSize = measuredSize
186-
}
187-
188-
val calculatedOffset = popupPositionProvider.calculatePosition(
189-
parentBounds,
190-
windowBounds,
191-
layoutDirection,
192-
measuredSize,
193-
popupMargin,
194-
alignment
195-
)
196-
if (offset != calculatedOffset) {
197-
offset = calculatedOffset
198151
}
152+
.layout { measurable, constraints ->
153+
val placeable = measurable.measure(
154+
constraints.copy(
155+
minWidth = if (minWidth.roundToPx() <= windowSize.width) minWidth.roundToPx() else windowSize.width,
156+
minHeight = if (50.dp.roundToPx() <= windowSize.height) 50.dp.roundToPx() else windowSize.height,
157+
maxHeight = maxHeight?.roundToPx()?.coerceAtLeast(50.dp.roundToPx())
158+
?: (windowBounds.height - popupMargin.top - popupMargin.bottom).coerceAtLeast(
159+
50.dp.roundToPx()
160+
),
161+
maxWidth = if (minWidth.roundToPx() <= windowSize.width) windowSize.width else minWidth.roundToPx()
162+
)
163+
)
164+
val measuredSize = IntSize(placeable.width, placeable.height)
165+
166+
val calculatedOffset = popupPositionProvider.calculatePosition(
167+
parentBounds,
168+
windowBounds,
169+
layoutDirection,
170+
measuredSize,
171+
popupMargin,
172+
alignment
173+
)
199174

200-
layout(constraints.maxWidth, constraints.maxHeight) {
201-
placeable.place(offset)
175+
layout(constraints.maxWidth, constraints.maxHeight) {
176+
placeable.place(calculatedOffset)
177+
}
202178
}
203-
}
204-
) {
205-
Box(
206-
modifier = Modifier
207-
.graphicsLayer(
208-
clip = true,
209-
shape = shape,
210-
shadowElevation = elevationPx,
211-
ambientShadowColor = MiuixTheme.colorScheme.windowDimming,
212-
spotShadowColor = MiuixTheme.colorScheme.windowDimming
213-
)
214-
.background(MiuixTheme.colorScheme.surface)
215179
) {
216-
currentContent()
180+
Box(
181+
modifier = Modifier
182+
.graphicsLayer(
183+
clip = true,
184+
shape = shape,
185+
shadowElevation = elevationPx,
186+
ambientShadowColor = MiuixTheme.colorScheme.windowDimming,
187+
spotShadowColor = MiuixTheme.colorScheme.windowDimming
188+
)
189+
.background(MiuixTheme.colorScheme.surface)
190+
) {
191+
content()
192+
}
217193
}
218194
}
219195
}
220196

221197
BackHandler(enabled = show.value) {
222-
currentOnDismissRequest?.invoke()
198+
onDismissRequest?.invoke()
223199
}
224200
}
225201

miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/basic/NavigationBar.kt

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.size
2727
import androidx.compose.foundation.layout.statusBars
2828
import androidx.compose.foundation.layout.windowInsetsPadding
2929
import androidx.compose.runtime.Composable
30+
import androidx.compose.runtime.derivedStateOf
3031
import androidx.compose.runtime.getValue
3132
import androidx.compose.runtime.mutableStateOf
3233
import androidx.compose.runtime.remember
@@ -104,25 +105,26 @@ fun NavigationBar(
104105
val itemWeight = 1f / items.size
105106

106107
items.forEachIndexed { index, item ->
107-
val isSelected = selected == index
108+
val isSelected = remember(selected) { selected == index }
108109
var isPressed by remember { mutableStateOf(false) }
109110

110111
val onSurfaceContainerColor = MiuixTheme.colorScheme.onSurfaceContainer
111112
val onSurfaceContainerVariantColor = MiuixTheme.colorScheme.onSurfaceContainerVariant
112113

113-
val tint by animateColorAsState(
114-
targetValue = when {
115-
isPressed -> if (isSelected) {
116-
onSurfaceContainerColor.copy(alpha = 0.6f)
117-
} else {
118-
onSurfaceContainerVariantColor.copy(alpha = 0.6f)
119-
}
114+
val tint by remember(isSelected, isPressed) {
115+
derivedStateOf {
116+
when {
117+
isPressed -> if (isSelected) {
118+
onSurfaceContainerColor.copy(alpha = 0.6f)
119+
} else {
120+
onSurfaceContainerVariantColor.copy(alpha = 0.6f)
121+
}
120122

121-
isSelected -> onSurfaceContainerColor
122-
else -> onSurfaceContainerVariantColor
123-
},
124-
label = "tintAnimation"
125-
)
123+
isSelected -> onSurfaceContainerColor
124+
else -> onSurfaceContainerVariantColor
125+
}
126+
}
127+
}
126128
val fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal
127129

128130
Column(
@@ -269,7 +271,7 @@ fun FloatingNavigationBar(
269271
verticalAlignment = Alignment.CenterVertically
270272
) {
271273
items.forEachIndexed { index, item ->
272-
val isSelected = selected == index
274+
val isSelected = remember(selected) { selected == index }
273275
var isPressed by remember { mutableStateOf(false) }
274276

275277
val onSurfaceContainerColor = MiuixTheme.colorScheme.onSurfaceContainer

0 commit comments

Comments
 (0)