Я разрабатываю приложение для Android с помощью Jetpack Compose.
Я хочу реализовать TextField. Это TextField должно отображать небольшой смайлик или изображение вместо текста при вводе определенного токена.
Такой случай можно найти в приложении Slack. Приложение Slack поддерживает собственные смайлы в дополнение к обычным смайлам.
InlineTextContent я обнаружил в качестве подсказки.
Код: Выделить всё
val inlineContentMap = mapOf(
"ab_12" to emojiImage("https://c.tenor.com/Rd6ULrCRvlQAAAAd/tenor.gif")
)
var inputText by remember { mutableStateOf("") }
BasicTextField(
value = inputText,
onValueChange = {
inputText = it
},
modifier = Modifier
.fillMaxWidth()
.border(1.dp, Color.LightGray, RoundedCornerShape(4.dp))
.padding(8.dp),
textStyle = TextStyle(fontSize = 16.sp).copy(color = Color.Transparent),
visualTransformation = EmojiVisualTransformation,
decorationBox = { innerTextField ->
Box(
modifier = Modifier,
contentAlignment = Alignment.TopStart
) {
val annotatedString = replaceTokens(inputText)
Text(
text = annotatedString,
style = TextStyle(fontSize = 16.sp),
inlineContent = inlineContentMap
)
innerTextField()
}
}
)
Код: Выделить всё
@Composable
private fun emojiImage(imgUrl: String) =
InlineTextContent(Placeholder(16.sp, 16.sp, PlaceholderVerticalAlign.TextCenter)) {
val context = LocalContext.current
val imageLoader = ImageLoader.Builder(context)
.components {
add(ImageDecoderDecoder.Factory())
}
.build()
Image(
painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(context)
.data(data = imgUrl)
.build(),
imageLoader = imageLoader
),
contentDescription = null,
modifier = Modifier.size(16.dp),
)
}
private fun replaceTokens(input: String): AnnotatedString {
val annotatedString = buildAnnotatedString {
val regex = Regex("\\{:(\\w+_\\d+):\\}")
var currentIndex = 0
regex.findAll(input).forEach { matchResult ->
val token = matchResult.groupValues[1]
val tokenIndex = matchResult.range.first
val tokenLength = matchResult.value.length
append(input.substring(currentIndex, tokenIndex))
appendInlineContent(id = token)
currentIndex = tokenIndex + tokenLength
}
append(input.substring(currentIndex, input.length))
}
return annotatedString
}
Код: Выделить всё
object EmojiVisualTransformation: VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
val originText = text.text
val annotatedString = replaceTokens(originText)
return TransformedText(annotatedString, EmojiOffsetMapping(originText, annotatedString.text))
}
}
data class EmojiOffsetMapping(
private val origin: String,
private val transformed: String,
): OffsetMapping {
private val tokenPositionRanges = mutableListOf()
init {
val regex = Regex("\\{:(\\w+_\\d+):\\}")
regex.findAll(origin).forEach { matchResult ->
val tokenPosition = matchResult.range
tokenPositionRanges.add(tokenPosition)
}
}
private fun getTransformedOffset(offset: Int): Int {
if (offset == 0) {
return 0
}
var newOffset = offset
tokenPositionRanges.forEachIndexed { index, tokenRange ->
if (tokenRange.first + 1
Источник: [url]https://stackoverflow.com/questions/78145214/android-compose-textfield-with-image-using-inlinetextcontent[/url]
Мобильная версия