0
0

【Jetpack Compose】OutlinedTextField 全体に対して onClick する方法

Posted at

完成形(OutlinedTextField をクリックすると日付選択ができるようにする)

OutlinedTextFieldAndDatePicker.gif

  • 日付を選択すると OutlinedTextField の値を変更する
    • 日付選択はダイアログから行う
    • テキスト入力はさせない
  • 日付選択のダイアログを閉じると OutlinedTextField のフォーカスを外す

実装

OutlinedTextFiled 全体を選択可能にする

【NG】 Modifier.fillMaxWidth().clickable(onClick)
    OutlinedTextField(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = { /* TODO */ }),
        value = value,
        onValueChange = onValueChange,
        placeholder = { Text(text = "選択してください") },
        trailingIcon = {
            Icon(
                imageVector = GeneratedVectorImages.IcnPull,
                contentDescription = null,
            )
        },
    )

OutlinedTextField 全体に対してクリックしようと Modifier.fillMaxWidth().clickable(onClick) をしてもクリックできませんので注意が必要です。

ポイント

  • interactionSource を設定する
  • readOnly = true を設定する
@Composable
fun SelectOutlineTextField(
    value: String,
    onValueChange: (String) -> Unit,
    onClick: () -> Unit,
) {
    val interactionSource = remember {
        object : MutableInteractionSource {
            override val interactions = MutableSharedFlow<Interaction>(
                extraBufferCapacity = 16,
                onBufferOverflow = BufferOverflow.DROP_OLDEST,
            )

            override suspend fun emit(interaction: Interaction) {
                when (interaction) {
                    is PressInteraction.Press -> {
                        onClick()
                    }
                }

                interactions.emit(interaction)
            }

            override fun tryEmit(interaction: Interaction): Boolean {
                return interactions.tryEmit(interaction)
            }
        }
    }

    OutlinedTextField(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp),
        value = value,
        onValueChange = onValueChange,
        placeholder = { Text(text = "選択してください") },
        trailingIcon = {
            Icon(
                imageVector = Icons.Filled.KeyboardArrowDown,
                contentDescription = null,
            )
        },
        readOnly = true,
        interactionSource = interactionSource,
    )
}

日付選択画面

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerModal(
    onDateSelected: (Long?) -> Unit,
    onDismiss: () -> Unit
) {
    val datePickerState = rememberDatePickerState()

    DatePickerDialog(
        onDismissRequest = onDismiss,
        confirmButton = {
            TextButton(onClick = {
                onDateSelected(datePickerState.selectedDateMillis)
                onDismiss()
            }) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) {
                Text("Cancel")
            }
        }
    ) {
        DatePicker(state = datePickerState)
    }
}

完成形

@Composable
fun HomeScreen() {
    var dateText by remember { mutableStateOf("") }
    var showDialog by remember { mutableStateOf(false) }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        SelectOutlineTextField(
            value = dateText,
            onValueChange = { dateText = it },
            onClick = { showDialog = true },
        )
    }
    
    val focusManager = LocalFocusManager.current

    if (showDialog) {
        DatePickerModal(
            onDateSelected = {
                dateText = convertMillisToDate(it)
                showDialog = false
                focusManager.clearFocus()
            },
            onDismiss = {
                showDialog = false
                focusManager.clearFocus()
            },
        )
    }
}

private fun convertMillisToDate(millis: Long?): String {
    val formatter = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault())
    return millis?.let {
        formatter.format(Date(it))
    } ?: ""
}

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0