Kotlin Practice # 17 Compose 下拉式選單 DropdownMenu

Dogpa Chen
10 min readApr 22, 2023

--

上一篇透過官方的原生元件,理解了RangeSlider的使用方式。

這一篇來研究side project的另一個功能,鄉鎮市區的選取。在iOS會有picker可以使用,而在研究後,Android則是透過DropdownMenu來協助完成,可以另外透過TextField的搜尋方式來完成,因為這個功能基本上會使用在使用者選取台灣的鄉鎮市區,所以就不透過的這種方式來完成。簡單的透過按鈕點擊出現讓使用者選取。

首先建立一個Array儲存六都的名稱,另外一個map透過六都名稱當作key對應該城市的區名。

val taiwanCountryArray = arrayOf(
"台北市",
"新北市",
"桃園市",
"台中市",
"台南市",
"高雄市",
)

val taiwanCountryMap =
mapOf(
"台北市" to arrayOf(
"中正區",
"大同區",
"中山區",
"松山區",
"大安區",
"萬華區",
"信義區",
"士林區",
"北投區",
"內湖區",
"南港區",
"文山區"
),

"新北市" to arrayOf(
"萬里區",
"金山區",
"板橋區",
"汐止區",
"深坑區",
"石碇區",
"瑞芳區",
"平溪區",
"雙溪區",
"貢寮區",
"新店區",
"坪林區",
"烏來區",
"永和區",
"中和區",
"土城區",
"三峽區",
"樹林區",
"鶯歌區",
"三重區",
"新莊區",
"泰山區",
"林口區",
"蘆洲區",
"五股區",
"八里區",
"淡水區",
"三芝區",
"石門區"
),

"桃園市" to arrayOf(
"中壢區",
"平鎮區",
"龍潭區",
"楊梅區",
"新屋區",
"觀音區",
"桃園區",
"龜山區",
"八德區",
"大溪區",
"復興區",
"大園區",
"蘆竹區"
),

"台中市" to arrayOf(
"中區",
"東區",
"南區",
"西區",
"北區",
"北屯區",
"西屯區",
"南屯區",
"太平區",
"大里區",
"霧峰區",
"烏日區",
"豐原區",
"后里區",
"石岡區",
"東勢區",
"和平區",
"新社區",
"潭子區",
"大雅區",
"神岡區",
"大肚區",
"沙鹿區",
"龍井區",
"梧棲區",
"清水區",
"大甲區",
"外埔區",
"大安區"
),

"台南市" to arrayOf(
"中西區",
"東區",
"南區",
"北區",
"安平區",
"安南區",
"永康區",
"歸仁區",
"新化區",
"左鎮區",
"玉井區",
"楠西區",
"南化區",
"仁德區",
"關廟區",
"龍崎區",
"官田區",
"麻豆區",
"佳里區",
"西港區",
"七股區",
"將軍區",
"學甲區",
"北門區",
"新營區",
"後壁區",
"白河區",
"東山區",
"六甲區",
"下營區",
"柳營區",
"鹽水區",
"善化區",
"新市區",
"大內區",
"山上區",
"安定區"
),

"高雄市" to arrayOf(
"新興區",
"前金區",
"苓雅區",
"鹽埕區",
"鼓山區",
"旗津區",
"前鎮區",
"三民區",
"楠梓區",
"小港區",
"左營區",
"仁武區",
"大社區",
"岡山區",
"路竹區",
"阿蓮區",
"田寮區",
"燕巢區",
"橋頭區",
"梓官區",
"彌陀區",
"永安區",
"湖內區",
"鳳山區",
"大寮區",
"林園區",
"鳥松區",
"大樹區",
"旗山區",
"美濃區",
"六龜區",
"內門區",
"杉林區",
"甲仙區",
"桃源區",
"那瑪夏區",
"茂林區",
"茄萣區"
)
)

接著在新專案內的Greeting內替換成下列內容,因為上一篇簡單理解MVVM的架構,在這裡就先不用MVVM處理,直接將對應的參數寫在Greeting內

@Composable
fun Greeting() {
// 判斷是否展開縣市下拉選單
val countryExpanded = remember {
mutableStateOf(false)
}

// 判斷是否展開行政區下拉選單
val districtExpanded = remember {
mutableStateOf(false)
}

// 縣市index
val countrySelectIndex = remember {
mutableStateOf(0)
}

// 行政區index
val districtSelectIndex = remember {
mutableStateOf(0)
}

// 行政區的Array
val taiwanCountryArray = taiwanCountryArray

// 鄉鎮市區的Array,透過map去找出目前都市的鄉鎮市區array後存入
val taiwanDistrictArray = taiwanCountryMap.getOrDefault(taiwanCountryArray[countrySelectIndex.value],
emptyArray()
)

Column() {

Column(horizontalAlignment = Alignment.CenterHorizontally) {

Row() {

// 縣市
Box(
Modifier
.weight(0.4f)
.padding(10.dp)
.wrapContentSize(Alignment.TopStart)
) {
val colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Green,
contentColor = Color.Black
)
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
// countryExpanded變成true使DropdownMenu開啟
countryExpanded.value = true
},
colors = colors
) {
Text(text = taiwanCountryArray[countrySelectIndex.value])
}

DropdownMenu(
expanded = countryExpanded.value,
onDismissRequest = { countryExpanded.value = false }) {
taiwanCountryArray.forEachIndexed { index, s ->
DropdownMenuItem(onClick = {
// 選擇完成後countryExpanded變成false縮小
// countrySelectIndex變成點擊的六都index
// 給後續的map去抓出相對應的鄉鎮市區Array後顯示
// 因每個鄉鎮市數量不同,統一先將districtSelectIndex變成0,以防止閃退
countryExpanded.value = false
countrySelectIndex.value = index
districtSelectIndex.value = 0
}) {
Text(text = s)
}
}
}
}


// 行政區
Box(
Modifier
.weight(0.4f)
.padding(10.dp)
.wrapContentSize(Alignment.TopStart)
) {
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
districtExpanded.value = true
},
) {
Text(text = taiwanDistrictArray[districtSelectIndex.value])
}

DropdownMenu(
expanded = districtExpanded.value,
onDismissRequest = { districtExpanded.value = false }) {
taiwanDistrictArray.forEachIndexed { index, s ->
DropdownMenuItem(onClick = {
districtExpanded.value = false
districtSelectIndex.value = index
}) {
Text(text = s)
}
}
}
}
}

// 目前選擇提示字
Text(
text = "目前選擇:${taiwanCountryArray[countrySelectIndex.value].toString()} ${taiwanDistrictArray[districtSelectIndex.value]}",
textAlign = TextAlign.Center
)
}
}
}

接著在MainActivity內調整Greeting

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
KP17DropdownMenuTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Greeting()
}
}
}
}
}

來看看結果

可以看到完成了縣市的轉換,其對應的鄉鎮市區也會跟著切換,又多學到一個元件的使用了,持續加油!!

參考資源:

--

--