nba*_*man 22 android kotlin android-jetpack android-jetpack-compose
我怎样才能在全屏渲染树的深处制作一个可组合项,类似于Dialog可组合项的工作原理?
例如,当用户单击图像时,它会显示该图像的全屏预览,而无需更改当前路线。
我可以在 CSS 中使用position: absoluteor来完成此操作position: fixed,但如何在 Jetpack Compose 中执行此操作?有可能吗?
一种解决方案是在树的顶部有一个可组合项,可以将另一个可组合项作为参数从树中的其他位置传递,但这听起来有点混乱。当然有更好的方法。
tim*_*tim 23
据我所知,您希望能够从嵌套层次结构中进行绘制,而不受父级约束的限制。
我们遇到了类似的问题,并研究了可组合项(例如Popup、DropDown和 )的实现方式Dialog。
他们所做的就是ComposeView向Window.
正因为如此,他们基本上是从一张空白的画布开始的。
通过使其透明,看起来 Dialog/Popup/DropDown 出现在顶部。
不幸的是,我们找不到一个可组合项为我们提供添加新功能的功能ComposeView,Window因此我们复制了相关部分并进行了以下操作。
@Composable
fun FullScreen(content: @Composable () -> Unit) {
val view = LocalView.current
val parentComposition = rememberCompositionContext()
val currentContent by rememberUpdatedState(content)
val id = rememberSaveable { UUID.randomUUID() }
val fullScreenLayout = remember {
FullScreenLayout(
view,
id
).apply {
setContent(parentComposition) {
currentContent()
}
}
}
DisposableEffect(fullScreenLayout) {
fullScreenLayout.show()
onDispose { fullScreenLayout.dismiss() }
}
}
@SuppressLint("ViewConstructor")
private class FullScreenLayout(
private val composeView: View,
uniqueId: UUID
) : AbstractComposeView(composeView.context) {
private val windowManager =
composeView.context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private val params = createLayoutParams()
override var shouldCreateCompositionOnAttachedToWindow: Boolean = false
private set
init {
id = android.R.id.content
ViewTreeLifecycleOwner.set(this, ViewTreeLifecycleOwner.get(composeView))
ViewTreeViewModelStoreOwner.set(this, ViewTreeViewModelStoreOwner.get(composeView))
ViewTreeSavedStateRegistryOwner.set(this, ViewTreeSavedStateRegistryOwner.get(composeView))
setTag(R.id.compose_view_saveable_id_tag, "CustomLayout:$uniqueId")
}
private var content: @Composable () -> Unit by mutableStateOf({})
@Composable
override fun Content() {
content()
}
fun setContent(parent: CompositionContext, content: @Composable () -> Unit) {
setParentCompositionContext(parent)
this.content = content
shouldCreateCompositionOnAttachedToWindow = true
}
private fun createLayoutParams(): WindowManager.LayoutParams =
WindowManager.LayoutParams().apply {
type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL
token = composeView.applicationWindowToken
width = WindowManager.LayoutParams.MATCH_PARENT
height = WindowManager.LayoutParams.MATCH_PARENT
format = PixelFormat.TRANSLUCENT
flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
}
fun show() {
windowManager.addView(this, params)
}
fun dismiss() {
disposeComposition()
ViewTreeLifecycleOwner.set(this, null)
windowManager.removeViewImmediate(this)
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个如何使用它的示例
@Composable
internal fun Screen() {
Column(
Modifier
.fillMaxSize()
.background(Color.Red)
) {
Text("Hello World")
Box(Modifier.size(100.dp).background(Color.Yellow)) {
DeeplyNestedComposable()
}
}
}
@Composable
fun DeeplyNestedComposable() {
var showFullScreenSomething by remember { mutableStateOf(false) }
TextButton(onClick = { showFullScreenSomething = true }) {
Text("Show full screen content")
}
if (showFullScreenSomething) {
FullScreen {
Box(
Modifier
.fillMaxSize()
.background(Color.Green)
) {
Text("Full screen text", Modifier.align(Alignment.Center))
TextButton(onClick = { showFullScreenSomething = false }) {
Text("Close")
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
黄色框设置了一些约束,这将防止可组合项从内部绘制到其边界之外。
使用 Dialog 可组合项,我能够在任何嵌套的可组合项中获得正确的全屏可组合项。它比其他一些答案更快更容易。
Dialog(
onDismissRequest = { /* Do something when back button pressed */ },
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = false, usePlatformDefaultWidth = false)
){
/* Your full screen content */
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的话,你只是不想导航到任何地方。我有这样的事情。
when (val viewType = viewModel.viewTypeGallery.get()) {
is GalleryViewModel.GalleryViewType.Gallery -> {
Gallery(viewModel, scope, installId, filePathModifier, fragment, setImageUploadType)
}
is GalleryViewModel.GalleryViewType.ImageViewer -> {
Row(Modifier.fillMaxWidth()) {
Image(
modifier = Modifier
.fillMaxSize(),
painter = rememberCoilPainter(viewType.imgUrl),
contentScale = ContentScale.Crop,
contentDescription = null
)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我只是跟踪视图的类型。就我而言,我没有显示对话框,而是删除整个图库并显示图像。
或者,您可以在调用下方添加一个 if(viewImage) 条件,并将“对话框”放在其顶部。
| 归档时间: |
|
| 查看次数: |
27964 次 |
| 最近记录: |