Skip to content

Commit

Permalink
Merge pull request #566 from skydoves/compose/repositional
Browse files Browse the repository at this point in the history
Implement repositioning over scrollable or movable parent for Compose
  • Loading branch information
skydoves committed Dec 27, 2023
2 parents 7d27797 + a326ad8 commit a4a4222
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 69 deletions.
4 changes: 2 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".CustomActivity" />
<activity android:name=".ComposeActivity" />
<activity android:name=".MainActivity" />
<activity
android:name=".ComposeActivity"
android:name=".CustomActivity"
android:exported="true"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
Expand Down
33 changes: 17 additions & 16 deletions app/src/main/kotlin/com/skydoves/balloondemo/ComposeActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -87,20 +88,18 @@ class ComposeActivity : ComponentActivity() {
.padding(20.dp)
.align(Alignment.Center),
builder = builder,
onComposedAnchor = {
balloonWindow1?.showAlignTop()
},
onBalloonWindowInitialized = {
balloonWindow1 = it
},
balloonContent = {
Text(
text = "Now you can edit your profile1 profile2 profile3 profile4",
textAlign = TextAlign.Center,
color = Color.White,
)
},
) {
) { balloonWindow ->
LaunchedEffect(key1 = Unit) {
balloonWindow1 = balloonWindow
}

Button(
modifier = Modifier.size(160.dp, 60.dp),
onClick = { balloonWindow1?.showAlignTop() },
Expand All @@ -114,20 +113,21 @@ class ComposeActivity : ComponentActivity() {
.padding(20.dp)
.align(Alignment.TopStart),
builder = builder,
onBalloonWindowInitialized = {
balloonWindow2 = it
},
balloonContent = {
Text(
text = "Now you can edit your profile!",
textAlign = TextAlign.Center,
color = Color.White,
)
},
) {
) { balloonWindow ->
LaunchedEffect(key1 = Unit) {
balloonWindow2 = balloonWindow
}

Button(
modifier = Modifier.size(160.dp, 60.dp),
onClick = { balloonWindow2?.showAlignBottom() },
onClick = { balloonWindow2?.showAlignTop() },
) {
Text(text = "wrap balloon")
}
Expand All @@ -138,9 +138,6 @@ class ComposeActivity : ComponentActivity() {
.padding(20.dp)
.align(Alignment.TopEnd),
builder = builder,
onBalloonWindowInitialized = {
balloonWindow3 = it
},
balloonContent = {
Box(modifier = Modifier.fillMaxWidth()) {
Box(
Expand All @@ -164,7 +161,11 @@ class ComposeActivity : ComponentActivity() {
)
}
},
) {
) { balloonWindow ->
LaunchedEffect(key1 = Unit) {
balloonWindow3 = balloonWindow
}

Button(
modifier = Modifier.size(160.dp, 60.dp),
onClick = { balloonWindow3?.showAlignBottom() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import androidx.lifecycle.setViewTreeViewModelStoreOwner
import androidx.savedstate.findViewTreeSavedStateRegistryOwner
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import com.skydoves.balloon.Balloon
import com.skydoves.balloon.BalloonAlign
import java.lang.Integer.max
import java.util.UUID

Expand Down Expand Up @@ -156,12 +157,20 @@ public fun Balloon(
}

Box(
modifier = modifier.onSizeChanged {
anchorView.updateLayoutParams {
width = it.width
height = it.height
modifier = modifier
.onGloballyPositioned {
balloonComposeView.updateAlign(
align = balloonComposeView.balloon.currentAlign ?: BalloonAlign.BOTTOM,
xOff = 0,
yOff = 0,
)
}
},
.onSizeChanged {
anchorView.updateLayoutParams {
width = it.width
height = it.height
}
},
) {
AndroidView(
modifier = Modifier.matchParentSize(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,6 @@ internal class BalloonComposeView(
balloon.updateAlign(align, anchorView, xOff, yOff)
}

@Deprecated(
"Use updateAlign instead.",
replaceWith = ReplaceWith("updateAlign(BalloonAlign.Top, xOff, yOff)"),
)
override fun update(xOff: Int, yOff: Int): Unit = balloon.update(anchorView, xOff, yOff)

override fun showAlign(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,10 +450,6 @@ public interface BalloonWindow {
* @param xOff A horizontal offset from the anchor in pixels.
* @param yOff A vertical offset from the anchor in pixels.
*/
@Deprecated(
"Use updateAlign instead.",
replaceWith = ReplaceWith("updateAlign(BalloonAlign.Top, xOff, yOff)"),
)
public fun update(xOff: Int = 0, yOff: Int = 0)

/** updates the size of the balloon card. */
Expand Down
3 changes: 1 addition & 2 deletions balloon/api/balloon.api
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public final class com/skydoves/balloon/Balloon : androidx/lifecycle/DefaultLife
public final fun getBalloonArrowView ()Landroid/view/View;
public final fun getBodyWindow ()Landroid/widget/PopupWindow;
public final fun getContentView ()Landroid/view/ViewGroup;
public final fun getCurrentAlign ()Lcom/skydoves/balloon/BalloonAlign;
public final fun getMeasuredHeight ()I
public final fun getMeasuredWidth ()I
public final fun getOverlayWindow ()Landroid/widget/PopupWindow;
Expand Down Expand Up @@ -186,8 +187,6 @@ public final class com/skydoves/balloon/Balloon : androidx/lifecycle/DefaultLife
public final fun showAtCenter (Landroid/view/View;II)V
public final fun showAtCenter (Landroid/view/View;IILcom/skydoves/balloon/BalloonCenterAlign;)V
public static synthetic fun showAtCenter$default (Lcom/skydoves/balloon/Balloon;Landroid/view/View;IILcom/skydoves/balloon/BalloonCenterAlign;ILjava/lang/Object;)V
public final fun update (Landroid/view/View;)V
public final fun update (Landroid/view/View;I)V
public final fun update (Landroid/view/View;II)V
public static synthetic fun update$default (Lcom/skydoves/balloon/Balloon;Landroid/view/View;IIILjava/lang/Object;)V
public final fun updateAlign (Lcom/skydoves/balloon/BalloonAlign;Landroid/view/View;)V
Expand Down
87 changes: 51 additions & 36 deletions balloon/src/main/kotlin/com/skydoves/balloon/Balloon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ public class Balloon private constructor(
ViewGroup.LayoutParams.MATCH_PARENT,
)

/** Denotes the align of the currently displaying balloon. */
public var currentAlign: BalloonAlign? = null
private set

/** Denotes the popup is showing or not. */
public var isShowing: Boolean = false
private set
Expand Down Expand Up @@ -269,41 +273,48 @@ public class Balloon private constructor(

adjustArrowOrientationByRules(anchor)

when (builder.arrowOrientation.getRTLSupportOrientation(builder.isRtlLayout)) {
ArrowOrientation.BOTTOM -> {
rotation = 180f
x = getArrowConstraintPositionX(anchor)
y = binding.balloonCard.y + binding.balloonCard.height - SIZE_ARROW_BOUNDARY
ViewCompat.setElevation(this, builder.arrowElevation)
runOnAfterSDK23 {
foreground = getArrowForeground(x, binding.balloonCard.height.toFloat())
}
}
updateArrow(anchor)

ArrowOrientation.TOP -> {
rotation = 0f
x = getArrowConstraintPositionX(anchor)
y = binding.balloonCard.y - builder.arrowSize + SIZE_ARROW_BOUNDARY
runOnAfterSDK23 { foreground = getArrowForeground(x, 0f) }
}
visible(builder.isVisibleArrow)
}
}
}

ArrowOrientation.START -> {
rotation = -90f
x = binding.balloonCard.x - builder.arrowSize + SIZE_ARROW_BOUNDARY
y = getArrowConstraintPositionY(anchor)
runOnAfterSDK23 { foreground = getArrowForeground(0f, y) }
private fun updateArrow(anchor: View) {
with(binding.balloonArrow) {
when (builder.arrowOrientation.getRTLSupportOrientation(builder.isRtlLayout)) {
ArrowOrientation.BOTTOM -> {
rotation = 180f
x = getArrowConstraintPositionX(anchor)
y = binding.balloonCard.y + binding.balloonCard.height - SIZE_ARROW_BOUNDARY
ViewCompat.setElevation(this, builder.arrowElevation)
runOnAfterSDK23 {
foreground = getArrowForeground(x, binding.balloonCard.height.toFloat())
}
}

ArrowOrientation.END -> {
rotation = 90f
x = binding.balloonCard.x + binding.balloonCard.width - SIZE_ARROW_BOUNDARY
y = getArrowConstraintPositionY(anchor)
runOnAfterSDK23 {
foreground = getArrowForeground(binding.balloonCard.width.toFloat(), y)
}
ArrowOrientation.TOP -> {
rotation = 0f
x = getArrowConstraintPositionX(anchor)
y = binding.balloonCard.y - builder.arrowSize + SIZE_ARROW_BOUNDARY
runOnAfterSDK23 { foreground = getArrowForeground(x, 0f) }
}

ArrowOrientation.START -> {
rotation = -90f
x = binding.balloonCard.x - builder.arrowSize + SIZE_ARROW_BOUNDARY
y = getArrowConstraintPositionY(anchor)
runOnAfterSDK23 { foreground = getArrowForeground(0f, y) }
}

ArrowOrientation.END -> {
rotation = 90f
x = binding.balloonCard.x + binding.balloonCard.width - SIZE_ARROW_BOUNDARY
y = getArrowConstraintPositionY(anchor)
runOnAfterSDK23 {
foreground = getArrowForeground(binding.balloonCard.width.toFloat(), y)
}
}
visible(builder.isVisibleArrow)
}
}
}
Expand Down Expand Up @@ -794,6 +805,7 @@ public class Balloon private constructor(
}

this.isShowing = true
this.currentAlign = placement.align

val dismissDelay = this.builder.autoDismissDuration
if (dismissDelay != NO_LONG_VALUE) {
Expand Down Expand Up @@ -1531,7 +1543,7 @@ public class Balloon private constructor(
@MainThread
private fun update(placement: BalloonPlacement) {
if (isShowing) {
initializeArrow(placement.anchor)
updateArrow(placement.anchor)

val (xOff, yOff) = calculateOffset(placement)
this.bodyWindow.update(
Expand All @@ -1555,20 +1567,23 @@ public class Balloon private constructor(
* @param xOff A horizontal offset from the anchor in pixels.
* @param yOff A vertical offset from the anchor in pixels.
*/
@JvmOverloads
@Deprecated(
"Use updateAlign instead.",
replaceWith = ReplaceWith("updateAlign(BalloonAlign.Top, anchor, xOff, yOff)"),
)
public fun update(anchor: View, xOff: Int = 0, yOff: Int = 0) {
update(placement = BalloonPlacement(anchor = anchor, xOff = xOff, yOff = yOff))
update(
placement = BalloonPlacement(
anchor = anchor,
xOff = xOff,
yOff = yOff,
type = PlacementType.CENTER,
),
)
}

/** dismiss the popup menu. */
public fun dismiss() {
if (this.isShowing) {
val dismissWindow: () -> Unit = {
this.isShowing = false
this.currentAlign = null
this.bodyWindow.dismiss()
this.overlayWindow.dismiss()
this.handler.removeCallbacks(autoDismissRunnable)
Expand Down

0 comments on commit a4a4222

Please sign in to comment.