How can I add a suffix to TextField
input that flows (moves) with the user input text?
How to add uneditable postfix (suffix) to TextField in Jetpack Compose?
Asked Answered
With M3 starting from the 1.1.0-alpha06
you can use the suffix
attribute:
TextField(
value = text,
onValueChange = { text = it },
suffix = { Text ("€") }
)
Before M3 1.1.0-alpha06
or with M2 or you can use the visualTransformation
attribute.
Something like:
TextField(
value = text,
onValueChange = { text = it },
singleLine = true,
visualTransformation = SuffixTransformation(" €"),
)
class SuffixTransformation(val suffix: String) : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
val result = text + AnnotatedString(suffix)
val textWithSuffixMapping = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
return offset
}
override fun transformedToOriginal(offset: Int): Int {
if (text.isEmpty()) return 0
if (offset >= text.length) return text.length return offset
}
}
return TransformedText(result, textWithSuffixMapping )
}
}
If you have the placeholder you can put a condition in the visualTransformation
attribute.
Something like:
TextField(
value = text,
onValueChange = { text = it },
singleLine = true,
visualTransformation = if (text.isEmpty())
VisualTransformation.None
else
SuffixTransformation(" €"),
placeholder = { Text("Placeholder") }
)
Thanks for the answer. But this was a self-answered question. I think you didn't notice that :) What do you think of my answer? Actually, I derived it from one of your posts! –
Lajuanalake
Thank you for your answer, very useful 👍 (just check the suggestion of Martynas B, it's right.) If it can be useful to someone, I use this code to avoid overlapping when using BasicTextField with placeholder : ` var suffixLocal: String = "" // avoid to overlap placeholder if (!text.isEmpty()) suffixLocal = suffix val result:AnnotatedString = text + AnnotatedString(suffixLocal) val suffixOffset = suffixLocal.length ` –
Showers
@Showers thanks for the feedback. I've update the answer with the placeholder scenario. I would prefer to put a condition in the
visualTransformation
attribute just to have more flexibility. For example you can also handle the focus state with a placeholder. –
Apocynaceous what is M3 and im not able to see any suffix property i can see only trailingIcon which accepts a compose object –
Croquette
@Croquette developer.android.com/jetpack/androidx/releases/… –
Apocynaceous
@GabrieleMariotti how can I do this? when I try I'm able to see only trailingIcon and its adding some padding and looks weird for my suffix icon –
Croquette
I found Gabriele Mariotti's answer buggy. Needed to change transformedToOriginal
function to this:
override fun transformedToOriginal(offset: Int): Int {
if (offset > text.length) return text.length
return offset
}
it's right, without this correction it gives errors like this, in my case happens with 2 fields, moving cursor by clicking from one to another o something else:
java.lang.IllegalStateException: OffsetMapping.transformedToOriginal returned invalid mapping: 5 -> 5 is not in range of original text [0, 4]
–
Showers This is easily done in Compose like this:
const val SUFFIX = " $"
@Composable
fun SuffixedText() {
var text by remember { mutableStateOf("") }
TextField(
text,
singleLine = true,
visualTransformation = SuffixTransformer(SUFFIX),
onValueChange = { text = it }
)
}
class SuffixTransformer(val suffix: String) : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
val result = text + AnnotatedString(suffix)
return TransformedText(result, OffsetMapping.Identity)
}
}
The above component probably can be used in traditional Views too. See this post
Also, see the following:
It has some issues. For example if you click in the suffix (inside o just after the last character) the code crashed because of OffsetMapping.Identity –
Apocynaceous
I tied it in a Desktop app using Compose Multiplatform v1.2.1 which uses Compose v??? on Windows and did not encounter any error. Maybe it's a regression in newer versions of Compose? –
Lajuanalake
OffsetMapping.identity cause crash on Android. You should add the offset mapping.
class PreSuffixTransformer(val prefix: String = "", val suffix: String = "") : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
val result = AnnotatedString(prefix) + text + AnnotatedString(suffix)
val offsetMapping = object : OffsetMapping {
override fun originalToTransformed(offset: Int) =
offset + prefix.length
override fun transformedToOriginal(offset: Int) =
if(text.length < offset){
text.length
} else if(offset < prefix.length){
0
}else {
offset - prefix.length
}
}
return TransformedText(result, offsetMapping)
}
}
© 2022 - 2024 — McMap. All rights reserved.