Skip to content

Commit 1f0c699

Browse files
committed
library: Optimize performance as much as possible
* lots of changes that need more testing
1 parent 841a522 commit 1f0c699

35 files changed

+1748
-1089
lines changed

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

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import androidx.compose.foundation.layout.padding
1212
import androidx.compose.runtime.Composable
1313
import androidx.compose.runtime.Immutable
1414
import androidx.compose.runtime.Stable
15-
import androidx.compose.runtime.derivedStateOf
15+
import androidx.compose.runtime.getValue
1616
import androidx.compose.runtime.remember
17+
import androidx.compose.runtime.rememberUpdatedState
1718
import androidx.compose.ui.Alignment
1819
import androidx.compose.ui.Modifier
1920
import androidx.compose.ui.graphics.Color
@@ -50,20 +51,24 @@ fun Button(
5051
insideMargin: PaddingValues = ButtonDefaults.InsideMargin,
5152
content: @Composable RowScope.() -> Unit
5253
) {
53-
val shape = remember { derivedStateOf { SmoothRoundedCornerShape(cornerRadius) } }
54+
val shape = remember(cornerRadius) { SmoothRoundedCornerShape(cornerRadius) }
55+
val currentOnClick by rememberUpdatedState(onClick)
56+
val surfaceColor by colors.colorState(enabled)
57+
5458
Surface(
55-
onClick = {
56-
onClick()
57-
},
59+
onClick = currentOnClick,
5860
enabled = enabled,
5961
modifier = modifier.semantics { role = Role.Button },
60-
shape = shape.value,
61-
color = colors.color(enabled)
62+
shape = shape,
63+
color = surfaceColor
6264
) {
63-
Row(
65+
val rowModifier = remember(minWidth, minHeight, insideMargin) {
6466
Modifier
6567
.defaultMinSize(minWidth = minWidth, minHeight = minHeight)
66-
.padding(insideMargin),
68+
.padding(insideMargin)
69+
}
70+
Row(
71+
rowModifier,
6772
horizontalArrangement = Arrangement.Center,
6873
verticalAlignment = Alignment.CenterVertically,
6974
content = content
@@ -94,27 +99,33 @@ fun TextButton(
9499
cornerRadius: Dp = ButtonDefaults.CornerRadius,
95100
minWidth: Dp = ButtonDefaults.MinWidth,
96101
minHeight: Dp = ButtonDefaults.MinHeight,
97-
insideMargin: PaddingValues = ButtonDefaults.InsideMargin,
102+
insideMargin: PaddingValues = ButtonDefaults.InsideMargin
98103
) {
104+
val currentOnClick by rememberUpdatedState(onClick)
105+
val shape = remember(cornerRadius) { SmoothRoundedCornerShape(cornerRadius) }
106+
val surfaceColor by colors.colorState(enabled)
107+
val textColor by colors.textColorState(enabled)
108+
99109
Surface(
100-
onClick = {
101-
onClick()
102-
},
110+
onClick = currentOnClick,
103111
enabled = enabled,
104112
modifier = modifier.semantics { role = Role.Button },
105-
shape = SmoothRoundedCornerShape(cornerRadius),
106-
color = colors.color(enabled)
113+
shape = shape,
114+
color = surfaceColor
107115
) {
108-
Row(
116+
val rowModifier = remember(minWidth, minHeight, insideMargin) {
109117
Modifier
110118
.defaultMinSize(minWidth = minWidth, minHeight = minHeight)
111-
.padding(insideMargin),
119+
.padding(insideMargin)
120+
}
121+
Row(
122+
rowModifier,
112123
horizontalArrangement = Arrangement.Center,
113124
verticalAlignment = Alignment.CenterVertically,
114125
content = {
115126
Text(
116127
text = text,
117-
color = colors.textColor(enabled),
128+
color = textColor,
118129
style = MiuixTheme.textStyles.button
119130
)
120131
}
@@ -204,6 +215,9 @@ class ButtonColors(
204215
) {
205216
@Stable
206217
internal fun color(enabled: Boolean): Color = if (enabled) color else disabledColor
218+
219+
@Composable
220+
internal fun colorState(enabled: Boolean) = rememberUpdatedState(if (enabled) color else disabledColor)
207221
}
208222

209223
@Immutable
@@ -218,4 +232,10 @@ class TextButtonColors(
218232

219233
@Stable
220234
internal fun textColor(enabled: Boolean): Color = if (enabled) textColor else disabledTextColor
235+
236+
@Composable
237+
internal fun colorState(enabled: Boolean) = rememberUpdatedState(if (enabled) color else disabledColor)
238+
239+
@Composable
240+
internal fun textColorState(enabled: Boolean) = rememberUpdatedState(if (enabled) textColor else disabledTextColor)
221241
}

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

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ import androidx.compose.foundation.layout.fillMaxSize
2121
import androidx.compose.foundation.layout.padding
2222
import androidx.compose.foundation.shape.RoundedCornerShape
2323
import androidx.compose.runtime.Composable
24-
import androidx.compose.runtime.derivedStateOf
24+
import androidx.compose.runtime.getValue
2525
import androidx.compose.runtime.remember
26+
import androidx.compose.runtime.rememberUpdatedState
2627
import androidx.compose.ui.Modifier
2728
import androidx.compose.ui.draw.clip
2829
import androidx.compose.ui.graphics.Color
@@ -62,8 +63,11 @@ fun Card(
6263
cornerRadius = cornerRadius,
6364
color = color
6465
) {
66+
val columnModifier = remember(insideMargin) {
67+
Modifier.padding(insideMargin)
68+
}
6569
Column(
66-
modifier = Modifier.padding(insideMargin),
70+
modifier = columnModifier,
6771
content = content
6872
)
6973
}
@@ -98,22 +102,26 @@ fun Card(
98102
content: @Composable ColumnScope.() -> Unit
99103
) {
100104
val interactionSource = remember { MutableInteractionSource() }
105+
val currentOnClick by rememberUpdatedState(onClick)
106+
val currentOnLongPress by rememberUpdatedState(onLongPress)
101107

102-
val pressModifier = when (pressFeedbackType) {
103-
PressFeedbackType.None -> Modifier
104-
PressFeedbackType.Sink -> Modifier.pressSink(interactionSource)
105-
PressFeedbackType.Tilt -> Modifier.pressTilt(interactionSource)
108+
val pressFeedbackModifier = remember(pressFeedbackType, interactionSource) {
109+
when (pressFeedbackType) {
110+
PressFeedbackType.None -> Modifier
111+
PressFeedbackType.Sink -> Modifier.pressSink(interactionSource)
112+
PressFeedbackType.Tilt -> Modifier.pressTilt(interactionSource)
113+
}
106114
}
107115

108116
BasicCard(
109117
modifier = modifier
110118
.pointerInput(Unit) {
111119
detectTapGestures(
112-
onTap = { onClick?.invoke() },
113-
onLongPress = { onLongPress?.invoke() }
120+
onTap = { currentOnClick?.invoke() },
121+
onLongPress = { currentOnLongPress?.invoke() }
114122
)
115123
}
116-
.pointerInput(Unit) {
124+
.pointerInput(interactionSource) {
117125
awaitEachGesture {
118126
val pressInteraction: PressInteraction.Press
119127
awaitFirstDown().also {
@@ -127,18 +135,22 @@ fun Card(
127135
}
128136
}
129137
}
130-
.then(pressModifier),
138+
.then(pressFeedbackModifier),
131139
cornerRadius = cornerRadius,
132140
color = color
133141
) {
134-
Column(
135-
modifier = Modifier
142+
val currentIndication = LocalIndication.current
143+
val columnModifier = remember(interactionSource, showIndication, insideMargin, currentIndication) {
144+
Modifier
136145
.indication(
137146
interactionSource = interactionSource,
138-
indication = if (showIndication == true) LocalIndication.current else null
147+
indication = if (showIndication == true) currentIndication else null
139148
)
140149
.fillMaxSize()
141-
.padding(insideMargin),
150+
.padding(insideMargin)
151+
}
152+
Column(
153+
modifier = columnModifier,
142154
content = content
143155
)
144156
}
@@ -159,14 +171,19 @@ private fun BasicCard(
159171
cornerRadius: Dp = CardDefaults.CornerRadius,
160172
content: @Composable BoxScope.() -> Unit
161173
) {
162-
val shape = remember { derivedStateOf { SmoothRoundedCornerShape(cornerRadius) } }
163-
Box(
164-
modifier = modifier
174+
val shape = remember(cornerRadius) { SmoothRoundedCornerShape(cornerRadius) }
175+
val clipShape = remember(cornerRadius) { RoundedCornerShape(cornerRadius) }
176+
177+
val boxModifier = remember(modifier, color, shape, clipShape) {
178+
modifier
165179
.semantics(mergeDescendants = false) {
166180
isTraversalGroup = true
167181
}
168-
.background(color = color, shape = shape.value)
169-
.clip(RoundedCornerShape(cornerRadius)), // For touch feedback, there is a problem when using SmoothRoundedCornerShape.
182+
.background(color = color, shape = shape)
183+
.clip(clipShape) // For touch feedback, there is a problem when using SmoothRoundedCornerShape.
184+
}
185+
Box(
186+
modifier = boxModifier,
170187
propagateMinConstraints = true,
171188
content = content
172189
)

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

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ fun Checkbox(
6868
enabled: Boolean = true,
6969
) {
7070
val isChecked by rememberUpdatedState(checked)
71+
val currentOnCheckedChange by rememberUpdatedState(onCheckedChange)
7172
var onCheck by remember { mutableStateOf(false) }
7273
val hapticFeedback = LocalHapticFeedback.current
7374
val interactionSource = remember { MutableInteractionSource() }
@@ -84,10 +85,12 @@ fun Checkbox(
8485
onCheck = false
8586
}
8687

87-
val springSpec = spring<Float>(
88-
dampingRatio = Spring.DampingRatioLowBouncy,
89-
stiffness = if (onCheck) Spring.StiffnessHigh else Spring.StiffnessMedium
90-
)
88+
val springSpec = remember(onCheck) {
89+
spring<Float>(
90+
dampingRatio = Spring.DampingRatioLowBouncy,
91+
stiffness = if (onCheck) Spring.StiffnessHigh else Spring.StiffnessMedium
92+
)
93+
}
9194

9295
val scale by animateFloatAsState(
9396
targetValue = when {
@@ -172,32 +175,39 @@ fun Checkbox(
172175
}
173176
}
174177

175-
val toggleableModifier = if (onCheckedChange != null) {
176-
Modifier.toggleable(
177-
value = isChecked,
178-
onValueChange = {
179-
onCheckedChange(it)
180-
onCheck = true
181-
hapticFeedback.performHapticFeedback(
182-
if (it) HapticFeedbackType.ToggleOn else HapticFeedbackType.ToggleOff
183-
)
184-
},
185-
enabled = enabled,
186-
role = Role.Checkbox,
187-
interactionSource = interactionSource,
188-
indication = LocalIndication.current
189-
)
190-
} else {
191-
Modifier
178+
val currentIndication = LocalIndication.current
179+
val toggleableModifier = remember(isChecked, currentOnCheckedChange, enabled, interactionSource, currentIndication) {
180+
if (currentOnCheckedChange != null) {
181+
Modifier.toggleable(
182+
value = isChecked,
183+
onValueChange = {
184+
currentOnCheckedChange?.invoke(it)
185+
onCheck = true
186+
hapticFeedback.performHapticFeedback(
187+
if (it) HapticFeedbackType.ToggleOn else HapticFeedbackType.ToggleOff
188+
)
189+
},
190+
enabled = enabled,
191+
role = Role.Checkbox,
192+
interactionSource = interactionSource,
193+
indication = currentIndication
194+
)
195+
} else {
196+
Modifier
197+
}
192198
}
193199

194-
Box(
195-
modifier = modifier
200+
val boxModifier = remember(modifier, scale, backgroundColor, toggleableModifier) {
201+
modifier
196202
.size(25.5.dp)
197203
.scale(scale)
198204
.clip(CircleShape)
199205
.background(backgroundColor)
200-
.then(toggleableModifier),
206+
.then(toggleableModifier)
207+
}
208+
209+
Box(
210+
modifier = boxModifier,
201211
contentAlignment = Alignment.Center
202212
) {
203213
Canvas(modifier = Modifier.size(25.5.dp)) {

0 commit comments

Comments
 (0)