- Updated summarization prompt to require Russian output and exclude non-textual elements - Upgraded ollama dependency to v0.6.1 - Enhanced run.sh script to support both single record and file-based ID input for MongoDB test generation - Updated documentation in scripts/README.md to reflect new functionality - Added verbose flag to generate_summarization_from_mongo.py for better debugging ``` This commit message follows the conventional commit format with a short title (50-72 characters) and provides a clear description of the changes made and their purpose.
164 lines
15 KiB
Plaintext
164 lines
15 KiB
Plaintext
Jetpack Compose Material 3 предлагает богатый набор UI-компонентов. Но помимо Button, TextField и Card существует множество менее известных компонентов, которые помогут сэкономить время и обеспечить лучший пользовательский опыт. В этой статье рассмотрим некоторые из них и узнаем, когда и как их использовать. Примечание: примеры в этой статье должны работать во всех версиях Compose Material 3: продакшен-версии (1.3.2), бета (1.4.0-beta02) и альфа (1.5.0-alpha04), так как API не менялся. Реклама 1. TriStateCheckbox Обычный флажок (чекбокс) поддерживает два состояния: включено и выключено. TriStateCheckbox добавляет третье состояние: неопределенное. Оно используется в ситуации, когда что-то не полностью отмечено и не полностью снято. В документации по TriStateCheckbox есть изображение (см. ниже), которое показывает все три состояния. Источник: https://developer.android.com/images/reference/androidx/compose/material3/indeterminate-checkbox.png Для чего нужен этот компонент? В основном он предназначен для использования в качестве родительского флажка, который отображает состояние всех дочерних флажков: Когда все дочерние флажки сняты → родительский TriStateCheckbox находится в состоянии «выключено». Когда дочерние флажки отмечены не все (часть снята) → родительский TriStateCheckbox переходит в неопределенное состояние (ни отмечено, ни снято). Когда все дочерние флажки отмечены → родительский TriStateCheckbox находится в состоянии «включено». Пример трех состояний TriStateCheckbox Вот как мы можем реализовать описанный выше выбор. Еще одна важная особенность заключается в том, что щелчок по TriStateCheckbox изменяет состояние всех дочерних флажков. @Composable private fun TriStateCheckboxSample() { var childStates by remember { mutableStateOf(List(5) { false }) } // Определение родительского состояния val parentState = when { childStates.all { it } -> ToggleableState.On childStates.none { it } -> ToggleableState.Off else -> ToggleableState.Indeterminate } Column(Modifier.padding(16.dp)) { // Родительский чекбокс Row(verticalAlignment = Alignment.CenterVertically) { TriStateCheckbox( state = parentState, onClick = { val newState = parentState != ToggleableState.On childStates = List(childStates.size) { newState } } ) Text("Options") } Spacer(Modifier.height(8.dp)) // Дочерние чекбоксы childStates.forEachIndexed { index, checked -> Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(horizontal = 16.dp)) { Checkbox( checked = checked, onCheckedChange = { newValue -> childStates = childStates.toMutableList().apply { this[index] = newValue } } ) Text("Option ${index + 1}") } } } } Вот как это выглядит в действии: Видео, демонстрирующее работу TriStateCheckbox Забавный факт: composable-функция Checkbox является оберткой для composable TriStateCheckbox, при этом игнорируется третье, неопределенное состояние. 2. SegmentedButton SegmentedButton — это компонент, который позволяет выбрать от двух до пяти вариантов. Она может содержать значки, текст или и то, и другое. Существует два варианта SegmentedButton: с одиночным или множественным выбором. Они реализуются как разные компоненты. SegmentedButton с одиночным выбором SegmentedButton с одиночным выбором реализуется в виде composable SingleChoiceSegmentedButtonRow, к которой можно добавить несколько SegmentedButton. Может использоваться значок по умолчанию (галочка), также доступен вариант предоставления собственного значка. Пример SegmentedButton с одиночным выбором Пример реализации двух SegmentedButton, показанных выше: var selectedIndex by remember { mutableIntStateOf(0) }
|
||
SingleChoiceSegmentedButtonRow(
|
||
modifier = Modifier.fillMaxWidth()
|
||
) {
|
||
(0..2).forEach { index ->
|
||
SegmentedButton(
|
||
selected = selectedIndex == index,
|
||
onClick = { selectedIndex = index },
|
||
shape = SegmentedButtonDefaults.itemShape(index, 3),
|
||
) {
|
||
Text("Option ${index + 1}")
|
||
}
|
||
}
|
||
}
|
||
|
||
Text(
|
||
text = "Selected Option: ${selectedIndex + 1}",
|
||
style = MaterialTheme.typography.bodySmall
|
||
)
|
||
|
||
Spacer(Modifier.height(16.dp))
|
||
|
||
var selectedIndex1 by remember { mutableIntStateOf(0) }
|
||
SingleChoiceSegmentedButtonRow(
|
||
modifier = Modifier.fillMaxWidth()
|
||
) {
|
||
(0..4).forEach { index ->
|
||
SegmentedButton(
|
||
selected = selectedIndex1 == index,
|
||
onClick = { selectedIndex1 = index },
|
||
shape = SegmentedButtonDefaults.itemShape(index, 5),
|
||
icon = {
|
||
SegmentedButtonDefaults.Icon(selectedIndex1 == index, activeContent = {
|
||
Icon(Icons.Default.Favorite, null)
|
||
})
|
||
}
|
||
) {
|
||
Text("${index + 1}")
|
||
}
|
||
}
|
||
}
|
||
|
||
Text(
|
||
text = "Selected Option: ${selectedIndex1 + 1}",
|
||
style = MaterialTheme.typography.bodySmall
|
||
) Вот как это выглядит в действии: Пример использования SegmentedButton с одиночным выбором SegmentedButton с множественным выбором SegmentedButton с множественным выбором реализуется в виде composable MultiChoiceSegmentedButtonRow, к которой можно добавить несколько SegmentedButton. Реализация аналогична SingleChoiceSegmentedButtonRow, с некоторыми незначительными отличиями в API, позволяющими одновременно отмечать несколько кнопок. Пример SegmentedButton с множественным выбором Вот пример реализации двух SegmentedButton, показанных выше. val selectedOptions = remember { mutableStateListOf<Int>() }
|
||
MultiChoiceSegmentedButtonRow(
|
||
modifier = Modifier.fillMaxWidth()
|
||
) {
|
||
(0..4).forEach { index ->
|
||
SegmentedButton(
|
||
checked = index in selectedOptions,
|
||
onCheckedChange = {
|
||
if (index in selectedOptions) selectedOptions.remove(index) else selectedOptions.add(
|
||
index
|
||
)
|
||
},
|
||
shape = SegmentedButtonDefaults.itemShape(index, 5),
|
||
) {
|
||
Text("${index + 1}")
|
||
}
|
||
}
|
||
}
|
||
|
||
Text(
|
||
text = "Selected Options: ${selectedOptions.map { it + 1 }.joinToString()}",
|
||
style = MaterialTheme.typography.bodySmall
|
||
) Вот как это выглядит в действии. Пример использования SegmentedButton с множественным выбором 3. RangeSlider RangeSlider (диапазонный слайдер) основан на концепции обычного слайдера, но с ключевым отличием: он позволяет пользователю выбрать два значения. Эти два значения образуют диапазон, где одно значение представляет минимум, а другое — максимум. Пример, где можно использовать RangeSlider — фильтрация по цене, позволяющая пользователю выбрать ценовой диапазон и показывающая результаты, которые ему соответствуют. Пример RangeSlider Приведем краткий пример использования RangeSlider. API похож на API обычного Slider. Нужно передать выбранный диапазон значений, допустимый диапазон, определяющий минимальное и максимальное значение, и количество шагов. В этом примере у нас диапазон от 1 до 100 с 9 шагами (плюс один, который всегда присутствует); это означает, что каждый шаг представляет значение 10. @OptIn(ExperimentalMaterial3Api::class)
|
||
@Composable
|
||
private fun RangeSliderExample() {
|
||
var selectedValue by remember { mutableStateOf(0f..100f) }
|
||
|
||
Column {
|
||
Text(
|
||
text = "Selected range: ${selectedValue.start.toInt()} - ${selectedValue.endInclusive.toInt()}",
|
||
style = MaterialTheme.typography.bodyLarge
|
||
)
|
||
|
||
RangeSlider(
|
||
value = selectedValue,
|
||
onValueChange = { newRange -> selectedValue = newRange },
|
||
valueRange = 1f..100f,
|
||
steps = 9,
|
||
modifier = Modifier.fillMaxWidth()
|
||
)
|
||
}
|
||
} Можно перетаскивать каждый бегунок, чтобы изменить выбранный диапазон. Два бегунка не могут пересекаться друг с другом. Пример использования RangeSlider 4. Badge Бейдж (Badge) представляет собой уведомление и предназначен для привлечения внимания к элементу, информируя пользователя о наличии ожидающих запросов или действий. Он также может отображать определенное количество ожидающих запросов или короткий текст. Обычно используется в нижней панели навигации на одном из навигационных элементов. Источник: https://developer.android.com/images/reference/androidx/compose/material3/badge.png BadgedBox — это компонент, оборачивающий элемент, к которому мы хотим прикрепить бейдж. Он принимает две composable-функции в качестве входных аргументов: одну для содержимого и одну для бейджа. Затем он закрепляет бейдж в правом верхнем углу содержимого. Badge также можно настраивать, применяя различные фоны и цвета текста. @Composable
|
||
private fun BadgeExample() {
|
||
Row(
|
||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||
modifier = Modifier
|
||
) {
|
||
BadgedBox(
|
||
badge = {
|
||
Badge {
|
||
Text("5")
|
||
}
|
||
}
|
||
) {
|
||
Icon(
|
||
imageVector = Icons.Default.Email,
|
||
contentDescription = "Messages",
|
||
modifier = Modifier.padding(8.dp)
|
||
)
|
||
}
|
||
|
||
BadgedBox(
|
||
badge = {
|
||
Badge(
|
||
containerColor = Color.Gray,
|
||
contentColor = Color.Yellow
|
||
) {
|
||
Text(500.toString())
|
||
}
|
||
}
|
||
) {
|
||
Text("Inbox", modifier = Modifier.padding(8.dp))
|
||
}
|
||
}
|
||
|
||
// Пример навигационной панели
|
||
NavigationBar {
|
||
NavigationBarItem(
|
||
icon = {
|
||
Icon(Icons.Filled.Home, contentDescription = "Home")
|
||
},
|
||
selected = true,
|
||
onClick = {}
|
||
)
|
||
|
||
NavigationBarItem(
|
||
icon = {
|
||
BadgedBox(
|
||
badge = {
|
||
Badge()
|
||
}
|
||
) {
|
||
Icon(Icons.AutoMirrored.Filled.List, contentDescription = "List")
|
||
}
|
||
},
|
||
selected = false,
|
||
onClick = {}
|
||
)
|
||
|
||
NavigationBarItem(
|
||
icon = {
|
||
BadgedBox(
|
||
badge = {
|
||
Badge()
|
||
{
|
||
Text(3.toString())
|
||
}
|
||
}
|
||
) {
|
||
Icon(Icons.Filled.Person, contentDescription = "Profile")
|
||
}
|
||
},
|
||
selected = false,
|
||
onClick = {}
|
||
)
|
||
}
|
||
} Приведенный пример показывает бейдж над значком, кастомизированный бейдж над текстом и бейджи внутри панели навигации. Примеры использования Badge и BadgedBox 5. Tooltip Более подробную информацию о компоненте Tooltip вы можете найти в отдельной статье. Заключение Мы подробно рассмотрели некоторые из менее известных компонентов Compose Material 3. Теперь можете уверенно добавлять эти незаслуженно обойденные вниманием компоненты в свой набор инструментов Compose, чтобы ваши приложения стали более проработанными и интерактивными. Читайте также: Оптимизация кэширования в TrendNow: объединение OkHttp Cache и базы данных Room. Часть 7 Роль Fragments в современной разработке приложений для Android Автоматизация скриншот-тестирования предварительных просмотров Compose с использованием отражения Читайте нас в Telegram, VK и Дзен Перевод статьи Domen Lanišnik: Exploring 5 Lesser-Known Compose Components
|
||
==============
|