I was trying to read the focus state in BasicTextF...
# compose
m
I was trying to read the focus state in BasicTextField decorationBox based on this but it doesn't seem to work. Minimum reproduction in 🧵 (print never fires)
Copy code
val interactionSource = remember { MutableInteractionSource() }

        BasicTextField(
            value = "",
            onValueChange = {},
            interactionSource = interactionSource,
            decorationBox = {
                Box(Modifier
                    .focusable(interactionSource = interactionSource)
                    .onFocusChanged { println(it) }
                ) {

                }
            }
        )
z
Focus observer modifiers apply to the next focusable after them – i think switching the order of your
focusable
and
onFocusChanged
should work.
That said, text fields are already focusables. I think what you want to do here is just pass
onFocusChanged
to the
BasicTextField
itself
m
switching them doesn't change anything, unfortunately 😕 I guess I could just pass the focused state to the decorationBox composable (this example was simplistic, of course it's a much larger and more complicated thing). but that feels weird and also the docs do suggest something else (although not directly)
c
I think you should collect the focused state using the
collectIsFocusedAsState
helper method like this
val focused by interactionSource.collectIsFocusedAsState()
See it in action inside
androidx.compose.material.TextFieldImpl.kt
m
I did something like this for test and it didn't work either. Something like
Copy code
val interactionSource = remember { MutableInteractionSource() }
        val focusedState = interactionSource.collectIsFocusedAsState()
        println("A $focusedState")
        BasicTextField(
            value = "",
            onValueChange = {},
            interactionSource = interactionSource,
            decorationBox = {
                MyDecorationBox(interactionSource)
            }
        )

@Composable fun MyDecorationBox(interactionSource: MutableInteractionSource){
        val focusedState = interactionSource.collectIsFocusedAsState()
        println("B $focusedState")
}
will only print A, not B, somehow
z
m
Hmm, that's basically passing the focused state from outside the decorationbox. If you extract the decorationbox composable and pass the interactionsource as a its param, it will not work, right? I don't understand why the focused state isnt passed. Not sure what is parent and what child in the basictextfield/decorationbox relation, that might be the issue
z
The
BasicTextField
itself is what is focusable. Internally, there is a
Box
around the
decorationBox
function and that outer box is what has the focus modifier, which is what the
MutableInteractionSource
is passed to. So it ends up looking like this:
Copy code
BasicTextField
  Box(Modifier.….focusable())
    decorationBox
      TextInputArea
I think you’ll get some weird behavior if you try to make anything inside the
decorationBox
function focusable, since the text field assumes the outer box is focusable “leaf”.
What are you trying to do, actually? I don’t think the decoration box is the way to do it. If you have modifiers you want to pass to the text field, pass them to the text field.
m
I have a decoration box with lots of stuff going on and this box also changes appearance based on whether it's focused or not. I wanted to observe the focused state inside of it. The right way to do that (based on the docs I pasted earlier and some SO answers) seemed to be to share the interactionsource between the basic text field and its decoration box. But that doesn't work. I guess I can observe the focused state in the composable wrapping basictextfield and pass it down to decorationbox...
z
Your decoration box can observe focus state fine, that’s how material text’s decoration box works, and that snippet in the video I posted. What your code was trying to do is define another focusable node as part of the decoration box. That’s different than simply observing the focus state of the field.
Copy code
@Composable
fun YourTextField(/* … */) {
    val interactionSource = remember { MutableInteractionSource() }
    BasicTextField(
        value = "",
        onValueChange = {},
        interactionSource = interactionSource,
        decorationBox = { field ->
            InfinitelyComplexDecorationBox(interactionSource, field)
        }
    )
}

@Composable
private fun InfinitelyComplexDecorationBox(
    interactionSource: InteractionSource,
    field: @Composable () -> Unit
) {
    // have fun
}
m
(I'm on my phone now so I might be missing something obvious)
z
Yep, the important parts are exactly the same
That should work
m
So this didn't work. However when I tried I've been on 1.1.0-rc3. Didn't try with newest version yet
Will try tomorrow. If it doesn't work either, do you think I should report?
z
I assumed you’d tried this with more realistic code. The reason you didn’t recompose is because you’re calling
toString()
on a
MutableState
, which doesn’t perform a snapshot-aware read of the internal value. In real code, where you’d actually the state value itself, it would work.
so either
println("B ${focusedState.value}")
or
val focusedState by interactionSource.collect…
m
Hmmm I did try that with realistic code, this was just a quick example. But I've tried many things and now I'm a bit confused, I might have messed it somewhere else. Need to revisit the issue, will let you know. Anyway, I really appreciate your help, thank you so much :)
z
If I copy your code and don’t read the value, I can reproduce your issue, but it works correctly when i read the actual value.
🙏 1
Feel free to come back and post more of your actual code tomorrow if you still can’t figure it out
m
I have no idea what I messed up earlier, thought I had exactly the same code as now, but there must have been something that prevented it from working right. Works for both 1.1.1 and 1.1.0-rc03. Thank you for your help Zach 🙂
z
Not sure what you mean. Are you wondering how to write custom modifiers?
l
Yes
And is there a main logic to follow ?
z
DMing you since this isn’t really related to the rest of this thread
129 Views