Android Compose Textfield с изображением с использованием inlinetextcontentAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Android Compose Textfield с изображением с использованием inlinetextcontent

Сообщение Anonymous »

Я разрабатываю приложение для Android с помощью JetPack Compose. < /p>
Я хочу реализовать текстовое поле. Это текстовое поле должно отображать небольшой смайлик или изображение вместо текста при введении конкретного токена. < /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]
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»