Я хочу реализовать текстовое поле. Это текстовое поле должно отображать небольшой смайлик или изображение вместо текста при введении конкретного токена. < /P>
Вы можете найти такой случай в приложении Slack. Slack App поддерживает пользовательские смайлики в дополнение к обычным смайкам.
Код: Выделить всё
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()
}
}
)
< /code>
А вот и другие функции: < /p>
@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
}
< /code>
Вот визуальная трансформация: < /p>
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
Это делает поведение курсора очень неустойчивым. При использовании InlineTextContent и Visualtransformation больше подход. < /p>
Как я могу эффективно реализовать это текстовое поле? [Редактировать 1] < /h3>
Еще один вопрос: < /p>
в приложении Slack, размещая курсор непосредственно после смайлика и нажатия Ключ Backspace удаляет смайлики. быть обнаженным. < /p>
Например, вместо того, чтобы удалить весь ток Последний кудрявый скоба '}' удаляется, оставляя "{: ab_12:" expened. < /p>
Как мы должны обрабатывать удаление всего токена при нажатии клавиши Backspace? < /p>
[edit 2] < /h3>
, чтобы разрешить правильно удалить эмодзи, когда пользователь помещает Курсор непосредственно после него и нажимает клавишу Backspace, необходимо более сложное управление курсором. < /p>
Я не уверен, что это даже возможно. Как правило, в BasicTextfield, когда нажата клавиша BackSpace, текст уже удален, что затрудняет определение того, какой символ был удален. Представление одного пустого символа (Unicode, например, U+0020 ), а не назначение строки, содержащей токен, значению BasicTextField может быть лучшим способом обработки списка Ключ. < /p>
Я также попытался передать TextFieldValue вместо строки значения BasicTextField, но это также не смог достичь цели. < /p>
Хотя я удалось заменить токен изображением в аннотированном строительстве при создании TextFieldValue в OnValueChange, когда строка заменит пустой символ Unicode, снова вызывается в OnValueChange, информация о позиции Аннотированный в AnnotatedString сброшен. Как они могли это реализовать?
Подробнее здесь: [url]https://stackoverflow.com/questions/78145214/android-compose-textfield-with-image-using-inlinetextcontent[/url]