pref: Dialog 弹出动画
This commit is contained in:
parent
7a3c2c354d
commit
9356f043ed
|
|
@ -35,30 +35,12 @@ import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
import com.ramcosta.composedestinations.spec.DestinationStyle
|
import com.ramcosta.composedestinations.spec.DestinationStyle
|
||||||
|
|
||||||
@Destination
|
|
||||||
@Composable
|
|
||||||
fun CopyTextPage(
|
|
||||||
text: String,
|
|
||||||
navigator: DestinationsNavigator,
|
|
||||||
) {
|
|
||||||
val context = LocalContext.current
|
|
||||||
CopyTextPageContent(
|
|
||||||
text = text,
|
|
||||||
onCopy = {
|
|
||||||
TiebaUtil.copyText(context, it)
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
navigator.navigateUp()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
object CopyTextDialogStyle : DestinationStyle.Dialog {
|
object CopyTextDialogStyle : DestinationStyle.Dialog {
|
||||||
override val properties: DialogProperties
|
override val properties: DialogProperties
|
||||||
get() = DialogProperties(
|
get() = DialogProperties(
|
||||||
usePlatformDefaultWidth = false,
|
usePlatformDefaultWidth = false,
|
||||||
|
decorFitsSystemWindows = false
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Destination(
|
@Destination(
|
||||||
|
|
@ -70,6 +52,7 @@ fun CopyTextDialogPage(
|
||||||
navigator: DestinationsNavigator,
|
navigator: DestinationsNavigator,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ import com.huanchengfly.tieba.post.ui.common.theme.compose.invertChipContent
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.pullRefreshIndicator
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.pullRefreshIndicator
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.threadBottomBar
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.threadBottomBar
|
||||||
import com.huanchengfly.tieba.post.ui.page.ProvideNavigator
|
import com.huanchengfly.tieba.post.ui.page.ProvideNavigator
|
||||||
import com.huanchengfly.tieba.post.ui.page.destinations.CopyTextPageDestination
|
import com.huanchengfly.tieba.post.ui.page.destinations.CopyTextDialogPageDestination
|
||||||
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
|
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
|
||||||
import com.huanchengfly.tieba.post.ui.page.destinations.ReplyPageDestination
|
import com.huanchengfly.tieba.post.ui.page.destinations.ReplyPageDestination
|
||||||
import com.huanchengfly.tieba.post.ui.page.destinations.SubPostsSheetPageDestination
|
import com.huanchengfly.tieba.post.ui.page.destinations.SubPostsSheetPageDestination
|
||||||
|
|
@ -875,7 +875,7 @@ fun ThreadPage(
|
||||||
},
|
},
|
||||||
onMenuCopyClick = {
|
onMenuCopyClick = {
|
||||||
navigator.navigate(
|
navigator.navigate(
|
||||||
CopyTextPageDestination(it)
|
CopyTextDialogPageDestination(it)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onMenuFavoriteClick = {
|
onMenuFavoriteClick = {
|
||||||
|
|
@ -1216,7 +1216,7 @@ fun ThreadPage(
|
||||||
},
|
},
|
||||||
onMenuCopyClick = {
|
onMenuCopyClick = {
|
||||||
navigator.navigate(
|
navigator.navigate(
|
||||||
CopyTextPageDestination(it)
|
CopyTextDialogPageDestination(it)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onMenuFavoriteClick = {
|
onMenuFavoriteClick = {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import androidx.compose.material.ButtonColors
|
||||||
import androidx.compose.material.ButtonDefaults
|
import androidx.compose.material.ButtonDefaults
|
||||||
import androidx.compose.material.ButtonElevation
|
import androidx.compose.material.ButtonElevation
|
||||||
import androidx.compose.material.ContentAlpha
|
import androidx.compose.material.ContentAlpha
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
|
||||||
import androidx.compose.material.LocalContentAlpha
|
import androidx.compose.material.LocalContentAlpha
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.ProvideTextStyle
|
import androidx.compose.material.ProvideTextStyle
|
||||||
|
|
@ -25,12 +24,12 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Button(
|
fun Button(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
|
|
@ -50,6 +49,7 @@ fun Button(
|
||||||
val contentColor by colors.contentColor(enabled)
|
val contentColor by colors.contentColor(enabled)
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.clip(shape)
|
||||||
.clickable(
|
.clickable(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,33 @@
|
||||||
package com.huanchengfly.tieba.post.ui.widgets.compose
|
package com.huanchengfly.tieba.post.ui.widgets.compose
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.ButtonDefaults
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.OutlinedTextField
|
||||||
|
import androidx.compose.material.ProvideTextStyle
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.TextButton
|
||||||
import androidx.compose.material.TextFieldDefaults
|
import androidx.compose.material.TextFieldDefaults
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.Saver
|
import androidx.compose.runtime.saveable.Saver
|
||||||
import androidx.compose.runtime.saveable.listSaver
|
import androidx.compose.runtime.saveable.listSaver
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -24,9 +39,10 @@ import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.window.DialogProperties
|
|
||||||
import com.huanchengfly.tieba.post.R
|
import com.huanchengfly.tieba.post.R
|
||||||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||||
|
import com.huanchengfly.tieba.post.ui.widgets.compose.dialogs.AnyPopDialog
|
||||||
|
import com.huanchengfly.tieba.post.ui.widgets.compose.dialogs.AnyPopDialogProperties
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.picker.TimePicker
|
import com.huanchengfly.tieba.post.ui.widgets.compose.picker.TimePicker
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -305,71 +321,60 @@ fun Dialog(
|
||||||
content: @Composable (DialogScope.() -> Unit),
|
content: @Composable (DialogScope.() -> Unit),
|
||||||
) {
|
) {
|
||||||
if (dialogState.show) {
|
if (dialogState.show) {
|
||||||
|
var isActiveClose by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
val dialogScope = DialogScope(
|
val dialogScope = DialogScope(
|
||||||
onDismiss = onDismiss,
|
onDismiss = {
|
||||||
dialogState = dialogState,
|
isActiveClose = true
|
||||||
|
},
|
||||||
)
|
)
|
||||||
androidx.compose.ui.window.Dialog(
|
AnyPopDialog(
|
||||||
onDismissRequest = { dialogScope.dismiss() },
|
isActiveClose = isActiveClose,
|
||||||
properties = DialogProperties(
|
onDismiss = {
|
||||||
usePlatformDefaultWidth = false,
|
onDismiss?.invoke()
|
||||||
|
dialogState.show = false
|
||||||
|
},
|
||||||
|
properties = AnyPopDialogProperties(
|
||||||
dismissOnBackPress = cancelable,
|
dismissOnBackPress = cancelable,
|
||||||
dismissOnClickOutside = cancelableOnTouchOutside
|
dismissOnClickOutside = cancelableOnTouchOutside
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Box(modifier = Modifier
|
Column(
|
||||||
.fillMaxSize()
|
modifier = modifier
|
||||||
.clickable(
|
.fillMaxWidth()
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
.padding(16.dp)
|
||||||
indication = null,
|
.background(
|
||||||
enabled = cancelableOnTouchOutside
|
color = ExtendedTheme.colors.windowBackground,
|
||||||
) {
|
shape = RoundedCornerShape(24.dp)
|
||||||
dialogScope.dismiss()
|
)
|
||||||
}
|
.padding(vertical = 24.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
Column(
|
ProvideContentColor(color = ExtendedTheme.colors.text) {
|
||||||
modifier = modifier
|
if (title != null) {
|
||||||
.align(Alignment.BottomCenter)
|
Box(
|
||||||
.fillMaxWidth()
|
modifier = Modifier
|
||||||
.padding(16.dp)
|
.padding(horizontal = 24.dp)
|
||||||
.background(
|
.align(Alignment.CenterHorizontally)
|
||||||
color = ExtendedTheme.colors.windowBackground,
|
) {
|
||||||
shape = RoundedCornerShape(24.dp)
|
ProvideTextStyle(value = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold)) {
|
||||||
)
|
dialogScope.title()
|
||||||
.padding(vertical = 24.dp)
|
|
||||||
.clickable(
|
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
|
||||||
indication = null,
|
|
||||||
onClick = {}
|
|
||||||
),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
|
||||||
) {
|
|
||||||
ProvideContentColor(color = ExtendedTheme.colors.text) {
|
|
||||||
if (title != null) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 24.dp)
|
|
||||||
.align(Alignment.CenterHorizontally)
|
|
||||||
) {
|
|
||||||
ProvideTextStyle(value = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold)) {
|
|
||||||
dialogScope.title()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Box(modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
}
|
||||||
dialogScope.content()
|
Box(modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
||||||
}
|
dialogScope.content()
|
||||||
Column(
|
}
|
||||||
modifier = Modifier
|
Column(
|
||||||
.padding(horizontal = 24.dp),
|
modifier = Modifier
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
.padding(horizontal = 24.dp),
|
||||||
) {
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
dialogScope.buttons()
|
) {
|
||||||
}
|
dialogScope.buttons()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -418,11 +423,9 @@ class DialogState private constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
class DialogScope(
|
class DialogScope(
|
||||||
private val dialogState: DialogState,
|
private val onDismiss: () -> Unit,
|
||||||
private val onDismiss: (() -> Unit)? = null,
|
|
||||||
) {
|
) {
|
||||||
fun dismiss() {
|
fun dismiss() {
|
||||||
onDismiss?.invoke()
|
onDismiss()
|
||||||
dialogState.show = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,268 @@
|
||||||
|
package com.huanchengfly.tieba.post.ui.widgets.compose.dialogs
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.view.View
|
||||||
|
import android.view.Window
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.animation.Animatable
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideInHorizontally
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import androidx.compose.ui.window.DialogWindowProvider
|
||||||
|
import androidx.compose.ui.window.SecureFlagPolicy
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun getDialogWindow(): Window? = (LocalView.current.parent as? DialogWindowProvider)?.window
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun getActivityWindow(): Window? = LocalView.current.context.getActivityWindow()
|
||||||
|
|
||||||
|
tailrec fun Context.getActivityWindow(): Window? = when (this) {
|
||||||
|
is Activity -> window
|
||||||
|
is ContextWrapper -> baseContext.getActivityWindow()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val DefaultDurationMillis: Int = 250
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DialogFullScreen(
|
||||||
|
isActiveClose: Boolean,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
properties: AnyPopDialogProperties,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
var isAnimateLayout by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
var isBackPress by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
LaunchedEffect(isActiveClose) {
|
||||||
|
if (isActiveClose) {
|
||||||
|
isBackPress = true
|
||||||
|
isAnimateLayout = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val handleBackPress = {
|
||||||
|
if (!isBackPress) {
|
||||||
|
isBackPress = true
|
||||||
|
isAnimateLayout = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
properties = DialogProperties(
|
||||||
|
// 这里不使用新的测量规范,不能设置为false
|
||||||
|
usePlatformDefaultWidth = true,
|
||||||
|
decorFitsSystemWindows = false,
|
||||||
|
dismissOnBackPress = false,
|
||||||
|
dismissOnClickOutside = false,
|
||||||
|
securePolicy = properties.securePolicy
|
||||||
|
),
|
||||||
|
content = {
|
||||||
|
val animColor = remember { Animatable(Color.Transparent) }
|
||||||
|
LaunchedEffect(isAnimateLayout) {
|
||||||
|
if (properties.backgroundDimEnabled) {
|
||||||
|
animColor.animateTo(
|
||||||
|
if (isAnimateLayout) Color.Black.copy(alpha = 0.45F) else Color.Transparent,
|
||||||
|
animationSpec = tween(properties.durationMillis)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
delay(properties.durationMillis.toLong())
|
||||||
|
}
|
||||||
|
if (!isAnimateLayout) {
|
||||||
|
onDismissRequest.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val activityWindow = getActivityWindow()
|
||||||
|
val dialogWindow = getDialogWindow()
|
||||||
|
val parentView = LocalView.current.parent as View
|
||||||
|
SideEffect {
|
||||||
|
if (activityWindow != null && dialogWindow != null && !isBackPress && !isAnimateLayout) {
|
||||||
|
val attributes = WindowManager.LayoutParams()
|
||||||
|
attributes.copyFrom(activityWindow.attributes)
|
||||||
|
attributes.type = dialogWindow.attributes.type
|
||||||
|
dialogWindow.attributes = attributes
|
||||||
|
|
||||||
|
dialogWindow.setLayout(
|
||||||
|
activityWindow.decorView.width,
|
||||||
|
activityWindow.decorView.height
|
||||||
|
)
|
||||||
|
WindowCompat.getInsetsController(dialogWindow, parentView)
|
||||||
|
.isAppearanceLightNavigationBars =
|
||||||
|
properties.isAppearanceLightNavigationBars
|
||||||
|
isAnimateLayout = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = when (properties.direction) {
|
||||||
|
DirectionState.TOP -> Alignment.TopCenter
|
||||||
|
DirectionState.LEFT -> Alignment.CenterStart
|
||||||
|
DirectionState.RIGHT -> Alignment.CenterEnd
|
||||||
|
else -> Alignment.BottomCenter
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(animColor.value)
|
||||||
|
.clickOutSideModifier(
|
||||||
|
dismissOnClickOutside = properties.dismissOnClickOutside,
|
||||||
|
onTap = handleBackPress
|
||||||
|
)
|
||||||
|
)
|
||||||
|
AnimatedVisibility(
|
||||||
|
modifier = Modifier.pointerInput(Unit) {},
|
||||||
|
visible = isAnimateLayout,
|
||||||
|
enter = when (properties.direction) {
|
||||||
|
DirectionState.TOP -> slideInVertically(initialOffsetY = { -it })
|
||||||
|
DirectionState.LEFT -> slideInHorizontally(initialOffsetX = { -it })
|
||||||
|
DirectionState.RIGHT -> slideInHorizontally(initialOffsetX = { it })
|
||||||
|
else -> slideInVertically(initialOffsetY = { it })
|
||||||
|
},
|
||||||
|
exit = when (properties.direction) {
|
||||||
|
DirectionState.TOP -> fadeOut() + slideOutVertically(targetOffsetY = { -it })
|
||||||
|
DirectionState.LEFT -> fadeOut() + slideOutHorizontally(targetOffsetX = { -it })
|
||||||
|
DirectionState.RIGHT -> fadeOut() + slideOutHorizontally(targetOffsetX = { it })
|
||||||
|
else -> fadeOut() + slideOutVertically(targetOffsetY = { it })
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BackHandler(enabled = properties.dismissOnBackPress, onBack = handleBackPress)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 被风吹过的夏天
|
||||||
|
* @see <a href="https://github.com/TheMelody/AnyPopDialog-Compose">https://github.com/TheMelody/AnyPopDialog-Compose</a>
|
||||||
|
* @param isActiveClose 设置为true可触发动画关闭Dialog,动画完自动触发[onDismiss]
|
||||||
|
* @param properties Dialog相关配置
|
||||||
|
* @param onDismiss Dialog关闭的回调
|
||||||
|
* @param content 可组合项视图
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun AnyPopDialog(
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
isActiveClose: Boolean = false,
|
||||||
|
properties: AnyPopDialogProperties = AnyPopDialogProperties(direction = DirectionState.BOTTOM),
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
DialogFullScreen(
|
||||||
|
isActiveClose = isActiveClose,
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
properties = properties
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.systemBarsPadding()
|
||||||
|
.imePadding()
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param dismissOnBackPress 是否支持返回关闭Dialog
|
||||||
|
* @param dismissOnClickOutside 是否支持空白区域点击关闭Dialog
|
||||||
|
* @param isAppearanceLightNavigationBars 导航栏前景色是不是亮色
|
||||||
|
* @param direction 当前对话框弹出的方向
|
||||||
|
* @param backgroundDimEnabled 背景渐入检出开关
|
||||||
|
* @param durationMillis 弹框消失和进入的时长
|
||||||
|
* @param securePolicy 屏幕安全策略
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
class AnyPopDialogProperties(
|
||||||
|
val direction: DirectionState = DirectionState.BOTTOM,
|
||||||
|
val dismissOnBackPress: Boolean = true,
|
||||||
|
val dismissOnClickOutside: Boolean = true,
|
||||||
|
val isAppearanceLightNavigationBars: Boolean = true,
|
||||||
|
val backgroundDimEnabled: Boolean = true,
|
||||||
|
val durationMillis: Int = DefaultDurationMillis,
|
||||||
|
val securePolicy: SecureFlagPolicy = SecureFlagPolicy.Inherit,
|
||||||
|
) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is AnyPopDialogProperties) return false
|
||||||
|
|
||||||
|
if (dismissOnBackPress != other.dismissOnBackPress) return false
|
||||||
|
if (isAppearanceLightNavigationBars != other.isAppearanceLightNavigationBars) return false
|
||||||
|
if (dismissOnClickOutside != other.dismissOnClickOutside) return false
|
||||||
|
if (direction != other.direction) return false
|
||||||
|
if (backgroundDimEnabled != other.backgroundDimEnabled) return false
|
||||||
|
if (durationMillis != other.durationMillis) return false
|
||||||
|
return securePolicy == other.securePolicy
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = dismissOnBackPress.hashCode()
|
||||||
|
result = 31 * result + dismissOnClickOutside.hashCode()
|
||||||
|
result = 31 * result + isAppearanceLightNavigationBars.hashCode()
|
||||||
|
result = 31 * result + direction.hashCode()
|
||||||
|
result = 31 * result + backgroundDimEnabled.hashCode()
|
||||||
|
result = 31 * result + durationMillis.hashCode()
|
||||||
|
result = 31 * result + securePolicy.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class DirectionState {
|
||||||
|
TOP,
|
||||||
|
LEFT,
|
||||||
|
RIGHT,
|
||||||
|
BOTTOM
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Modifier.clickOutSideModifier(
|
||||||
|
dismissOnClickOutside: Boolean,
|
||||||
|
onTap: () -> Unit,
|
||||||
|
) = this.then(
|
||||||
|
if (dismissOnClickOutside) {
|
||||||
|
Modifier.pointerInput(Unit) {
|
||||||
|
detectTapGestures(onTap = {
|
||||||
|
onTap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else Modifier
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue