Как получить абсолютную позицию представления для использования в наложении?

Я пытаюсь создать размытое наложение всего экрана. Я хотел бы воссоздать частичные элементы экрана поверх размытой части, чтобы создать эффект размытия всего, кроме выбранных элементов.

В примере, который я привожу, я хотел бы размыть все, кроме текста «Пока».

Я делаю это, используя две коробки. Один для основного контента, другой для наложения. Я отслеживаю глобальное положение текста «Пока» с помощью onGloballyPositioned и воссоздаю представление в наложении, используя эти координаты.

Проблема, с которой я столкнулся, заключается в том, что возвращаемые координаты кажутся совершенно неверными. Ни одно из значений не кажется мне полезным. Я не знаю, как подойти к этой проблеме. Тестируя мой реальный сценарий, я обнаружил, что значения, возвращаемые с помощью onGloballyPositioned, в 2,8 раза больше, чем должны быть, но эта константа менялась на разных устройствах.

package com.example.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            var root: Offset by remember { mutableStateOf(Offset.Zero) }
            var parent: Offset by remember { mutableStateOf(Offset.Zero) }
            var window: Offset by remember { mutableStateOf(Offset.Zero) }
            var positionText by remember { mutableStateOf("") }
            var blur by remember { mutableStateOf(0.dp) }

            Box(Modifier.fillMaxSize().blur(blur).clickable(onClick = {
                if (blur > 0.dp) {
                    blur = 0.dp
                } else {
                    blur = 4.dp
                }
            })) {
                Column {
                    Text(text = "Hi")
                    Text(text = "Hi")
                    Text(text = "Hi")
                    Text(text = "Hi")
                    Text(text = "Hi")
                    Text(text = "Bye", modifier = Modifier.onGloballyPositioned {
                        root = it.positionInRoot()
                        parent = it.positionInParent()
                        window = it.positionInWindow()
                        positionText = "positionInParent: $parent\npositionInRoot: $root\npositionInWindow: $window"
                    })
                    Text(text = "Hi")
                    Text(text = "Hi")
                    Text(text = "Hi")
                    Text(text = positionText)
                }
            }

            Box(Modifier.fillMaxSize()) {
                Text(
                    modifier = Modifier.offset(x = root.x.dp, y = root.y.dp),
                    text = "Byeeeeeeeeeeeee",
                    color = Color.Blue
                )
                Text(
                    modifier = Modifier.offset(x = parent.x.dp, y = parent.y.dp),
                    text = "Byeeeeeee",
                    color = Color.Green
                )
                Text(
                    modifier = Modifier.offset(x = window.x.dp, y = window.y.dp),
                    text = "Byeee",
                    color = Color.Magenta
                )
            }
        }
    }
}

0
0
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш ящик находится за пределами колонны. Кроме того, координаты, которые вы получаете, указаны в пикселях. Вы бы хотели, чтобы они были в dp, учитывая плотность

Код:

@Composable
fun SOBlur() {

    var parent: Offset by remember { mutableStateOf(Offset.Zero) }
    var positionText by remember { mutableStateOf("") }
    var blur by remember { mutableStateOf(0.dp) }

    Box(
        Modifier
            .fillMaxSize()
    ) {
        Column(modifier = Modifier.fillMaxSize().blur(blur).clickable {
            if (blur > 0.dp) {
                blur = 0.dp
            } else {
                blur = 4.dp
            }
        }) {

            Text(text = "Hi")
            Text(text = "Hi")
            Text(text = "Hi")
            Text(text = "Hi")
            Text(text = "Hi")
            Text(text = "Hi")
            Text(text = "Hi")
            Text(text = "Hi")
            Text(text = "Bye", modifier = Modifier.onGloballyPositioned {
                parent = Offset(
                    it.positionInParent().x,
                    it.positionInParent().y
                )
                positionText =
                    "positionInParent: $parent"
            })
            Text(text = positionText)
        }
            Box(Modifier.offset(x = parent.x.pxToDp(), y = parent.y.pxToDp())) {
                Text(
                    modifier = Modifier,
                    text = "Byeeeeeee",
                    color = Color.Green
                )

            }
    }
}

@Composable
fun Float.pxToDp() = with(LocalDensity.current) { [email protected]() }

ScreenShot: Я надеюсь, что это то, что вы ищете, если щелкнуть столбец, он размывается, и текст отображается в этом положении.

Также обратите внимание: я переместил текст внутри поля и сделал размытие столбца. Box имеет 2 дочерних элемента: один — столбец с текстом, другой — перекрывает его.

Raghunandan 07.04.2024 17:31

Отмеченный. Мой реальный вариант использования немного сложнее, и подход с двумя блоками имеет для меня немного больше смысла при использовании positionInRoot().

lazyvar 07.04.2024 17:42

не уверен в вашем фактическом варианте использования. но если это список, вы можете сопоставить индекс со смещением, так что только текст элемента, по которому щелкнут, будет перекрывать размытый список ниже! в любом случае подход один и тот же!

Raghunandan 07.04.2024 17:56

Другие вопросы по теме