Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 572 Vote(s) - 3.49 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Jetpack Compose: Make full-screen (absolutely positioned) component

#1
How can I go about making a composable deep down within the render tree full screen, similar to how the `Dialog` composable works?

Say, for example, when a use clicks an image it shows a full-screen preview of the image without changing the current route.

I could do this in CSS with `position: absolute` or `position: fixed` but how would I go about doing this in Jetpack Compose? Is it even possible?

One solution would be to have a composable at the top of the tree that can be passed another composable as an argument from somewhere else in the tree, but this sounds kind of messy. Surely there is a better way.
Reply

#2
If I understand correctly you just don't want to navigate anywhere. Id something like this.



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
)
}
}
}

I just keep track of what type the view is meant to be. In my case I'm not displaying a dialog I'm removing my entire gallery and showing an image instead.

Alternatively you could just have an if(viewImage) condition below your call your and layer the 'dialog' on top of it.
Reply

#3
From what I can tell you want to be able to draw from a nested hierarchy without being limited by the parent constraints.

We faced similar issues and looked at the implementation how Composables such as `Popup`, `DropDown` and `Dialog` function.

What they do is add an entirely new `ComposeView` to the `Window`.
Because of this they are basically starting from a blank canvas.
By making it transparent it looks like the Dialog/Popup/DropDown appears on top.

Unfortunately we could not find a Composable that provides us the functionality to just add a new `ComposeView` to the `Window` so we copied the relevant parts and made following.

@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)
}
}

Here is an example how you can use it

@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")
}
}
}
}
}

The yellow box has set some constraints, which would prevent the Composables from inside to draw outside its bounds.

[![enter image description here][1]][1]


[1]:
Reply

#4
Using the Dialog composable, I have been able to get a proper fullscreen Composable in any nested one. It's quicker and easier than some of other answers.

Dialog(
onDismissRequest = { /* Do something when back button pressed */ },
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = false, usePlatformDefaultWidth = false)
){
/* Your full screen content */
}
Reply

#5
After notice that, at least for now, we don't have any `Composable` to do "easy" fullscreen, I decided to implement mine one, mostly based on ideas from @foxtrotuniform6969 and @ntoskrnl. Also, I tried to do it most possible without to use platform dependent functions then I think this is very suiteable to Desktop/Android.

You can check the basic implementation in [this GitHub repository][1].

By the way, the implementation idea was just:
- Create a composable to wrap the target composables tree that can call an `FullScreen` composable;
- Retrieve the full screen dimensions/size from a auxiliary `Box` matched to the root screen size using the `.onGloballyPositioned()` modifier;
- Store the full screen size and all `FullScreen` composables created in the tree onto appropriated `compositionLocalOf` instances (see [documentation][2]).

I tried to use this in a Desktop project and seems to be working, however I didn't tested in Android yet. The repository also contains a example.

Feel free to navigate in the repository and sent a pull request if you can. :)


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through