Sharing my modifier for onFocusChanged on a textFi...
# compose
c
Sharing my modifier for onFocusChanged on a textField. Let me know if anyone see any improvements
Copy code
fun Modifier.onFocusLost(onFocusLost: ()-> Unit) = composed {
    var isFocused: Boolean by remember { mutableStateOf(false) }
    Modifier.onFocusChanged {
        if(isFocused == true && it.isFocused == false){
            isFocused = it.isFocused
            onFocusLost()
        } else {
            isFocused = it.isFocused
        }
    }
}
🔥 4
🟰 1
true 1
h
Just maybe a little off topic, but using
composed
to create custom modifiers is no longer recommended; instead, they go with nodes. https://developer.android.com/develop/ui/compose/custom-modifiers#implement-custom
☝🏼 1
p
Copy code
fun Modifier.onFocusLost(
    listener: () -> Unit
): Modifier {
    return this then FocusLostListenerModifierNodeElement(listener)
}

class FocusLostListenerNode(
    internal var listener: () -> Unit
) : Modifier.Node(), FocusEventModifierNode {

    private var hasFocus: Boolean = false

    override fun onFocusEvent(focusState: FocusState) {
        if (focusState.hasFocus) {
            hasFocus = true
        } else if (hasFocus) {
            hasFocus = false
            listener()
        }
    }
}

data class FocusLostListenerModifierNodeElement(
    val listener: () -> Unit
) : ModifierNodeElement<FocusLostListenerNode>() {

    override fun create() = FocusLostListenerNode(listener)

    override fun update(node: FocusLostListenerNode) {
        node.listener = listener
    }
}
💯 1
c
Interesting how much more complex that modifier becomes with nodes... 🤯
1
f
How about
@Composable
Modifier?
Copy code
@Composable
fun Modifier.onFocusLost(onFocusLost: () -> Unit): Modifier {
    var isFocused: Boolean by remember { mutableStateOf(false) }
    return this then Modifier.onFocusChanged {
        if (isFocused == true && it.isFocused == false) {
            isFocused = it.isFocused
            onFocusLost()
        } else {
            isFocused = it.isFocused
        }
    }
}
p
Interesting how much more complex that modifier becomes with nodes...
But this is more performant solution.
a
> Interesting how much more complex that modifier becomes with nodes... I haven't looked at the node API for that reason. @Colton Idle I use a similar pattern on Paper. I have a dedicated TextField() component that has a
onMovedAway
callback, having a similar logic as the one u shared. very handy for knowing when the text field is no longer in focused
👍 1
c
cool. I guess I will steal the node based one here since its more performant. I wonder if there should be some lint checks for this. also... i wonder how chatgpt would do in transforming my original one. will give it a try soon.
f
I think the performance point to note is that recomposition is not skipped if using
composed
.