Вопрос или проблема
Я собрал пользовательскую форму, используя две карточки, которые расположены рядом друг с другом в Jetpack Compose. Я хочу, чтобы форма была приподнята, т.е. имела тень. Если я поднимаю обе карточки, обе получают тени, как будто они являются одной формой.
Пример кода:
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
@Composable
fun MenuExample ()
{
Row(
verticalAlignment = Alignment.CenterVertically
) {
Card(
elevation = CardDefaults.cardElevation(
defaultElevation = 10.dp
),
modifier = Modifier
.padding(0.dp)
.height(80.dp)
.zIndex(1f)
.width(40.dp),
shape = RoundedCornerShape(topStart = 10.dp, bottomStart = 10.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.98f)
)
) {
Button(
onClick = { },
modifier = Modifier
.padding(0.dp)
.height(80.dp)
.width(40.dp),
shape = RectangleShape,
contentPadding = PaddingValues(0.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent,
contentColor = Color.Black
)
) {
Icon(
imageVector = Icons.Filled.ArrowBackIosNew,
contentDescription = null,
modifier = Modifier
.size(22.dp)
.padding(0.dp)
)
}
}
Card(
elevation = CardDefaults.cardElevation(
defaultElevation = 10.dp,
),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.98f)
),
modifier = Modifier
.padding(0.dp)
.width(200.dp)
.height(200.dp)
.zIndex(0.5f)
) {
}
}
}
@Preview
@Composable
fun MenuExamplePreview() {
MenuExample()
}
Я хотел бы, чтобы Elevation рассматривала две карточки как одну, что означает, что перекрывающаяся область не должна иметь тени. Как я могу убрать нежелательную тень между двумя карточками (обозначенную стрелкой)?
Ответ или решение
Чтобы решить проблему с нежелательной тенью между двумя картами в Jetpack Compose, необходимо изменить подход к компоновке элементов. Ваша задача заключается в том, чтобы создать эффект единой формы с единой тенью, избегая накладки тени, когда карты расположены рядом.
Вот как это можно сделать:
-
Создайте вспомогательный контейнер: Вместо того чтобы использовать две карты с наложением тени, используйте один контейнер, который будет единой фигурой с правильной тенью.
-
Используйте
Box
илиRow
как контейнер: Оберните ваши карты вBox
илиRow
, который будет иметь тень. -
Сформируйте треугольник тени: Создайте пользовательскую фигуру или используйте
Clip
для формирования тени по вашему желанию.
Вот пример кода, который демонстрирует вышеописанный подход:
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
@Composable
fun MenuExample() {
// Используем Box для создания общей тени
Box(
modifier = Modifier.padding(4.dp) // Тень будет окружать всю Box
.size(240.dp, 80.dp)
.shadow(10.dp, shape = RoundedCornerShape(10.dp), clip = false) // Добавляем тень к контейнеру
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Card(
modifier = Modifier
.size(40.dp, 80.dp)
.clip(RoundedCornerShape(topStart = 10.dp, bottomStart = 10.dp)), // Обрезаем углы
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.98f)
),
elevation = CardDefaults.cardElevation(0.dp) // Убираем внутреннюю тень
) {
// Ваш контент здесь
// ...
}
Card(
modifier = Modifier
.size(200.dp, 80.dp)
.clip(RoundedCornerShape(topEnd = 10.dp, bottomEnd = 10.dp)), // Обрезаем углы
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.98f)
),
elevation = CardDefaults.cardElevation(0.dp) // Убираем внутреннюю тень
) {
// Ваш контент здесь
// ...
}
}
}
}
@Preview
@Composable
fun MenuExamplePreview() {
MenuExample()
}
Объяснение кода:
- Box: Мы используем
Box
с применениемshadow()
для создания одной тени для всего контента. - Row: Внутри
Box
расположены дваCard
, которые обрезаются с помощьюclip()
, чтобы углы выглядели плавными и не создавали нежелательной тени. - Elevation: Установлено значение
elevation
на ноль для карт, чтобы тень не накладывалась на них.
Таким образом, вы создаете иллюзию двух карт с единой тенью, избегая проблем с наложением теней между картами.