Hello, I’m doing some fancy stuff with `AnnotatedS...
# compose
o
Hello, I’m doing some fancy stuff with
AnnotatedString
and
InlineTextContent
and what blocks me is the static structure of
Placeholder
’s width & height. What I’d like to have is placeholder’s size to be derived from the text measurements it replaces. For example, like
this text in Slack
I’d like to put background (that I can with SpanStyle) and a border (which is missing from SpanStyle) with rounded rectangle (also not in SpanStyle). I could do this easily with
InlineTextContent
if only I could measure it relative to text size, e.g. with some margins/paddings, etc. Any ideas? Thanks!
k
I am in the same boat. I need to know the text measurement to properly define the width of my placeholder. The problem I could not work around is the fact that you can't call composable code when building the AnnotatedString. Making SubcomposeLayout not usable. For those curious: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1655638077840329
c
@Halil Ozercan weren't you doing a bunch of text based stuff like this a while back?
h
I'm doing a bunch of text based stuff as my job now 😂 For the question, placeholder takes TextUnit as width and height. Wouldn't using
1.em
work in your case? Ofc width is another question. You can then use onTextLayout callback to get a TextLayoutResult and find the bounding box for your replaced text. I'm on mobile right now so I cannot go into detail easily. You can always create a feature request through the issue tracker
k
@Halil Ozercan can you show how the
TextLayoutResult
would work with the placeholder together?
TextLayoutResult
would need to be called in a composable context, probably the
children
argument of
InlineTextContent
. But how do you propagate the width information to the placeholder? AFAIK the placeholder data is used to layout the text and only then the
children
are evaluated. See my previous answer and the link where I posted my code. I do not see a way on how to propagate that information. I think this is only a problem for me since I calculate the
AnnotatedString
based on my composable input. I
remember
the input, thus disallowing composable context during calculation. The only composable context I have is the
children
property.
Copy code
@Composable
fun UI (textData: List<TextData>) {
    val (annotatedText, inlineContent) = remember { calculateContent(textData = textData) }
    Text(text = text, inlineContent = inlineContent)
}

private fun calculateContent(textData: List<TextData>): Pair<AnnotatedString, Map<String, InlineContent>> {
    val inlineContent = mutableMapOf<String, InlineContent>()
    return buildAnnotatedString {
        // ...
    } to inlineContent
}
o
@Halil Ozercan I don’t think onTextLayout can be good enough solution here. First, it will cause double layout, because first it will layout with just text, and then I have to replace text with inline content with calculated width. Second, I will need to separate each occurrence of inline content with unique tag, because each of them would be of unique width (not a big deal, but additional complexity). Third, it would be really hard to “library-ize” it and make a modifier or custom component. Ideally, I want a component that behaves kinda like
<span>
in HTML, including text. So content can keep flowing from left to right (or RTL), and wrapping when needed, even in the middle of the text.
As an example, consider rendering something like single chat message here in the thread – with code blocks,
code spans
, people mentions, links (with hover effects) etc.
Alternative: • add padding/spacing (horizontal start/end only) to SpanStyle to add before/after span • add drawBehind callback to SpanStyle, so I can paint anything I need before text is rendered That would solve most of my current needs for text formatting
h
onTextLayout
is definitely not a good solution. It can be a workaround until a better API is added.
https://issuetracker.google.com/u/1/issues/237095661 this issue was created yesterday, please also +1
o
Okay, then I’ll file an issue about spacing before/after text https://issuetracker.google.com/u/1/issues/237253250
I see there were experiments by @Zach Klippenstein (he/him) [MOD] on rich content inside the text, via composable content, modifiers, MeasuredText, etc back in March. Is there some progress along these lines, or were they deprioritized or something? Like this: https://android-review.googlesource.com/c/platform/frameworks/support/+/2045124
k
It seems that 1.3.0 contains a new TextMeasurer that lays out text the same way that BsicText would do.
o
Thanks, will take a look
z
The priority hasn't really changed, we’ve got more critical bugs and performance issues to work on before really diving into real design work for that stuff. My experiments were just hopefully seeds for when we get around to that
190 Views