I've developed a textInput composable with a trailing icon, and I'd like to clear the textInput when the icon is clicked. How can I access the textInput value, so that I can clear it?
#Composable
fun TextInput(
myVal: String,
label: String,
placeholder: String="",
helperText: String="",
errorText: String="",
onValueChange : (String) -> Unit){
val hasError = !errorText.isNullOrEmpty()
val helperColor = if (hasError)
Color(0xFFfe392f)
else
Color(0xFF5c6a79)
Row() {
Column() {
TextField(
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color.Transparent,
textColor = Color(0xFF011e41),
cursorColor = Color(0xFF011e41),
focusedLabelColor = Color(0xFF011e41),
unfocusedLabelColor = Color(0xFF011e41),
unfocusedIndicatorColor = Color(0xFFebeced),
focusedIndicatorColor = Color(0xFF011e41),
errorCursorColor = Color(0xFFfe392f),
errorIndicatorColor = Color(0xFFfe392f),
errorLabelColor = Color(0xFFfe392f)
),
value = myVal,
onValueChange = onValueChange,
label = { Text(label) },
placeholder = { Text(placeholder) },
isError = hasError,
trailingIcon = {Icon(Icons.Filled.Email, contentDescription = "sdsd", modifier = Modifier.offset(x= 10.dp).clickable {
//What should I do here?
})}
)
Text(
modifier = Modifier.padding(8.dp),
text = if (hasError) errorText else helperText,
fontSize = 12.sp,
color = helperColor,
)
}
}
}
it's used like this:
var text by remember { mutableStateOf("") }
TextInput(myVal = text, label = "label", helperText = "", errorText = "my error") {text = it}
You can use the trailingIcon attribute with a custom clickable modifier.
Something like:
var text by rememberSaveable { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
trailingIcon = {
Icon(Icons.Default.Clear,
contentDescription = "clear text",
modifier = Modifier
.clickable {
text = ""
}
)
}
)
If you are using a TextFieldValue:
val content = "content"
var text by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(content))
}
TextField(
value = text,
onValueChange = { text = it },
trailingIcon = {
Icon(Icons.Default.Clear,
contentDescription = "clear text",
modifier = Modifier
.clickable {
text = TextFieldValue("")
}
)
}
)
the click handler of your trailing icon has to call the TextField's onValueChange with an empty string:
...
trailingIcon = {
Icon(
Icons.Filled.Email,
contentDescription = "sdsd",
modifier = Modifier
.offset(x= 10.dp)
.clickable {
//just send an update that the field is now empty
onValueChange("")
}
)
}
...
Use trailingIcon Composable property with IconButton to match the background selector of the icon with the rest of the theme. You can also put empty condition to display it only when there is some input in the text field.
Below is sample code snippet:
var text by remember { mutableStateOf ("") }
TextField(
trailingIcon = {
when {
text.isNotEmpty() -> IconButton(onClick = {
text = ""
}) {
Icon(
imageVector = Icons.Filled.Clear,
contentDescription = "Clear"
)
}
}
}
)
This shall achieve this
//Caller
val text by remember { mutableStateOf (...) }
TextInput(text, ..., ...,)
//Composable
#Composable
fun TextInput(text, ..., ...){
val textState by remember { mutableStateOf (text) }
TextField(
value = textState,
trailingIcon = {
Icon(..., Modifier.clickable { textState = "" })
}
}
Related
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'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.
I have created two TextField Email, Password & Button Login. Now on click of that button I want to access text and show success/error based on validation.
The problem is they are in two different composable functions.
#Composable
fun EmailField() {
var email by remember { mutableStateOf("") }
TextField(
modifier = Modifier.fillMaxWidth(0.9f),
colors = TextFieldDefaults.textFieldColors(
textColor = Color.White,
focusedIndicatorColor = Color.White,
focusedLabelColor = Color.White
),
value = email,
onValueChange = { email = it },
label = { Text("Email") },
leadingIcon = {
Icon(
Icons.Filled.Email,
"contentDescription",
modifier = Modifier.clickable {})
}
)
}
Button:
#Composable
private fun LoginButton() {
Button(
onClick = {
// validate email and password here
},
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Yellow,
contentColor = Color.White
)
) {
Text(text = "Login")
}
}
If you want to see whole activity this is how it's structured at the moment.
class LoginActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme {
Column(
modifier = Modifier
.fillMaxSize()
.background(color = MaterialTheme.colors.primary),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(32.dp))
LoginLogo()
Spacer(modifier = Modifier.height(32.dp))
Text(
text = "Login",
modifier = Modifier.fillMaxWidth(0.9f),
style = MaterialTheme.typography.h5,
textAlign = TextAlign.Start
)
Spacer(modifier = Modifier.height(12.dp))
Text(
text = "Please sign in to continue",
modifier = Modifier.fillMaxWidth(0.9f),
style = MaterialTheme.typography.subtitle1,
textAlign = TextAlign.Start
)
Spacer(modifier = Modifier.height(32.dp))
EmailField()
Spacer(modifier = Modifier.height(16.dp))
PassWordField()
Spacer(modifier = Modifier.height(16.dp))
LoginButton()
}
}
}
}
#Composable
private fun LoginButton() {
Button(
onClick = {
// validate email and password here
},
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Yellow,
contentColor = Color.White
)
) {
Text(text = "Login")
}
}
#Composable
fun LoginLogo() {
Image(
painter = painterResource(R.drawable.ic_vector_app_logo),
contentDescription = "Login Logo",
modifier = Modifier
.width(120.dp)
.height(120.dp)
)
}
#Composable
fun EmailField() {
var email by remember { mutableStateOf("") }
TextField(
modifier = Modifier.fillMaxWidth(0.9f),
colors = TextFieldDefaults.textFieldColors(
textColor = Color.White,
focusedIndicatorColor = Color.White,
focusedLabelColor = Color.White
),
value = email,
onValueChange = { email = it },
label = { Text("Email") },
leadingIcon = {
Icon(
Icons.Filled.Email,
"contentDescription",
modifier = Modifier.clickable {})
}
)
}
#Composable
fun PassWordField() {
var password by rememberSaveable { mutableStateOf("") }
TextField(
modifier = Modifier.fillMaxWidth(0.9f),
colors = TextFieldDefaults.textFieldColors(
textColor = Color.White,
focusedIndicatorColor = Color.White,
focusedLabelColor = Color.White
),
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
leadingIcon = {
Icon(
Icons.Filled.Lock,
"contentDescription",
modifier = Modifier.clickable {})
}
)
}
}
What is the right way to handle values in this case?
You can use a ViewModel or something like:
class TextFieldState(){
var text: String by mutableStateOf("")
}
#Composable
fun login(){
var emailState = remember { TextFieldState() }
EmailField(emailState)
LoginButton( onValidate = { /** validate **/})
}
with:
#Composable
fun EmailField( emailState : TextFieldState = remember { TextFieldState() }) {
TextField(
value = emailState.text,
onValueChange = {
emailState.text = it
},
//your code
)
}
and:
#Composable
private fun LoginButton(onValidate: () -> Unit) {
Button(
onClick = onValidate,
//your code
)
}
Here is another solution with rememberSaveable
#Composable
fun MainBody() {
Column(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
) {
var inputValue by rememberSaveable { mutableStateOf("") }
CommonTextField(value = inputValue, onInputChanged = { inputValue = it })
}
}
And here it is defined CommonTextField Function
#Composable
fun CommonTextField(value: String, onInputChanged: (String) -> Unit) {
TextField(value = value,
onValueChange = onInputChanged,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
label = { Text(text = "Enter here")})
}
I have achieved this with the following way :-
#Composable
fun login(){
var dataInput = "xyz#abc.com"
EmailField(dataInput, onChange = { dataInput = it })
LoginButton( onValidate = { /** validate **/})
}
#Composable
fun EmailField(textData: String, onChange: (String) -> Unit = {}) {
var textInput by remember { mutableStateOf(textData) }
TextField(
value = textInput,
onValueChange = {
textInput = it
onChange(it)
},
//your code
)
}
The beauty of this is that it will not recompose all the other views again on changing input for any TextField.
I have a dialog with and an editable textfield. Everything is working fine but I cant't change cursor positon when I have already started editing the field. I have to press the back button and focus it again in correct spot. Any ideas?
#Composable
inline fun DialogInputText(display: MutableState<Boolean>, text: String, title: String, noinline onTextSet: (String)->Unit){
BaseDialog(display = display ) {
var text by remember { mutableStateOf(TextFieldValue(text)) }
DialogHeader(title = title)
EditText(text, { text = it}, modifier = Modifier.padding(8.dp).height(30.dp))
DialogButtons {
TextButton(onClick = {display.value = false} ) {
Text(text = "ZPĚT")
}
TextButton(onClick = {onTextSet.invoke(text.text)}) {
Text(text = "POKRAČOVAT")
}
}
}
}
#Composable
fun EditText(
text: TextFieldValue,
onValueChange: (TextFieldValue)->Unit,
validate: (TextFieldValue)->Boolean = {true},
modifier: Modifier = Modifier,
label: String = "",
textStyle:TextStyle = TextStyle(
fontSize = 16.sp,
fontWeight = FontWeight.Bold
),
keyboardType: KeyboardType = KeyboardType.Text,
color: Color = Colors.ChipGray
){
val valid = validate(text)
val color = if (valid) color else Colors.NotCompleted
Stack(modifier.background(color, shape = RoundedCornerShape(50)), alignment = Alignment.Center) {
if (text.text.isEmpty())
Text(text = label)
BaseTextField(
value = text,
onValueChange = onValueChange,
textStyle = textStyle,
modifier = Modifier.padding(start = 8.dp, end = 8.dp).fillMaxWidth(),
keyboardType = keyboardType,
)
}
}
It was discussed here. But I couldn't get working solution out of it.
Change Cursor Position and force SingleLine of TextField in Jetpack Compose
I want to create textfield with hint text in jetpackcompose. Any example how create textfield using jectpack? Thanks
compose_version = '1.0.0-beta07'
Use parameter placeholder to show hint
TextField(value = "", onValueChange = {}, placeholder = { Text("Enter Email") })
Use parameter label to show floating label
TextField(value = "", onValueChange = {}, label = { Text("Enter Email") })
You can use
the label parameter in the TextField composable to display a floating label
the placeholder parameter to display a placeholder when the text field is in focus and the input text is empty.
You can also use them together.
Something like:
var text by remember { mutableStateOf("text") }
OutlinedTextField(
value = text,
onValueChange = {
text = it
},
label = {
Text("Label")
}
)
or
TextField(
value = text,
onValueChange = {
text = it
},
label = {
Text("Label")
},
placeholder = {
Text("Placeholder")
}
)
You can create hintTextField in jetpackCompose like below code:
#Composable
fun HintEditText(hintText: #Composable() () -> Unit) {
val state = state { "" } // The unary plus is no longer needed. +state{""}
val inputField = #Composable {
TextField(
value = state.value,
onValueChange = { state.value = it }
)
}
if (state.value.isNotEmpty()) {
inputField()
} else {
Layout(inputField, hintText) { measurable, constraints ->
val inputfieldPlacable = measurable[inputField].first().measure(constraints)
val hintTextPlacable = measurable[hintText].first().measure(constraints)
layout(inputfieldPlacable.width, inputfieldPlacable.height) {
inputfieldPlacable.place(0.ipx, 0.ipx)
hintTextPlacable.place(0.ipx, 0.ipx)
} }
}
}
Call #Compose function like below:
HintEditText #Composable {
Text(
text = "Enter Email",
style = TextStyle(
color = Color.White,
fontSize = 18.sp
)
)
}
Jetpack compose version: dev08
The benefit of compose is that we can easily create our widgets by composing current composable functions.
We can just create a function with all parameters of the current TextField and add a
hint: String parameter.
#Composable
fun TextFieldWithHint(
value: String,
modifier: Modifier = Modifier.None,
hint: String,
onValueChange: (String) -> Unit,
textStyle: TextStyle = currentTextStyle(),
keyboardType: KeyboardType = KeyboardType.Text,
imeAction: ImeAction = ImeAction.Unspecified,
onFocus: () -> Unit = {},
onBlur: () -> Unit = {},
focusIdentifier: String? = null,
onImeActionPerformed: (ImeAction) -> Unit = {},
visualTransformation: VisualTransformation? = null,
onTextLayout: (TextLayoutResult) -> Unit = {}
) {
Stack(Modifier.weight(1f)) {
TextField(value = value,
modifier = modifier,
onValueChange = onValueChange,
textStyle = textStyle,
keyboardType = keyboardType,
imeAction = imeAction,
onFocus = onFocus,
onBlur = onBlur,
focusIdentifier = focusIdentifier,
onImeActionPerformed = onImeActionPerformed,
visualTransformation = visualTransformation,
onTextLayout = onTextLayout)
if (value.isEmpty()) Text(hint)
}
}
We can use it like this:
#Model
object model { var text: String = "" }
TextFieldWithHint(value = model.text, onValueChange = { data -> model.text = data },
hint= "Type book name or author")
The pitfall of this approach is we are passing the hint as a string so if we want to style the hint we should add extra parameters to the TextFieldWithHint (e.g hintStyle, hintModifier, hintSoftWrap, ...)
The better approach is to accept a composable lambda instead of string:
#Composable
fun TextFieldWithHint(
value: String,
modifier: Modifier = Modifier.None,
hint: #Composable() () -> Unit,
onValueChange: (String) -> Unit,
textStyle: TextStyle = currentTextStyle(),
keyboardType: KeyboardType = KeyboardType.Text,
imeAction: ImeAction = ImeAction.Unspecified,
onFocus: () -> Unit = {},
onBlur: () -> Unit = {},
focusIdentifier: String? = null,
onImeActionPerformed: (ImeAction) -> Unit = {},
visualTransformation: VisualTransformation? = null,
onTextLayout: (TextLayoutResult) -> Unit = {}
) {
Stack(Modifier.weight(1f)) {
TextField(value = value,
modifier = modifier,
onValueChange = onValueChange,
textStyle = textStyle,
keyboardType = keyboardType,
imeAction = imeAction,
onFocus = onFocus,
onBlur = onBlur,
focusIdentifier = focusIdentifier,
onImeActionPerformed = onImeActionPerformed,
visualTransformation = visualTransformation,
onTextLayout = onTextLayout)
if (value.isEmpty()) hint()
}
}
We can use it like this:
#Model
object model { var text: String = "" }
TextFieldWithHint(value = model.text, onValueChange = { data -> model.text = data },
hint= { Text("Type book name or author", style = TextStyle(color = Color(0xFFC7C7C7))) })
var textState by remember { mutableStateOf(TextFieldValue()) }
var errorState by remember { mutableStateOf(false) }
var errorMessage by remember { mutableStateOf("") }
TextField(
value = textState,
onValueChange = {
textState = it
when {
textState.text.isEmpty() -> {
errorState = true
errorMessage = "Please Enter Site Code"
}
else -> {
errorState = false
errorMessage = ""
}
}
},
isError = errorState,
label = {
Text(
text = if (errorState) errorMessage
else "You Hint"
)
},
modifier = Modifier
.padding(top = 20.dp, start = 30.dp, end = 30.dp)
.fillMaxWidth())
If you want to create a text field with hint text and custom color here is the code for that.
#Composable
fun PhoneOrEmail() {
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
label = { Text("Phone/email", style = TextStyle(color =
Color.Red)) }
)//End of TextField
}//End of Function
Here's what works for me (I think it's a bit simpler than what Anas posted since it's using the same component:
#Composable
fun TextBox(
loginInput: LoginInput,
hint: String = "enter value",
color: Color = Color.LightGray,
height: Dp = 50.dp
) {
val state = +state { "" }
state.value = if (loginInput.usernameEntered) loginInput.username else hint
Surface(color = color) {
Row {
Container(modifier = Expanded, height = height) {
Clip(shape = RoundedCornerShape(15.dp)) {
Padding(padding = 15.dp) {
TextField(
value = state.value,
keyboardType = KeyboardType.Text,
onFocus = {
if (!loginInput.usernameEntered)
state.value = ""
},
onValueChange = {
loginInput.usernameEntered = true
loginInput.username = it
state.value = loginInput.username
}
)
}
}
}
}
}
}
the label parameter will be displayed as text if text is empty and moves above the textfield (as label) on typing input:
#Composable
fun SearchField() {
val (text, setText) = remember { mutableStateOf(TextFieldValue("")) }
Box(modifier = Modifier.width(180.dp).padding(2.dp)) {
TextField(
modifier = Modifier.fillMaxWidth(),
value = text,
onValueChange = { setText(it) },
label = { Text("quick do:") },
)
}
}