Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import com.example.compose.snippets.components.DatePickerExamples
import com.example.compose.snippets.components.DialogExamples
import com.example.compose.snippets.components.DividerExamples
import com.example.compose.snippets.components.FloatingActionButtonExamples
import com.example.compose.snippets.components.MenusExamples
import com.example.compose.snippets.components.PartialBottomSheet
import com.example.compose.snippets.components.ProgressIndicatorExamples
import com.example.compose.snippets.components.ScaffoldExample
Expand Down Expand Up @@ -111,6 +112,7 @@ class SnippetsActivity : ComponentActivity() {
TopComponentsDestination.TimePickerExamples -> TimePickerExamples()
TopComponentsDestination.DatePickerExamples -> DatePickerExamples()
TopComponentsDestination.CarouselExamples -> CarouselExamples()
TopComponentsDestination.MenusExamples -> MenusExamples()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.compose.snippets.components

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

@Composable
fun MenusExamples() {
var currentExample by remember { mutableStateOf<(@Composable () -> Unit)?>(null) }

// Display the current example and the button to close it.
Box(modifier = Modifier.fillMaxSize()) {
currentExample?.let {
it()
FloatingActionButton(
onClick = { currentExample = null },
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(16.dp)
) {
Text(text = "Close example", modifier = Modifier.padding(16.dp))
}
return
}
}

// Display the list of available examples.
Column(modifier = Modifier.padding(16.dp)) {
Button(onClick = { currentExample = { BasicDropdownMenu() } }) {
Text("Action Bar Menu")
}
Button(onClick = { currentExample = { TextFieldDropdownMenu() } }) {
Text("Options Menu")
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
// [START android_compose_components_basicdropdownmenu]
@Composable
fun BasicDropdownMenu() {
var shouldDisplayMenu by remember { mutableStateOf(false) }

TopAppBar(
title = { Text(text = "Basic menu example") },
actions = {
IconButton(onClick = { shouldDisplayMenu = !shouldDisplayMenu }) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend adding a second action, thereby making it clearer that the IconButton+DropdownMenu should be wrapped by a Box to correctly set the anchor for the DropdownMenu:

        actions = {
            IconButton(onClick = { shouldDisplayMenu = !shouldDisplayMenu }) {
                Icon(Icons.Default.StarOutline, stringResource( R.string.cd_star))
            }

            Box {
                IconButton(onClick = { shouldDisplayMenu = !shouldDisplayMenu }) {
                    Icon(Icons.Default.MoreVert, stringResource(R.string.cd_more_options))
                }
                DropdownMenu(
                    expanded = shouldDisplayMenu,
                    onDismissRequest = { shouldDisplayMenu = false }
                ) {
                  DropdownMenuItem(
                      text = { Text("Refresh") },
                      onClick = { /* Handle refresh! */ }
                  )
                  DropdownMenuItem(
                      text = { Text("Settings") },
                      onClick = { /* Handle settings! */ }
                  )
                }
            }

Icon(Icons.Default.MoreVert, "Overflow menu button")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Content description should describe the action. Change to "More options".

}
DropdownMenu(
expanded = shouldDisplayMenu,
onDismissRequest = { shouldDisplayMenu = false }
) {
DropdownMenuItem(
text = { Text("Refresh") },
onClick = { /* Handle refresh! */ }
)
DropdownMenuItem(
text = { Text("Settings") },
onClick = { /* Handle settings! */ }
)
}
}
)
}
// [END android_compose_components_basicdropdownmenu]

@Preview
@Composable
private fun BasicDropdownMenuPreview() {
BasicDropdownMenu()
}

// [START android_compose_components_textfielddropdownmenu]
@Composable
fun TextFieldDropdownMenu() {
var expanded by remember { mutableStateOf(false) }
var selectedText by remember { mutableStateOf("") }
val options = listOf("Option 1", "Option 2", "Option 3")

Box(modifier = Modifier.fillMaxWidth()) {
TextField(
value = selectedText,
onValueChange = { selectedText = it },
modifier = Modifier.fillMaxWidth(),
label = { Text("Select an option") },
trailingIcon = {
IconButton(onClick = { expanded = true }) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want the whole text field to be clickable, not just the arrow?

Icon(Icons.Filled.ArrowDropDown, "Dropdown arrow")
}
},
readOnly = true
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier.fillMaxWidth()
) {
options.forEach { option ->
DropdownMenuItem(
text = { Text(option) },
onClick = {
selectedText = option
expanded = false
}
)
}
}
}
}
// [END android_compose_components_textfielddropdownmenu]

@Preview
@Composable
private fun TextFieldMenuPreview() {
TextFieldDropdownMenu()
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ enum class TopComponentsDestination(val route: String, val title: String) {
PartialBottomSheet("partialBottomSheets", "Partial Bottom Sheet"),
TimePickerExamples("timePickerExamples", "Time Pickers"),
DatePickerExamples("datePickerExamples", "Date Pickers"),
CarouselExamples("carouselExamples", "Carousel")
CarouselExamples("carouselExamples", "Carousel"),
MenusExamples("menusExamples", "Menus")
}