Skip to content

Instantly share code, notes, and snippets.

@thc282
Last active April 13, 2024 18:22
Show Gist options
  • Save thc282/bdc32ddd859d2ec568a73931abd649ae to your computer and use it in GitHub Desktop.
Save thc282/bdc32ddd859d2ec568a73931abd649ae to your computer and use it in GitHub Desktop.
JetPack Compose Customize TextField + Error Message (Fix Text cutting when height is small) [Default style = OutlinedTextField] <Android>

Design Layout

image

With Text Content Compare

image

implementation(libs.androidx.material.icons.extended.v165)
var email by remember { mutableStateOf("") }
var isEmailValid by remember { mutableStateOf(false) }
//Calling the function
CustomOutlinedTextField(
value = email,
onValueChange = {
email = it
isEmailValid = isValidEmail(it)
},
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.height(40.dp),
errorMessage = if (isEmailValid) null else "Invalid email. Format: aaa@bbb.ccc",
placeholderText = ""
/*Adding & follow any other parameters in the function*/
)
//Customized TextField
@Composable
fun CustomOutlinedTextField(
value: String,
onValueChange: (String) -> Unit,
singleLine: Boolean = false,
modifier: Modifier = Modifier,
errorMessage: String? = null,
leadingIcon: (@Composable () -> Unit)? = null,
trailingIcon: (@Composable () -> Unit)? = null,
placeholderText: String = "Placeholder",
fontSize: TextUnit = MaterialTheme.typography.bodyMedium.fontSize
/*Adding any other parameters*/
) {
//For changing the text while typing
var value by rememberSaveable { mutableStateOf(value) }
Column{
BasicTextField(
modifier = modifier
.background(
MaterialTheme.colorScheme.surface,
MaterialTheme.shapes.small,
)
.fillMaxWidth()
.padding(top = 4.dp)
.border(1.dp, MaterialTheme.colorScheme.outline , RoundedCornerShape(4.dp)), // Border Style
value = value,
onValueChange = {
value = it //Update the text
onValueChange(it) //Pass the result back
},
singleLine = singleLine,
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
textStyle = LocalTextStyle.current.copy( /* */
color = MaterialTheme.colorScheme.onSurface, /* Input text style */
fontSize = fontSize /* */
),
decorationBox = { innerTextField ->
Row(
modifier = Modifier.padding(
start = 16.dp
),
verticalAlignment = Alignment.CenterVertically
) {
if (leadingIcon != null) leadingIcon()
Box(Modifier.weight(1f)) {
if (value.isEmpty())
Text(
text = placeholderText,
style = LocalTextStyle.current.copy(
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f),
fontSize = fontSize
),
)
innerTextField()
}
if (!errorMessage.isNullOrEmpty()) {
Icon(
imageVector = Icons.Default.Error, //need to implement extend Icon library
contentDescription = "Error Icon",
tint = MaterialTheme.colorScheme.error
)
}else if (trailingIcon != null) trailingIcon()
}
}
)
//Error message when invalid
if (!errorMessage.isNullOrEmpty()) {
Text(
text = errorMessage,
color = MaterialTheme.colorScheme.error,
fontSize = 12.sp
)
}
}
}
fun isValidEmail(email: String): Boolean {
val emailRegex = "^[A-Za-z](.*)([@]{1})(.{1,})(\\.)(.{1,})".toRegex()
return emailRegex.matches(email)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment