Компонент DropdownMenu позволяет компактным образом разместить ряд вариантов для выбора пользователем - некий аналог контекстного меню. DropdownMenu немного похож на всплывающее окно - он может быть отображаться, а может быть скрыт. DropdownMenu сам по себе не занимает места в разметке и отображается поверх остального контента. Обычно DropdownMenu размещается в контейнере Box, хотя это необязательное требование.
Функция компонента принимает следующие параметры:
@Composable fun DropdownMenu( expanded: Boolean, onDismissRequest: () -> Unit, modifier: Modifier = Modifier, offset: DpOffset = DpOffset(0.dp, 0.dp), scrollState: ScrollState = rememberScrollState(), properties: PopupProperties = PopupProperties(focusable = true), shape: Shape = MenuDefaults.shape, containerColor: Color = MenuDefaults.containerColor, tonalElevation: Dp = MenuDefaults.TonalElevation, shadowElevation: Dp = MenuDefaults.ShadowElevation, border: BorderStroke? = null, content: @Composable ColumnScope.() -> Unit ): Unit
Параметры функции компонента:
expanded
: значение типа Boolean
, которое устанавливает, будет ли меню отображаться (значение true
) или будет скрыто (значение false
)
onDismissRequest
: представляет функцию-обработчик типа () -> Unit
, которая вызывается, когда пользователь нажимает на область вне меню для его закрытия
modifier
: представляет объект Modifier, который определяет модификаторы кнопки
offset
: объект типа DpOffset, который определяет смещения позиции меню относительно положения по умолчанию.
По умолчанию равно DpOffset(0.dp, 0.dp)
scrollState
: значение типа ScrollState, которое применяется для настройки вертикальной прокрутки элементов.
properties
: объект типа PopupProperties, который задает дополнительные свойства меню.
По умолчанию равно PopupProperties(focusable = true)
shape
: форма меню в виде объекта Shape.
containerColor
: цвет контейнера.
tonalElevation
: эффект анимации при нажатии на элемент меню.
shadowElevation
: высота тени.
border
: параметры границы в виде объекта BorderStroke.
content
: содержимое меню в виде столбца компонентов. Обычно представляет набор компонентов типа DropdownMenuItem.
Определим простейшее меню DropdownMenu:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Divider import androidx.compose.material3.DropdownMenu import androidx.compose.material3.Icon import androidx.compose.material3.IconButton 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.unit.dp import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { var expanded by remember { mutableStateOf(false) } Box { IconButton(onClick = { expanded = true }) { Icon(Icons.Default.MoreVert, contentDescription = "Показать меню") } DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false } ) { Text("Скопировать", fontSize=18.sp, modifier = Modifier.padding(10.dp)) Text("Вставить", fontSize=18.sp, modifier = Modifier.padding(10.dp)) Divider() Text("Настройки", fontSize=18.sp, modifier = Modifier.padding(10.dp)) } } } } }
Здесь для управления отображением меню определена переменная expanded
, и ее значение привязано к параметру expanded
компонента DropdownMenu.
При нажатии на кнопку IconButton эта переменная получает значение true
, и меню отображается на экране.
Само меню состоит из трех компонентов Text. Между предпоследним и последним компонентами располагается элемент Divider
, который просто для красоты разделяет пункты меню горизонтальной линией.
При нажатии пользователем на область вне меню, срабатывает функция параметра onDismissRequest
компонента DropdownMenu. В этой функции переменная expanded
получает значение false
, и меню скрывается.
Обычно элементы меню DropdownMenu предоставляют компонент DropdownMenuItem:
@Composable fun DropdownMenuItem( text: @Composable () -> Unit, onClick: () -> Unit, modifier: Modifier = Modifier, leadingIcon: (@Composable () -> Unit)? = null, trailingIcon: (@Composable () -> Unit)? = null, enabled: Boolean = true, colors: MenuItemColors = MenuDefaults.itemColors(), contentPadding: PaddingValues = MenuDefaults.DropdownMenuItemContentPadding, interactionSource: MutableInteractionSource? = null ): Unit
Параметры функции компонента:
text
: устанавливает содержимое компонента
onClick
: представляет функцию-обработчик нажатия меню
modifier
: предствляет объект Modifier, который определяет модификаторы компонента
leadingIcon
: иконча, которая отображается в начале компонента
trailingIcon
: иконча, которая отображается в конце компонента
enabled
: значение типа Boolean
устанавливает, доступен ли компонент для нажатия (значение true
)
или нет (значение false
)
colors
: цветовые настройки меню
contentPadding
: объект типа PaddingValues, который устанавливает отступы между границами компонента и его содержимым. По умолчанию равно MenuDefaults.DropdownMenuItemContentPadding
interactionSource
: представляет объект типа MutableInteractionSource, который устанавливает поток взаимодействий для кнопки. Значение по умолчанию - remember { MutableInteractionSource() }
Используем в качестве пунктов меню DropdownMenuItem:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Box import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Divider import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.IconButton 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 class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { var expanded by remember { mutableStateOf(false) } Box { IconButton(onClick = { expanded = true }) { Icon(Icons.Default.MoreVert, contentDescription = "Показать меню") } DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false } ) { DropdownMenuItem( onClick = { }, text = { Text("Скопировать") } ) DropdownMenuItem( onClick = { }, text = {Text("Вставить")} ) Divider() DropdownMenuItem( onClick = { }, text = {Text("Настройки")} ) } } } } }
Если пункт меню представлен компонентом DropdownMenuItem, то мы можем определить обработку выбора пункта с помощью параметра onClick
:
ackage com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Divider import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.IconButton 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.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { var expanded by remember { mutableStateOf(false) } var selectedOption by remember { mutableStateOf("") } Box { Row { IconButton(onClick = { expanded = true }) { Icon(Icons.Default.MoreVert, contentDescription = "Показать меню") } Text("Выбран пункт: $selectedOption", fontSize = 28.sp) } DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false } ) { DropdownMenuItem( onClick = { selectedOption = "Copy" }, text = { Text("Скопировать") } ) DropdownMenuItem( onClick = { selectedOption = "Paste" }, text = { Text("Вставить") } ) Divider() DropdownMenuItem( onClick = { selectedOption = "Settings" }, text = { Text("Настройки") } ) } } } } }
Здесь по нажатию на любой пункт меню в обработчике нажатия передаем переменной selectedOption
соответствующее значение.
Если нас не устраивает начальная позиция DropdownMenu, то мы можем ее сместить с помощью параметра offset
. Он представляет объект
DpOffset
, который имеет два свойства: x (смещение по горизонтали) и y (смещение по вертикали). Оба свойства принимают значения в единицах dp:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Box import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.Divider import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.IconButton 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.unit.DpOffset import androidx.compose.ui.unit.dp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { var expanded by remember { mutableStateOf(false) } var selectedOption by remember { mutableStateOf("") } Box { IconButton(onClick = { expanded = true }) { Icon(Icons.Default.MoreVert, contentDescription = "Показать меню") } DropdownMenu( expanded = expanded, onDismissRequest = { expanded = false }, offset = DpOffset(x = 20.dp, y = 10.dp) ) { DropdownMenuItem( onClick = {}, text = { Text("Скопировать") } ) DropdownMenuItem( onClick = { }, text = { Text("Вставить") } ) Divider() DropdownMenuItem( onClick = { }, text = { Text("Настройки") } ) } } } } }
В данном случае строка
offset = DpOffset(x = 20.dp, y = 10.dp)
Позволяет задать смещение меню на 20 пикселей вправо и на 10 пикселей вниз