Search
Write a publication
Pull to refresh

Comments 12

Я понимаю каскад на десктопе, но в смартфонах... Это же будет неудобно. зачем?

Мне понадобилось настройки приложения "спрятать", чтобы случайно пользователь не сбил. Но и к десктопу это все тоже применимо.

Возможно стоит еще немного подумать над интерфейсом? Потому что каскадное меню на смартфоне - это перебор.

PS: Эмулятор умеет записывать видео (ну или через adb shell screenrecord тоже вариант).

Спасибо за советы! Но у меня стоит задача повторить приложение написанное на Android Xamarin (Фактически на Jave) на Котлине. А на Андроиде есть класс android.view.Menu, который позволяет сделать сложные вложенные меню, что и используется в приложении. Вот что-то подобное мне нужно реализовать на Compose. Я погуглил "Каскадные меню в Compose" и ничего приличного не обнаружил. Поэтому пришлось подумать самому. Важный момент, который удалось найти - использование параметра key у функции remember.

Запись видео на эмуляторе обязательно попробую.

Ну оно так-то достаточно просто делается... Пример, набросано за несколько минут:

@Composable
fun NestedMenuTest(name: String, modifier: Modifier = Modifier) {
    var isExpanded by rememberSaveable { mutableStateOf(false) }
    var isNestedExpanded by rememberSaveable { mutableStateOf(false) }
    Box(modifier = modifier) {
        IconButton(onClick = { isExpanded = true }) {
            Icon(Icons.Default.MoreVert, contentDescription = null)
        }
        DropdownMenu(expanded = isExpanded, onDismissRequest = { isExpanded = false }) {
            DropdownMenuItem(text = { Text(text = "Item 1") }, onClick = { })
            DropdownMenuItem(
                text = { Text(text = "Item 2") }, onClick = { isNestedExpanded = true },
                trailingIcon = {
                    Icon(Icons.Default.MoreVert, contentDescription = null)
                    DropdownMenu(expanded = isNestedExpanded, onDismissRequest = { isNestedExpanded = false }) {
                        DropdownMenuItem(text = { Text(text = "Nested Item 1") }, onClick = { })
                        DropdownMenuItem(text = { Text(text = "Nested Item 2") }, onClick = { })
                    }
                })
            DropdownMenuItem(text = { Text(text = "Item 3") }, onClick = { })
        }
    }
}
Результат
Результат

Намеренно. Для меня, как для пользователя, такой интерфейс (скрытие родителя) является дизориентирующим. Если сильно надо скрывать, то это делается легкой перекомпоновкой:

@Composable
fun NestedMenuTest(modifier: Modifier = Modifier) {
    var isExpanded by rememberSaveable { mutableStateOf(false) }
    var isNestedExpanded by rememberSaveable { mutableStateOf(false) }
    Box(modifier = modifier) {
        IconButton(onClick = { isExpanded = true }) {
            Icon(Icons.Default.MoreVert, contentDescription = null)
        }
        DropdownMenu(expanded = isExpanded && !isNestedExpanded, onDismissRequest = { isExpanded = false }) {
            DropdownMenuItem(text = { Text(text = "Item 1") }, onClick = { })
            DropdownMenuItem(
                text = { Text(text = "Item 2") }, onClick = { isNestedExpanded = true },
                trailingIcon = {
                    Icon(Icons.Default.MoreVert, contentDescription = null)
                })
            DropdownMenuItem(text = { Text(text = "Item 3") }, onClick = { })
        }
        DropdownMenu(expanded = isNestedExpanded, onDismissRequest = { isNestedExpanded = false }) {
            DropdownMenuItem(text = { Text(text = "Nested Item 1") }, onClick = { })
            DropdownMenuItem(text = { Text(text = "Nested Item 2") }, onClick = { })
        }
    }
}

Вы все несколько переусложняете.

Но в любом случае, такого рода решения не очень хороши с точки зрения юзабилити. По моему скромному мнению.

Признаю. Ваше решение элегантнее моего. Я в начале тоже пытался разместить все меню в одной функции, но, к сожалению, не догадался до:

expanded = isExpanded && !isNestedExpanded, onDismissRequest = { isExpanded = false }

Спасибо за обсуждение и идею. Надеюсь, что это поможет еще кому-нибудь, кроме меня

Честно говоря выглядит как штука ради штуки, когда то же самое воспроизводится и на обычных dropdown'ах без дополнительных штук. Особенно странно в композе видеть unstable в data class.

data class-ы позволяют организовать любую, заранее не известную вложенность меню, в том числе настраиваемую программно. При необходимости их можно преобразовать во ViewModel.

стиль котлин не соблюден

в дата классах методов быть не должно

код написан небрежно

статические методы и данные тоже доставляют удовольсвтвия

Готов согласится по поводу data . Правда, если вместо data class ListMenu(..написать просто class ListMenu(.. принципиально ни чего не изменится и все будет работать. По поводу стека companion - ни чего лучшего не придумал. Но, повторюсь, что смысл статьи - просто дать работающий пример каскадного меню "бесконечной" вложенности тем, кто будет искать что-то подобное...

Sign up to leave a comment.

Articles