I'm trying to put a drop down for US states that uses a TextField and a TextField in a Row and the second TextField (zip) does not show up. What am I doing wrong?
Here is how I'm declaring the row:
Row (Modifier.fillMaxWidth()) {
StateSelection(
onFormChanged = onFormChanged,
selectedLocation = selectedLocation,
label = "State"
)
Spacer(modifier = Modifier.width(8.dp))
ShippingField(
modifier = modifier,
onFormChanged = onFormChanged,
formType = FormType.SHIPPING_ZIP,
label = "Zip",
valueField = selectedLocation.zipCode
)
}
StatesDropDown:
#Composable
fun StateSelection(
onFormChanged: (FormType, String) -> Unit,
selectedLocation: Address,
label: String
) {
// State variables
val statesMap = AddressUtils.mapOfAmericanStatesToValue
var stateName: String by remember { mutableStateOf(selectedLocation.shippingState) }
var expanded by remember { mutableStateOf(false)}
val focusManager = LocalFocusManager.current
Box(contentAlignment = Alignment.CenterStart) {
Row(
Modifier
.padding(vertical = 8.dp)
.clickable {
expanded = !expanded
}
.padding(8.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) { // Anchor view
TextField(
modifier = Modifier
.fillMaxWidth(),
value = stateName,
onValueChange = {
onFormChanged(FormType.SHIPPING_COUNTRY, it)
},
label = { Text(text = label) },
textStyle = MaterialTheme.typography.subtitle1,
singleLine = true,
trailingIcon = {
IconButton(onClick = { expanded = true }) {
Icon(imageVector = Icons.Filled.ArrowDropDown, contentDescription = "")
}
},
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }),
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Text
),
colors = TextFieldDefaults.textFieldColors(
cursorColor = MaterialTheme.colors.secondary,
textColor = MaterialTheme.colors.onPrimary,
focusedIndicatorColor = MaterialTheme.colors.secondary,
backgroundColor = MaterialTheme.colors.secondaryVariant
)
) // state name label
DropdownMenu(expanded = expanded, onDismissRequest = {
expanded = false
}) {
statesMap.asIterable().iterator().forEach {
val (key, value) = it
DropdownMenuItem(onClick = {
expanded = false
stateName = key
onFormChanged(FormType.SHIPPING_STATE, key)
},
modifier = Modifier.fillMaxWidth()) {
Text(text = key)
}
}
}
}
}
}
ZipCode:
#Composable
fun ShippingField(
modifier: Modifier,
onFormChanged: (FormType, String) -> Unit,
formType: FormType,
label: String,
valueField: String
) {
val focusManager = LocalFocusManager.current
var state by rememberSaveable {
mutableStateOf(valueField)
}
TextField(modifier = modifier
.background(MaterialTheme.colors.primaryVariant)
.fillMaxWidth(),
value = state,
onValueChange = {
state = it
onFormChanged(formType, it)
},
label = { Text(text = label) },
textStyle = MaterialTheme.typography.subtitle1,
singleLine = true,
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }),
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Text
),
colors = TextFieldDefaults.textFieldColors(
cursorColor = MaterialTheme.colors.secondary,
textColor = MaterialTheme.colors.onPrimary,
focusedIndicatorColor = MaterialTheme.colors.secondary,
backgroundColor = MaterialTheme.colors.secondaryVariant
)
)
}
Row (Modifier.fillMaxWidth()) {
StateSelection(
modifier = Modifier.weight(1f)
...
)
Spacer(modifier = Modifier.width(8.dp))
ShippingField(
modifier = Modifier.weight(1f),
...
)
}
You should do it like above, and then pass the modifier to your composables below. Weight distributes and fills max width evenly on your composables
You have to remove the modifier = Modifier.fillMaxWidth() in the 1st TextField in the StatesDropDown composable.
Related
I wrote an AutoCompletet TextField in Jetpack Compose. I used this view in a Row and between two others' views. The side views move down when autocomplete dropdown is opened. How can I fix this issue?
The Link of GIF file is end of page. in the GIF you can see side views of Autocomplete move to bottom when the suggest items is shows.
My AutoComplete codes:
#Composable
fun AutoCompleteTextField(
modifier: Modifier = Modifier,
list: List<Product>,
searchTerm: TextFieldValue,
updateSearchTerm: (TextFieldValue) -> Unit,
) {
var product by remember {
mutableStateOf("")
}
var heightTextFields by remember {
mutableStateOf(55.dp)
}
var textFieldSize by remember {
mutableStateOf(Size.Zero)
}
var expanded by remember {
mutableStateOf(false)
}
val interactionSource = remember {
MutableInteractionSource()
}
Column(
modifier = modifier
.width(200.dp)
// .padding(30.dp)
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = {
expanded = false
}
)
) {
Column(modifier = modifier.fillMaxWidth()) {
Row(
modifier = modifier
.border(BorderStroke(width = 1.dp, color = Color.LightGray))
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = {product = "" }) {
Icon(
imageVector = Icons.Filled.Add,
contentDescription = "Add",
modifier = modifier
.padding(4.dp)
.align(Alignment.CenterVertically)
)
}
TextField(
modifier = Modifier
.fillMaxWidth()
.height(heightTextFields)
.onGloballyPositioned { coordinates ->
textFieldSize = coordinates.size.toSize()
},
value = product,
onValueChange = {
product = it
expanded = true
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
cursorColor = Color.Black
),
textStyle = TextStyle(
fontFamily = shabnamFontFamily,
color = MaterialTheme.colorScheme.secondary,
fontWeight = FontWeight.Bold,
fontSize = 14.sp,
),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done
),
singleLine = true,
)
}
AnimatedVisibility(visible = expanded) {
Card(
modifier = modifier
.padding(horizontal = 4.dp)
.width(textFieldSize.width.dp),
elevation = 10.dp,
shape = RoundedCornerShape(bottomStart = 4.dp, bottomEnd = 4.dp)
) {
LazyColumn(
modifier = Modifier.heightIn(max = 150.dp),
) {
if (product.isNotEmpty()) {
items(
list.filter {
it.productName.lowercase()
.contains(product.lowercase())
}
) { item ->
ProductItems(title = item.productName) { title ->
product = title
expanded = false
}
}
} else {
items(
items =
list
) { item ->
ProductItems(title = item.productName) { title ->
product = title
expanded = false
}
}
}
}
}
}
}
}
}
}
Screen GIF file
I have created one function called TextInput that contained TextField
#Composable
fun TextInput(
inputType: InputType
) {
var value by remember { mutableStateOf("") }
TextField(
modifier = Modifier.clip(RoundedCornerShape(30.dp)),
value = value,
onValueChange = { value = it },
leadingIcon = { Icon(imageVector = inputType.icon, null) },
label = { Text(text = inputType.label) },
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),
singleLine = true,
keyboardOptions = inputType.keyboardOptions,
visualTransformation = inputType.visualTransformation,
)
}
Now on click of the button SIGN UP\SIGN IN I want to access the value and show success/error based on validation.
Button(
onClick = {
//here
},
modifier = Modifier
.padding(top = 30.dp)
.width(200.dp),
shape = RoundedCornerShape(20.dp)
) {
Text(
text = "SIGN IN",
)
}
==================================================
Button(
onClick = {
//here
},
modifier = Modifier
.padding(top = 5.dp)
.width(200.dp),
shape = RoundedCornerShape(20.dp)
) {
Text(text = "SIGN UP")
}
If you want to see whole code to understand what i mean exactly.
#Composable
fun Sign_in_up_Screen() {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(R.drawable.login),
contentDescription = "",
modifier = Modifier
.background(Color.Companion.Red)
.fillMaxWidth()
)
TopTextButton()
}
}
#Composable
fun Login_Screen() {
val context = LocalContext.current
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(20.dp),
modifier = Modifier.fillMaxSize()
) {
TextInput(InputType.Email)
TextInput(InputType.Password)
Button(
onClick = {
//here
},
modifier = Modifier
.padding(top = 30.dp)
.width(200.dp),
shape = RoundedCornerShape(20.dp)
) {
Text(
text = "SIGN IN",
)
}
}
}
#Composable
fun Signup_Screen() {
val context = LocalContext.current
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(20.dp),
modifier = Modifier.fillMaxSize()
) {
TextInput(InputType.FullName)
TextInput(InputType.Email)
TextInput(InputType.Password)
TextInput(InputType.ConfirmPassword)
Button(
onClick = {
//here
},
modifier = Modifier
.padding(top = 5.dp)
.width(200.dp),
shape = RoundedCornerShape(20.dp)
) {
Text(text = "SIGN UP")
}
}
}
sealed class InputType(
val label: String,
val icon: ImageVector,
val keyboardOptions: KeyboardOptions,
val visualTransformation: VisualTransformation
) {
object FullName : InputType(
label = "Full Name",
icon = Icons.Default.Person,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
visualTransformation = VisualTransformation.None
)
object Email : InputType(
label = "E-mail",
icon = Icons.Default.Email,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
visualTransformation = VisualTransformation.None
)
object Password : InputType(
label = "Password",
icon = Icons.Default.Lock,
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Password
),
visualTransformation = PasswordVisualTransformation()
)
object ConfirmPassword : InputType(
label = "Confirm Password",
icon = Icons.Default.Lock,
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Password
),
visualTransformation = PasswordVisualTransformation()
)
}
#Composable
fun TextInput(
inputType: InputType
) {
var value by remember { mutableStateOf("") }
TextField(
modifier = Modifier.clip(RoundedCornerShape(30.dp)),
value = value,
onValueChange = { value = it },
leadingIcon = { Icon(imageVector = inputType.icon, null) },
label = { Text(text = inputType.label) },
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),
singleLine = true,
keyboardOptions = inputType.keyboardOptions,
visualTransformation = inputType.visualTransformation,
)
}
#Composable
fun TopTextButton() {
var screen by remember { mutableStateOf(false) }
Row(
modifier = Modifier.padding(bottom = 40.dp),
) {
TextButton( onClick = {
if (screen)
screen = !screen
}) {
Text(text = "Sign in")
}
Spacer(Modifier.width(145.dp))
TextButton(onClick = {
if (!screen)
screen = !screen
}) {
Text(text = "Sign up")
}
}
if (!screen){
Login_Screen()
}
if (screen) {
Signup_Screen()
}
}
Is this code correct or should I put a function for each {Textfield}?
So each text field has its own state
I am beginner android studio programming😅
You can add onValueChange param into TextInput like this;
#Composable
fun TextInput(
inputType: InputType,
onValueChange: (String) -> Unit
) {
TextField(
//
onValueChange = {
onValueChange(it)
value = it
}
//
}
print your value;
TextInput(InputType.Email){ textFieldValue ->
println(textFieldValue)
}
I am try to learning text field in android jetpack compose, so I have two text field in a screen, and when I typing somethings in first text field, I want to close keyboard when I click the space on screen. I was using
.pointerInput(Unit) {
detectTapGestures(onTap = {
focusManager.clearFocus()
})
}
this line of code for it, it work, but it is not work for multi textfield like 10 textfield, when I click the 8.textfield for example, bottom screen looks black. I do not have any idea why it is black? Any idea?
#Composable
fun KeyboardSample(){
val focusManager = LocalFocusManager.current
Column(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures(onTap = {
focusManager.clearFocus()
})
}
.padding(start = 16.dp, end = 16.dp),
) {
var name by rememberSaveable { mutableStateOf("") }
val updateName = { _name : String ->
name = _name
}
var amount by rememberSaveable { mutableStateOf("") }
val updateAmount = { _amount : String ->
amount = _amount
}
TextFiledsToExperiment(
name = name,
updateName = updateName,
amount = amount,
updateAmount = updateAmount
)
}
}
#Composable
fun TextFiledsToExperiment(
name : String,
updateName : (String) -> Unit,
amount : String,
updateAmount : (String) -> Unit
){
val focusManager = LocalFocusManager.current
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
OutlinedTextField(
value = name,
onValueChange = updateName ,
label = { Text("Name") },
placeholder = { Text(text = "Name") },
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
autoCorrect = true,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(onNext = {
focusManager.moveFocus(FocusDirection.Down)
}),
modifier = Modifier
.fillMaxWidth()
.padding(top = 6.dp, start = 0.dp, end = 0.dp, bottom = 6.dp),
)
OutlinedTextField(
value = amount,
onValueChange = updateAmount ,
label = { Text("Amount") },
placeholder = { Text(text = "Amount") },
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences,
autoCorrect = true,
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = {
focusManager.clearFocus()
}),
modifier = Modifier
.fillMaxWidth()
.padding(top = 6.dp, start = 0.dp, end = 0.dp, bottom = 6.dp),
)
}
}
You can simply create clickable modifier in your column and run hide function in there.
val keyboardController = LocalSoftwareKeyboardController.current
Column(Modifier.clickable{keyboardController?.hide()}){
//
}
I was making a login for my app in the new android jetpack's compose.
I want to make a OTP layout like in the given photo.
check full example here
const val PIN_VIEW_TYPE_UNDERLINE = 0
const val PIN_VIEW_TYPE_BORDER = 1
#Composable
fun PinView(
pinText: String,
onPinTextChange: (String) -> Unit,
digitColor: Color = MaterialTheme.colors.onBackground,
digitSize: TextUnit = 16.sp,
containerSize: Dp = digitSize.value.dp * 2,
digitCount: Int = 4,
type: Int = PIN_VIEW_TYPE_UNDERLINE,
) {
BasicTextField(value = pinText,
onValueChange = onPinTextChange,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
decorationBox = {
Row(horizontalArrangement = Arrangement.SpaceBetween) {
repeat(digitCount) { index ->
DigitView(index, pinText, digitColor, digitSize, containerSize, type = type)
Spacer(modifier = Modifier.width(5.dp))
}
}
})
}
#Composable
private fun DigitView(
index: Int,
pinText: String,
digitColor: Color,
digitSize: TextUnit,
containerSize: Dp,
type: Int = PIN_VIEW_TYPE_UNDERLINE,
) {
val modifier = if (type == PIN_VIEW_TYPE_BORDER) {
Modifier
.width(containerSize)
.border(
width = 1.dp,
color = digitColor,
shape = MaterialTheme.shapes.medium
)
.padding(bottom = 3.dp)
} else Modifier.width(containerSize)
Column(horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center) {
Text(
text = if (index >= pinText.length) "" else pinText[index].toString(),
color = digitColor,
modifier = modifier,
style = MaterialTheme.typography.body1,
fontSize = digitSize,
textAlign = TextAlign.Center)
if (type == PIN_VIEW_TYPE_UNDERLINE) {
Spacer(modifier = Modifier.height(2.dp))
Box(
modifier = Modifier
.background(digitColor)
.height(1.dp)
.width(containerSize)
)
}
}
}
You can use a very simple layout for each char in the otp.
Something like
#Composable
fun OtpChar(){
var text by remember { mutableStateOf("1") }
val maxChar = 1
Column(Modifier.background(DarkGray),
horizontalAlignment = Alignment.CenterHorizontally){
TextField(
value =text,
onValueChange = {if (it.length <= maxChar) text = it},
modifier = Modifier.width(50.dp),
singleLine = true,
textStyle = LocalTextStyle.current.copy(
fontSize = 20.sp,
textAlign= TextAlign.Center),
colors= TextFieldDefaults.textFieldColors(
textColor = White,
backgroundColor = Transparent,
unfocusedIndicatorColor = Transparent,
focusedIndicatorColor = Transparent)
)
Divider(Modifier
.width(28.dp)
.padding(bottom = 2.dp)
.offset(y=-10.dp),
color = White,
thickness = 1.dp)
}
}
You can add some features like:
manage the focus in Next direction with the TAB key
manage the focus in Previous direction with the BACK SPACE key
how to move to the next textfield when a digit is entered
Something like:
fun OtpChar(
modifier: Modifier = Modifier
){
val pattern = remember { Regex("^[^\\t]*\$") } //to not accept the tab key as value
var (text,setText) = remember { mutableStateOf("") }
val maxChar = 1
val focusManager = LocalFocusManager.current
LaunchedEffect(
key1 = text,
) {
if (text.isNotEmpty()) {
focusManager.moveFocus(
focusDirection = FocusDirection.Next,
)
}
}
Column(
horizontalAlignment = Alignment.CenterHorizontally
){
TextField(
value =text,
onValueChange = {
if (it.length <= maxChar &&
((it.isEmpty() || it.matches(pattern))))
setText(it)
},
modifier = modifier
.width(50.dp)
.onKeyEvent {
if (it.key == Key.Tab) {
focusManager.moveFocus(FocusDirection.Next)
true
}
if (text.isEmpty() && it.key == Key.Backspace) {
focusManager.moveFocus(FocusDirection.Previous)
}
false
},
textStyle = LocalTextStyle.current.copy(
fontSize = 20.sp,
textAlign= TextAlign.Center),
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next
),
colors= TextFieldDefaults.textFieldColors(
backgroundColor = Transparent,
unfocusedIndicatorColor = Transparent,
focusedIndicatorColor = Transparent),
)
Divider(
Modifier
.width(28.dp)
.padding(bottom = 2.dp)
.offset(y = -10.dp),
color = Teal200,
thickness = 1.dp)
}
}
Then just use something like a Row to display 4 OtpChars
val (item1, item2, item3, item4) = FocusRequester.createRefs()
Row(horizontalArrangement = Arrangement.SpaceBetween){
OtpChar(
modifier = Modifier
.focusRequester(item1)
.focusProperties {
next = item2
previous = item1
}
)
OtpChar(
modifier = Modifier
.focusRequester(item2)
.focusProperties {
next = item3
previous = item1
}
)
OtpChar(
modifier = Modifier
.focusRequester(item3)
.focusProperties {
next = item4
previous = item2
}
)
OtpChar(
modifier = Modifier
.focusRequester(item4)
.focusProperties {
previous = item3
next = item4
}
)
//....
}
If you faced keyboard issues try the code below:
#Composable
fun OtpCell(
modifier: Modifier,
value: String,
isCursorVisible: Boolean = false
) {
val scope = rememberCoroutineScope()
val (cursorSymbol, setCursorSymbol) = remember { mutableStateOf("") }
LaunchedEffect(key1 = cursorSymbol, isCursorVisible) {
if (isCursorVisible) {
scope.launch {
delay(350)
setCursorSymbol(if (cursorSymbol.isEmpty()) "|" else "")
}
}
}
Box(
modifier = modifier
) {
Text(
text = if (isCursorVisible) cursorSymbol else value,
style = MaterialTheme.typography.body1,
modifier = Modifier.align(Alignment.Center)
)
}
}
#ExperimentalComposeUiApi
#Composable
fun PinInput(
modifier: Modifier = Modifier,
length: Int = 5,
value: String = "",
onValueChanged: (String) -> Unit
) {
val focusRequester = remember { FocusRequester() }
val keyboard = LocalSoftwareKeyboardController.current
TextField(
value = value,
onValueChange = {
if (it.length <= length) {
if (it.all { c -> c in '0'..'9' }) {
onValueChanged(it)
}
if (it.length >= length) {
keyboard?.hide()
}
}
},
// Hide the text field
modifier = Modifier
.size(0.dp)
.focusRequester(focusRequester),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number
)
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
repeat(length) {
OtpCell(
modifier = modifier
.size(width = 45.dp, height = 60.dp)
.clip(MaterialTheme.shapes.large)
.background(MaterialTheme.colors.surface)
.clickable {
focusRequester.requestFocus()
keyboard?.show()
},
value = value.getOrNull(it)?.toString() ?: "",
isCursorVisible = value.length == it
)
if (it != length - 1) Spacer(modifier = Modifier.size(8.dp))
}
}
}
Result:
First make the common TextField for OTP Screen
#Composable
fun CommonOtpTextField(otp: MutableState<String>) {
val max = 1
OutlinedTextField(
value = otp.value,
singleLine = true,
onValueChange = { if (it.length <= max) otp.value = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone),
shape = RoundedCornerShape(20.dp),
modifier = Modifier
.width(60.dp)
.height(60.dp),
maxLines = 1,
textStyle = LocalTextStyle.current.copy(
textAlign = TextAlign.Center
)
)
}
And Now use above CommonTextField to make four otp Field
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 15.dp, start = 15.dp, end = 15.dp),
horizontalArrangement = Arrangement.SpaceEvenly
) {
CommonOtpTextField(otp = otpOne)
CommonOtpTextField(otp = otpTwo)
CommonOtpTextField(otp = otpThree)
CommonOtpTextField(otp = otpFour)
}
Simple solution that uses one TextField and different code length
#Composable
fun RegistrationCodeInput(codeLength: Int) {
val code = remember { mutableStateOf("") }
val focusRequester = FocusRequester()
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
BasicTextField(
value = code.value,
onValueChange = { if (it.length <= codeLength) code.value = it },
Modifier.focusRequester(focusRequester = focusRequester),
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number),
decorationBox = {
CodeInputDecoration(code.value, codeLength)
})
}
}
#Composable
private fun CodeInputDecoration(code: String, length: Int) {
Box(
modifier = Modifier
.padding(16.dp)
.border(
border = BorderStroke(2.dp, color = borderColor),
shape = Shapes.small
)
) {
Row(
) {
for (i in 0 until length) {
val text = if (i < code.length) code[i].toString() else ""
CodeEntry(text)
}
}
}
}
#Composable
private fun CodeEntry(text: String) {
Box(
modifier = Modifier
.width(42.dp)
.height(42.dp),
contentAlignment = Alignment.Center
) {
Text(text = text)
}
}
#Preview
#Composable
fun PreviewInput() {
RegistrationCodeInput(4)
}
I have a Jetpack Compose (Beta04) BasicTextField (with decorationBox). How can I clear the focus?
I have tried with focusRequester but this doesn't works:
val focusRequester = remember { FocusRequester() }
// ...
BasicTextField(modifier = Modifier.focusRequester(focusRequester), /* ... */)
// ...
placesFocusRequester.freeFocus()
To clear focus from the currently focused component you can use the FocusManager.clearFocus method:
val focusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current
var value by rememberSaveable { mutableStateOf("initial value") }
BasicTextField(
value = value,
onValueChange = { value = it },
decorationBox = { innerTextField ->
Row(
Modifier
.background(Color.LightGray, RoundedCornerShape(percent = 30))
.padding(16.dp)
.focusRequester(focusRequester)
) {
//...
innerTextField()
}
}
)
Button(onClick = { focusManager.clearFocus() }) {
Text("Clear focus")
}
#Composable
fun InputEditText(
value: String,
modifier: Modifier,
onValueChange: (String) -> Unit,
textStyle: TextStyle, hintTextStyle:
TextStyle, placeHolderString: String = "",
enabled: Boolean = true, readOnly: Boolean = false,
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
cursorColor: Color = Color.Black,
imageVector: ImageVector,
iconTint: Color = Color.Gray,
backColor: Color = Color.White,
borderColor: Color = Color.LightGray,
showPassword: Boolean = false,
backGroundShape: Shape = RectangleShape,
passwordVisible: MutableState,
error: String,
howError: Boolean = false
) {
BasicTextField(
visualTransformation = if (showPassword) {
if (!passwordVisible.value) VisualTransformation.None else PasswordVisualTransformation()
} else { VisualTransformation.None },
value = value,
onValueChange = onValueChange,
modifier = modifier,
textStyle = textStyle,
decorationBox = { innerTextField ->
Column {
Row(
modifier = Modifier
.background(backColor, backGroundShape)
.border( width = 1.dp, color = if (showError) Color.Red else borderColor, backGroundShape )
.padding(14.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.Start,
verticalAlignment = CenterVertically
) {
Icon(
imageVector = imageVector,
contentDescription = null,
tint = iconTint,
modifier = Modifier.padding(end = 6.dp)
)
if (value.isEmpty()) {
Text(
text = placeHolderString,
color = hintTextStyle.color,
fontSize = hintTextStyle.fontSize,
fontStyle = hintTextStyle.fontStyle,
fontFamily = hintTextStyle.fontFamily,
textAlign = hintTextStyle.textAlign,
fontWeight = hintTextStyle.fontWeight,
style = hintTextStyle
)
}
innerTextField()
if (showPassword) {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.End
) {
Image(
painter = painterResource(
id = if (!passwordVisible.value)
R.drawable.ic_baseline_visibility_off_24
else R.drawable.ic_baseline_visibility_24
),
contentDescription = "Cart button icon",
modifier = Modifier
.size(24.dp)
.clickable {
passwordVisible.value = !passwordVisible.value
},
colorFilter = ColorFilter.tint(color = iconTint)
)
}
}
if (showError) {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.End
) {
Icon(
imageVector = Icons.Filled.Info,
contentDescription = null,
tint = Color.Red,
modifier = Modifier.padding(end = 6.dp)
)
}
}
}
if (showError) {
Row(modifier = Modifier.fillMaxWidth()) {
Text(
text = error,
modifier = Modifier.fillMaxWidth(),
style = TextStyle(
color = Color.Red,
fontFamily = FontFamily.SansSerif,
fontSize = 11.sp,
textAlign = TextAlign.Start,
)
)
}
}
}
},
enabled = enabled,
readOnly = readOnly,
singleLine = singleLine,
maxLines = maxLines,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
cursorBrush = SolidColor(cursorColor)
)
}