https://kotlinlang.org logo
#compose
Title
# compose
i

Ian Warwick

01/10/2020, 8:43 AM
Morning folks, is there any way to detect clicks further up the compose tree? I have a child that toggles visibility of a local element, but I want the clicks on the root to cancel (basically a pop up box that when you click outside of the popup it will close it)
When I click Hello World, the popup below is shown using
DropDownPopup
when I click out of the popup anywhere I want it to close 🤔 without passing a listener down the tree would be cool, I guess I could use
+ambient
somehow though not sure of the best way
m

matvei

01/10/2020, 11:09 AM
I don't think using ambient will be the right approach here. If you want parent to be able to control state of the child, why are you hesitating to bubble up this state? e.g.
Copy code
@Composable fun RootComponent() {
    var popupOpen by state { false }
    Clickable(onClick = { popupOpen = fasel } ) {
    SomeLayoutToPositionSomewhere() {
        DropDownItem(open = popupOpen, onPopupOpen = { popupOpen = true })
    }
Doesn't look that scary, does it? 🙂
i

Ian Warwick

01/10/2020, 11:12 AM
Ok, really hesitating because it depends how far down the tree the popup is and how to make it scalable say if you have X number of popups
m

matvei

01/10/2020, 11:12 AM
With ambients, this very explicit state becomes implicit, which will easily lead to complicating when project/screen will grow or when you start to refactor something.
i

Ian Warwick

01/10/2020, 11:13 AM
cool yeh sounds like ambients is not the right solution though passing down state from up above depends on how far that drop down is
m

matvei

01/10/2020, 11:13 AM
Re scalability:
Copy code
DropDownItem(open = popupOpen, onPopupOpen = { popupOpen = true })
I think this gives you a lot of flexibility and scalability, TBH. It's stateless, so you can put it on any screen, with any architecture and its parameter set clearly indicated expectations from the callee
With ambients, it will be the same, but way less obvious for the code reader / for future yourself
i

Ian Warwick

01/10/2020, 11:15 AM
yeh maybe I am missing something but if
Copy code
SomeLayoutToPositionSomewhere() {
        DropDownItem(open = popupOpen, onPopupOpen = { popupOpen = true })
was somewhere else in another file>? would need to pass
popupOpen
as an argument
m

matvei

01/10/2020, 11:17 AM
True, because it becomes the contract of this composable as well
i

Ian Warwick

01/10/2020, 11:18 AM
cool, and if I had more than one popup then I would need ot declare state
popupOpen1
popupOpen2
etc?
m

matvei

01/10/2020, 11:20 AM
More than one popup on the screen? Yes, it seems like you want to have state for every popup, or you can create one state to hold everything, e.g.
data class ScreenState(val popup1Open: Boolean, val popup2Open: Boolean)
and copy and propogate new state every time
i

Ian Warwick

01/10/2020, 11:21 AM
yeh that could work nicely 🙂 maybe that would be the best approach
Thanks @matvei! 🙂
m

matvei

01/10/2020, 11:23 AM
No problem 🙂
6 Views