Anonymous
Текст M3 OutlinedTextField недоступен для выбора и курсор не может быть перемещен
Сообщение
Anonymous » 18 мар 2024, 02:46
Я создал оболочку, которую можно компоновать вокруг обычного OutlinedTextField M3, вот так:
Код: Выделить всё
@Composable
fun FormTextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
modifier: Modifier = Modifier,
labelTxt: String,
placeholderTxt: String,
focusedBorderColor: Color,
textColor: Color = colorResource(id = R.color.black),
keyboardOptions: KeyboardOptions,
keyboardActions: KeyboardActions,
trailingIcon: @Composable() (() -> Unit)? = null,
) {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
label = {
Text(labelTxt, color = focusedBorderColor, fontSize = 12.sp)
},
placeholder = {
Text(placeholderTxt, fontSize = 12.sp)
},
textStyle = TextStyle(
color = textColor
),
shape = RoundedCornerShape(8.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = focusedBorderColor,
cursorColor = focusedBorderColor,
unfocusedBorderColor = Color(0xFFBEBEBE),
),
modifier = modifier,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
trailingIcon = trailingIcon
)
}
Теперь я пытаюсь использовать его, чтобы создать поле формы, которое принимает только числа. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что текст, который я набираю, вообще не доступен для выбора, и курсор не может перемещаться по тексту, как вы обычно ожидаете.
Вот мой нижний лист, где это используется:
Код: Выделить всё
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditProductStockBottomSheet(
modifier: Modifier = Modifier,
productLocationViewModel: ProductLocationViewModel = koinInject(),
productDetails: ProductDetails,
stockLocations: List
,
onStockChanged: (Int) -> Unit,
onDismissRequest: () -> Unit
) {
val context = LocalContext.current
val navViewModel = LocalNavViewModel.current
val scannedBarcode by navViewModel.scannedBarcode.observeAsState()
val coroutineContext = rememberCoroutineScope()
val bottomSheetState = rememberModalBottomSheetState(true)
var locationUUIDToUpdateStock by remember {
mutableStateOf("")
}
var updatedStock by remember {
mutableStateOf(TextFieldValue("0"))
}
val locationToUpdateStock by remember {
derivedStateOf {
stockLocations.firstOrNull { it.uuid == locationUUIDToUpdateStock }
}
}
var reasonForStockUpdate by remember {
mutableStateOf(TextFieldValue(""))
}
LaunchedEffect(key1 = Unit) {
navViewModel.setActiveBarcodeReceivingDestination(BarcodeScanReceivingDestination.EDIT_PRODUCT_STOCK_BOTTOM_SHEET)
}
LaunchedEffect(key1 = scannedBarcode) {
if (scannedBarcode.isNullOrEmpty() || !productDetails.getPossibleBarcodes()
.contains(scannedBarcode)
) return@LaunchedEffect
val updatedStockAsInt = updatedStock.text.toIntOrNull()
if (updatedStockAsInt != null) {
updatedStock = TextFieldValue(
updatedStockAsInt.plus(1).toString()
)
}
navViewModel.setScannedBarcode("")
}
ModalBottomSheet(
onDismissRequest = {
onDismissRequest()
coroutineContext.launch {
bottomSheetState.hide()
}
},
sheetState = bottomSheetState,
contentColor = Color.Black,
scrimColor = Color.DarkGray.copy(alpha = 0.4f),
modifier = modifier
.wrapContentHeight(),
containerColor = colorResource(id = R.color.white),
) {
Column(
modifier = Modifier.padding(horizontal = 16.dp)
) {
Text(
text = stringResource(R.string.stock_title_txt),
fontSize = 14.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Spacer(Modifier.height(16.dp))
LyraDropDown(
modifier = Modifier
.fillMaxWidth(),
label = stringResource(R.string.location_input_field_label),
onClick = {
locationUUIDToUpdateStock = stockLocations[it].uuid
},
data = stockLocations.map { it.location.name },
) {
Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
LocationBox(locationName = it)
}
}
Spacer(Modifier.height(16.dp))
Row(
Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
FormTextField(
modifier = Modifier
.weight(0.7f, true),
value = updatedStock,
onValueChange = { newVal ->
val newText = newVal.text.filter { it.isDigit() || it == '-' || it == '.' }
updatedStock = TextFieldValue(newText)
},
labelTxt = stringResource(id = R.string.stock_title_txt),
placeholderTxt = "0",
focusedBorderColor = colorResource(id = R.color.blue_500),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number
),
keyboardActions = KeyboardActions(),
)
Row(
Modifier
.weight(0.3f, true)
.padding(top = 4.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly
) {
Text(
"${locationToUpdateStock?.stock ?: 0}",
fontSize = 12.sp,
color = colorResource(id = R.color.gray_700)
)
Icon(
painter = painterResource(id = R.drawable.ic_arrow_right_long),
contentDescription = null,
tint = colorResource(
id = R.color.gray_700
),
modifier = Modifier.size(24.dp)
)
Text(
"${locationToUpdateStock?.stock?.plus(updatedStock.text.toIntOrNull() ?: 0) ?: 0}",
fontSize = 12.sp,
color = colorResource(id = R.color.gray_700)
)
}
}
Spacer(modifier = Modifier.height(16.dp))
FormTextField(
modifier = Modifier.fillMaxWidth(),
value = reasonForStockUpdate,
onValueChange = { newVal ->
reasonForStockUpdate = newVal
},
labelTxt = stringResource(R.string.reason_form_field_txt),
placeholderTxt = stringResource(id = R.string.reason_form_field_txt),
focusedBorderColor = colorResource(id = R.color.blue_500),
keyboardOptions = KeyboardOptions(
),
keyboardActions = KeyboardActions(onDone = {
if (updatedStock.text.toIntOrNull() != null) onStockChanged(updatedStock.text.toInt())
else Toast.makeText(
context,
context.getString(R.string.invalid_stock_value_msg),
Toast.LENGTH_LONG
).show()
})
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.reason_text_field_desc),
modifier = Modifier.padding(horizontal = 8.dp),
color = colorResource(
id = R.color.gray_700
),
fontSize = 11.sp,
lineHeight = 11.sp,
fontWeight = FontWeight.Light
)
Spacer(modifier = Modifier.height(16.dp))
Row(
Modifier
.fillMaxWidth()
.padding(end = 16.dp, top = 16.dp),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically
) {
ActionButton(
text = stringResource(R.string.cancel_btn_txt)
) {
onDismissRequest()
coroutineContext.launch {
bottomSheetState.hide()
}
}
Spacer(Modifier.width(8.dp))
ActionButton(
modifier = Modifier.width(100.dp),
text = stringResource(R.string.add_location_btn_txt),
isEnabled = locationUUIDToUpdateStock.isNotEmpty() && updatedStock.text.toIntOrNull() != null,
containerColor = colorResource(id = R.color.blue_500),
contentColor = colorResource(id = R.color.white)
) {
onStockChanged(updatedStock.text.toInt())
coroutineContext.launch {
bottomSheetState.hide()
onDismissRequest()
}
}
}
}
Spacer(Modifier.height(50.dp))
}
}
Может ли это быть связано с проблемой 2021 года, связанной с выбором текста во время фокусировки, или я что-то путаю внутри, когда фильтрую числа и назначаю новое TextFieldValue в onValueChange поля ?
Подробнее здесь:
https://stackoverflow.com/questions/781 ... t-be-moved
1710719193
Anonymous
Я создал оболочку, которую можно компоновать вокруг обычного OutlinedTextField M3, вот так: [code]@Composable fun FormTextField( value: TextFieldValue, onValueChange: (TextFieldValue) -> Unit, modifier: Modifier = Modifier, labelTxt: String, placeholderTxt: String, focusedBorderColor: Color, textColor: Color = colorResource(id = R.color.black), keyboardOptions: KeyboardOptions, keyboardActions: KeyboardActions, trailingIcon: @Composable() (() -> Unit)? = null, ) { OutlinedTextField( value = value, onValueChange = onValueChange, label = { Text(labelTxt, color = focusedBorderColor, fontSize = 12.sp) }, placeholder = { Text(placeholderTxt, fontSize = 12.sp) }, textStyle = TextStyle( color = textColor ), shape = RoundedCornerShape(8.dp), colors = OutlinedTextFieldDefaults.colors( focusedBorderColor = focusedBorderColor, cursorColor = focusedBorderColor, unfocusedBorderColor = Color(0xFFBEBEBE), ), modifier = modifier, keyboardOptions = keyboardOptions, keyboardActions = keyboardActions, trailingIcon = trailingIcon ) } [/code] Теперь я пытаюсь использовать его, чтобы создать поле формы, которое принимает только числа. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что текст, который я набираю, вообще не доступен для выбора, и курсор не может перемещаться по тексту, как вы обычно ожидаете. Вот мой нижний лист, где это используется: [code]@OptIn(ExperimentalMaterial3Api::class) @Composable fun EditProductStockBottomSheet( modifier: Modifier = Modifier, productLocationViewModel: ProductLocationViewModel = koinInject(), productDetails: ProductDetails, stockLocations: List , onStockChanged: (Int) -> Unit, onDismissRequest: () -> Unit ) { val context = LocalContext.current val navViewModel = LocalNavViewModel.current val scannedBarcode by navViewModel.scannedBarcode.observeAsState() val coroutineContext = rememberCoroutineScope() val bottomSheetState = rememberModalBottomSheetState(true) var locationUUIDToUpdateStock by remember { mutableStateOf("") } var updatedStock by remember { mutableStateOf(TextFieldValue("0")) } val locationToUpdateStock by remember { derivedStateOf { stockLocations.firstOrNull { it.uuid == locationUUIDToUpdateStock } } } var reasonForStockUpdate by remember { mutableStateOf(TextFieldValue("")) } LaunchedEffect(key1 = Unit) { navViewModel.setActiveBarcodeReceivingDestination(BarcodeScanReceivingDestination.EDIT_PRODUCT_STOCK_BOTTOM_SHEET) } LaunchedEffect(key1 = scannedBarcode) { if (scannedBarcode.isNullOrEmpty() || !productDetails.getPossibleBarcodes() .contains(scannedBarcode) ) return@LaunchedEffect val updatedStockAsInt = updatedStock.text.toIntOrNull() if (updatedStockAsInt != null) { updatedStock = TextFieldValue( updatedStockAsInt.plus(1).toString() ) } navViewModel.setScannedBarcode("") } ModalBottomSheet( onDismissRequest = { onDismissRequest() coroutineContext.launch { bottomSheetState.hide() } }, sheetState = bottomSheetState, contentColor = Color.Black, scrimColor = Color.DarkGray.copy(alpha = 0.4f), modifier = modifier .wrapContentHeight(), containerColor = colorResource(id = R.color.white), ) { Column( modifier = Modifier.padding(horizontal = 16.dp) ) { Text( text = stringResource(R.string.stock_title_txt), fontSize = 14.sp, textAlign = TextAlign.Center, fontWeight = FontWeight.Bold, modifier = Modifier.align(Alignment.CenterHorizontally) ) Spacer(Modifier.height(16.dp)) LyraDropDown( modifier = Modifier .fillMaxWidth(), label = stringResource(R.string.location_input_field_label), onClick = { locationUUIDToUpdateStock = stockLocations[it].uuid }, data = stockLocations.map { it.location.name }, ) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { LocationBox(locationName = it) } } Spacer(Modifier.height(16.dp)) Row( Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, ) { FormTextField( modifier = Modifier .weight(0.7f, true), value = updatedStock, onValueChange = { newVal -> val newText = newVal.text.filter { it.isDigit() || it == '-' || it == '.' } updatedStock = TextFieldValue(newText) }, labelTxt = stringResource(id = R.string.stock_title_txt), placeholderTxt = "0", focusedBorderColor = colorResource(id = R.color.blue_500), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number ), keyboardActions = KeyboardActions(), ) Row( Modifier .weight(0.3f, true) .padding(top = 4.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceEvenly ) { Text( "${locationToUpdateStock?.stock ?: 0}", fontSize = 12.sp, color = colorResource(id = R.color.gray_700) ) Icon( painter = painterResource(id = R.drawable.ic_arrow_right_long), contentDescription = null, tint = colorResource( id = R.color.gray_700 ), modifier = Modifier.size(24.dp) ) Text( "${locationToUpdateStock?.stock?.plus(updatedStock.text.toIntOrNull() ?: 0) ?: 0}", fontSize = 12.sp, color = colorResource(id = R.color.gray_700) ) } } Spacer(modifier = Modifier.height(16.dp)) FormTextField( modifier = Modifier.fillMaxWidth(), value = reasonForStockUpdate, onValueChange = { newVal -> reasonForStockUpdate = newVal }, labelTxt = stringResource(R.string.reason_form_field_txt), placeholderTxt = stringResource(id = R.string.reason_form_field_txt), focusedBorderColor = colorResource(id = R.color.blue_500), keyboardOptions = KeyboardOptions( ), keyboardActions = KeyboardActions(onDone = { if (updatedStock.text.toIntOrNull() != null) onStockChanged(updatedStock.text.toInt()) else Toast.makeText( context, context.getString(R.string.invalid_stock_value_msg), Toast.LENGTH_LONG ).show() }) ) Spacer(modifier = Modifier.height(8.dp)) Text( text = stringResource(R.string.reason_text_field_desc), modifier = Modifier.padding(horizontal = 8.dp), color = colorResource( id = R.color.gray_700 ), fontSize = 11.sp, lineHeight = 11.sp, fontWeight = FontWeight.Light ) Spacer(modifier = Modifier.height(16.dp)) Row( Modifier .fillMaxWidth() .padding(end = 16.dp, top = 16.dp), horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically ) { ActionButton( text = stringResource(R.string.cancel_btn_txt) ) { onDismissRequest() coroutineContext.launch { bottomSheetState.hide() } } Spacer(Modifier.width(8.dp)) ActionButton( modifier = Modifier.width(100.dp), text = stringResource(R.string.add_location_btn_txt), isEnabled = locationUUIDToUpdateStock.isNotEmpty() && updatedStock.text.toIntOrNull() != null, containerColor = colorResource(id = R.color.blue_500), contentColor = colorResource(id = R.color.white) ) { onStockChanged(updatedStock.text.toInt()) coroutineContext.launch { bottomSheetState.hide() onDismissRequest() } } } } Spacer(Modifier.height(50.dp)) } } [/code] Может ли это быть связано с проблемой 2021 года, связанной с выбором текста во время фокусировки, или я что-то путаю внутри, когда фильтрую числа и назначаю новое TextFieldValue в onValueChange поля ? Подробнее здесь: [url]https://stackoverflow.com/questions/78147451/m3-outlinedtextfields-text-is-not-selectable-cursor-cannot-be-moved[/url]