#android #android-jetpack-compose
#Android #android-jetpack-compose
Вопрос:
Создание простой клавиатуры в Jetpack Compose довольно простое и понятное. Я создал действительно простой набор клавиш, используя это:
Key.kt
@Composable
fun Key(modifier: Modifier = Modifier, label: String, onClick: () -> Unit) {
val shape = RoundedCornerShape(4.dp)
//TODO: make clickable outside but don't show ripple
Box(modifier = modifier
.padding(2.dp)
.clip(shape)
.clickable(onClick = onClick)
.background(Color.White)
.padding(vertical = 12.dp, horizontal = 4.dp), contentAlignment = Alignment.Center) {
Text(text = label, fontSize = 20.sp)
}
}
KeyRow.kt
@Composable
fun KeyRow(keys: List<String>) {
Row(modifier = Modifier.fillMaxWidth().background(color = grey200)) {
keys.forEach {
Key(modifier = Modifier.weight(1f), label = it, onClick = { })
}
}
}
Вот как это выглядит:
Я хочу добиться этой анимации:
Однако в настоящее время я застрял с этим
![4]
Иерархия
-Keyboard
--KeyRow
---KeyLayout
----Key
----KeyPressedOverlay (only visible when pressed)
Моя главная проблема в том, что я не знаю, как отобразить композицию KeyPressedOverlay (которая больше, чем составная клавиша), не увеличивая родительский макет. В результате мне нужно каким-то образом переполнить родительский макет.
Ответ №1:
Не уверен, что это лучший способ (возможно, нет), но я нашел решение с помощью ConstraintLayout
…
val keys = listOf("A", "B", "C", "D")
ConstraintLayout(
modifier = Modifier.graphicsLayer(clip = false)
) {
val refs = keys.map { createRef() }
refs.forEachIndexed { index, ref ->
val modifier = when (index) {
0 -> Modifier.constrainAs(ref) {
start.linkTo(parent.start)
}
refs.lastIndex -> Modifier.constrainAs(ref) {
start.linkTo(refs[index - 1].end)
end.linkTo(parent.end)
}
else -> Modifier.constrainAs(ref) {
start.linkTo(refs[index - 1].end)
end.linkTo(refs[index 1].start)
}
}
val modifierPressed = Modifier.constrainAs(createRef()) {
start.linkTo(ref.start)
end.linkTo(ref.end)
bottom.linkTo(ref.bottom)
}
KeyboardKey(
keyboardKey = keys[index],
modifier = modifier,
modifierPressed = modifierPressed,
pressed = { s -> /* Do something with the key */}
)
}
}
Здесь есть одна важная деталь graphicLayer(clip = false)
(которая похожа на clipChildren
in View Toolkit). Затем я создаю модификатор для каждой клавиши и для нажатой клавиши. Заметил, что modifierPressed
он выровнен по центру / низу другого модификатора.
Наконец KeyboardKey
, это описано ниже.
@Composable
fun KeyboardKey(
keyboardKey: String,
modifier: Modifier,
modifierPressed: Modifier,
pressed: (String) -> Unit
) {
var isKeyPressed by remember { mutableStateOf(false) }
Text(keyboardKey, Modifier
.then(modifier)
.pointerInput(Unit) {
detectTapGestures(onPress = {
isKeyPressed = true
val success = tryAwaitRelease()
if (success) {
isKeyPressed = false
pressed(keyboardKey)
} else {
isKeyPressed = false
}
})
}
.background(Color.White)
.padding(
start = 12.dp,
end = 12.dp,
top = 16.dp,
bottom = 16.dp
),
color = Color.Black
)
if (isKeyPressed) {
Text(
keyboardKey, Modifier
.then(modifierPressed)
.background(Color.White)
.padding(
start = 16.dp,
end = 16.dp,
top = 16.dp,
bottom = 48.dp
),
color = Color.Black
)
}
}
Вот результат, который я получил:
Редактировать: добавив еще немного логики, я смог получить это…
Надеюсь, на этот раз это поможет 😉 Вот суть на всякий случай … https://gist.github.com/nglauber/4cb1573efba9024c008ea71f3320b4d8
Комментарии:
1. Спасибо за ваш ответ! Отличная идея использовать иерархию плоской компоновки. Немного халтурно, но это работает 🙂
2. Есть ли способ добиться этого с помощью пользовательских макетов? ConstraintLayout может работать очень медленно в сложных ситуациях
3. Я смог добиться «перекрывающегося» поведения без необходимости использования сложных ограничений (в моем случае это происходило так медленно, что я не мог его использовать), используя простой пользовательский макет с фиксированной высотой gist.github.com/THEAccess/b71e17d58d830ed6deaed7066a929576
4. Единственная проблема заключается в том, что он расширяется ниже, а не выше
5. У меня есть полное приложение, так что вы можете понять, что я имею в виду здесь github.com/THEAccess/compose-keyboard-ime/blob/master/app/src /… и gif-файл imgur.com/a/GGL2ziI может быть, вы знаете, как решить эту маленькую проблему
Ответ №2:
Я думаю, вы ищете pressIndicatorGestureFilter
модификатор… Я попробовал это и сработало для меня…
var pressed by remember { mutableStateOf(false) }
val padding = if (pressed) 32.dp else 16.dp
Text("A", Modifier
.pressIndicatorGestureFilter(
onStart = {
pressed = true
},
onStop = {
pressed = false
},
onCancel = {
pressed = false
}
)
.background(Color.White)
.padding(start = 16.dp, end = 16.dp, top = padding, bottom = padding)
)
Комментарии:
1. Спасибо за ваш ответ. Я архивировал поведение щелчка с
interactionState
помощью . Я обновил свой вопрос, чтобы прояснить мою конкретную проблему