Skip to content

Commit e0d5668

Browse files
Balloon Compose: fix fixed-width tooltip content clamped to anchor constraints (#913)
* fix(balloon_modifier) - fix fixed-width tooltip content clamped to anchor constraints * fix(tests) - SDK changed to 23 --------- Co-authored-by: gamer3dx <gamer3dxmobil@yandex.com>
1 parent a17b413 commit e0d5668

File tree

3 files changed

+50
-9
lines changed

3 files changed

+50
-9
lines changed

balloon-compose/src/main/kotlin/com/skydoves/balloon/compose/BalloonModifier.kt

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,31 +168,72 @@ public fun Modifier.balloon(
168168
val horizontalPadding = builder.paddingLeft + builder.paddingRight +
169169
builder.marginLeft + builder.marginRight
170170

171-
// Pre-measure balloon content if not yet measured
172-
if (balloonLayoutInfo.value == null) {
171+
// Pre-measure balloon content if not yet measured (or if fixed-width target changed)
172+
val fixedWidthMode = builder.widthRatio > 0f || builder.maxWidthRatio > 0f
173+
174+
// In fixed-width mode, the target width is screen-based, not anchor-constraint-based.
175+
// We can compute it outside the measurePolicy so we can re-trigger this Layout when it changes.
176+
val desiredFixedWidth = if (fixedWidthMode) {
177+
val w = when {
178+
builder.widthRatio > 0f ->
179+
(screenWidth * builder.widthRatio - horizontalPadding).toInt()
180+
181+
builder.maxWidthRatio > 0f ->
182+
(screenWidth * builder.maxWidthRatio - horizontalPadding).toInt()
183+
184+
else -> 0
185+
}.coerceAtLeast(0)
186+
w
187+
} else {
188+
null
189+
}
190+
191+
if (balloonLayoutInfo.value == null ||
192+
(desiredFixedWidth != null && balloonLayoutInfo.value?.width != desiredFixedWidth)
193+
) {
173194
Layout(
174195
content = { balloonContent() },
175196
measurePolicy = { measurables, constraints ->
197+
176198
val maxContentWidth = when {
177199
builder.widthRatio > 0f ->
178200
(screenWidth * builder.widthRatio - horizontalPadding).toInt()
201+
179202
builder.maxWidthRatio > 0f ->
180203
(screenWidth * builder.maxWidthRatio - horizontalPadding).toInt()
181-
else -> constraints.maxWidth - horizontalPadding
204+
205+
else ->
206+
constraints.maxWidth - horizontalPadding
207+
}.coerceAtLeast(0)
208+
209+
val targetWidth = if (fixedWidthMode) {
210+
// IMPORTANT: do NOT clamp to constraints.maxWidth (anchor width)
211+
maxContentWidth
212+
} else {
213+
// Non-fixed mode: behave like before, limited by the anchor constraints.
214+
maxContentWidth.coerceAtMost((constraints.maxWidth - horizontalPadding).coerceAtLeast(0))
182215
}.coerceAtLeast(0)
183216

184217
val contentConstraints = Constraints(
185-
minWidth = 0,
186-
maxWidth = maxContentWidth.coerceAtMost(constraints.maxWidth),
218+
// IMPORTANT: in fixed mode, force the content host to measure at EXACT width
219+
minWidth = if (fixedWidthMode) targetWidth else 0,
220+
maxWidth = targetWidth,
187221
minHeight = 0,
188222
maxHeight = constraints.maxHeight,
189223
)
190224

191225
val placeables = measurables.map { it.measure(contentConstraints) }
192226

193227
if (placeables.isNotEmpty()) {
194-
val measuredWidth = placeables.maxOf { it.width }
195-
val measuredHeight = placeables.maxOf { it.height }
228+
val measuredHeight = placeables.maxOf { it.height }.coerceAtLeast(0)
229+
230+
// IMPORTANT: in fixed mode, the card width must be the fixed width,
231+
// not the max placeable width (which can still end up smaller).
232+
val measuredWidth = if (fixedWidthMode) {
233+
targetWidth
234+
} else {
235+
placeables.maxOf { it.width }.coerceAtLeast(0)
236+
}
196237

197238
if (measuredWidth > 0 && measuredHeight > 0) {
198239
val size = IntSize(width = measuredWidth, height = measuredHeight)

balloon-compose/src/test/kotlin/com/skydoves/balloon/compose/BalloonComposeExtensionTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import org.robolectric.RobolectricTestRunner
3232
import org.robolectric.annotation.Config
3333

3434
@RunWith(RobolectricTestRunner::class)
35-
@Config(sdk = [21])
35+
@Config(sdk = [23])
3636
class BalloonComposeExtensionTest {
3737

3838
private lateinit var context: Context

balloon-compose/src/test/kotlin/com/skydoves/balloon/compose/BalloonStateTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import org.robolectric.RobolectricTestRunner
3232
import org.robolectric.annotation.Config
3333

3434
@RunWith(RobolectricTestRunner::class)
35-
@Config(sdk = [21])
35+
@Config(sdk = [23])
3636
class BalloonStateTest {
3737

3838
private lateinit var context: Context

0 commit comments

Comments
 (0)