https://kotlinlang.org logo
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
benchmarks
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
confetti
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
lincheck
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by
Title
m

Manuel Unterhofer

02/17/2023, 2:58 PM
Hey there! What’s the Compose way of sharing focus between two UI elements? I’m trying to replicate this view which shares focus between an input and a list so that the user can both type a search query and use the arrow keys and return to select results without switching back and forth via ⇥
v

vide

02/17/2023, 6:05 PM
I don't unfortunately have a solution but I am interested if there's a native way to do this
r

Ruckus

02/17/2023, 6:46 PM
Not sure if there's a different idiomatic way in compose, but generally (in other UI frameworks) the idea is to capture up and down arrow key press events in the input and update the selected index of the list accordingly. It's not "shared focus", as only the input is focused, but there's nothing stopping input on one element to impact the state elsewhere in the app (that's kind of the whole point of event handling).
m

Manuel Unterhofer

02/18/2023, 7:18 AM
Thanks @Ruckus! I was hoping for there to be a composable way where I don’t have to know about the keys that I need to send elsewhere, and where I don’t have to fake focus styling in one part. The problem is that there might be special key handlers and different child components in the list items of the result list, which should be encapsulated there with their own key handlers and based on their own focus state. But neither will work if I have to intercept key events at the top level and if the list doesn’t actually receive focus
r

Ruckus

02/23/2023, 4:55 PM
The problem is that there might be special key handlers...
What do you mean by this? If you're talking about a list view that you create, you could just extract the handlers into functions and call them from both the list or the input depending on who has focus. If you're talking about arbitrary composables, that's a whole different can of worms. A workaround I've used in other UI toolkits is to grab a reference to the target node (e.g. the list) and call it's event handler directly passing in either the event captured from the input, or a new event I constructed for more fine grained control. However, considering UI nodes are functions instead of objects in Compose, I'm not sure what the correct way to go about doing that is.
In both of these cases, I think it's important to point out that there's still only one element with focus. While the idea of multiple focus (each element handling the input it's designed to and ignoring the rest) may sound good at first glance, it has many issues that pile up rapidly. What if multiple elements can handle the same event? Who gets priority? How do you handle consuming events? Or filtering? What about "partial" events (e.g. one element is watching for Ctrl+R, while another is consuming all Ctrl presses)? etc.
m

Manuel Unterhofer

02/23/2023, 4:56 PM
I have answers to all these questions already, and yes, it’s about arbitrary composition exactly
The difficulties you’re describing regarding more complex event handling aren’t much different from nested key handlers
r

Ruckus

02/23/2023, 4:59 PM
There is one big difference in that nested handlers are structured. They have to go up and down the tree, so handling order can be deterministic and easy to reason about, whereas arbitrary elements are not.
m

Manuel Unterhofer

02/23/2023, 4:59 PM
Arbitrary elements can be enumerated in DFS order
r

Ruckus

02/23/2023, 5:00 PM
Sure, but what about two siblings. It isn't clear who gets priority.
m

Manuel Unterhofer

02/23/2023, 5:00 PM
Why? DFS order makes this very clear
Siblings have an order, and the children of the first sibling come before the second sibling on the way down, and vice versa on the way up
r

Ruckus

02/23/2023, 5:06 PM
Siblings have an order
That's my point, the order often isn't as clear as it may seem. The obvious example is whatever order they are defined in the code, but that might not line up with many users expectations, such as what is visible on the screen, or where elements appear on the screen. But all of this is arguably beside the point, as the fundamental idea of having multiple elements focused is problematic, as that kind of defeats the whole point of focus in the first place, and can be fairly easily worked around using the methods I mentioned earlier, without having to answer any of these questions.
(It's also interesting to note there are UI frameworks that do not use trees at all for their UI, though that's not really important here as Compose does. Just kind of fun to think about how things work in those cases.)
m

Manuel Unterhofer

02/23/2023, 5:08 PM
Aren’t you expecting to be able to both type and move the selection in macOS Spotlight, or the completion in any IDE, or even in your browser address bar?
r

Ruckus

02/23/2023, 5:09 PM
Sure, but that's not multiple focus. In all of those cases, the focus in on the input, and the appropriate functions are called from the input's event handler. There is still only one thing focused at any given time.
m

Manuel Unterhofer

02/23/2023, 5:10 PM
That’s one way of implementing it, but that doesn’t compose. That’s my whole point. I want to be able to plug any component into a list entry and the component should be able to query the focus API just like any other
r

Ruckus

02/23/2023, 5:12 PM
The same argument applies to input validation, or clicking a button to show or hide parts of the input, or anything on the UI whose interaction modifies anything else on the UI. It's not multiple focus, it's just event handling.
but that doesn’t compose ... I want to be able to plug any component into a list entry and the component should be able to query the focus API just like any other
I don't understand what you mean by "query the focus API just like any other". I think you may be conflating the focus with the selection, but I could be wrong. Can you elaborate?
m

Manuel Unterhofer

02/23/2023, 5:13 PM
I don’t understand how these examples relate to the point. None of them actually need to be active at the same time
r

Ruckus

02/23/2023, 5:14 PM
None of them actually need to be active at the same time
Yes, that's exactly my point.
m

Manuel Unterhofer

02/23/2023, 5:14 PM
How does bringing up unrelated examples prove your point?
r

Ruckus

02/23/2023, 5:16 PM
My point is that all of these are essentially the same thing, and your use case doesn't require multiple focus. It's just another example of one elements interaction changing the state of the app that gets represented elsewhere.
m

Manuel Unterhofer

02/23/2023, 5:17 PM
No use case requires a built-in focus system or even key handlers in any nested position. I can also hard-code all key handlers at the window root and build my own focus system to keep track of what is going on in the window. I think we can agree that this would not be a reasonable way to go about it but it would be possible, right?
It wouldn’t be very easy to maintain this kind of code, most importantly. Everything would be coupled. And in the same way, I’m trying to avoid coupling the two parts of my UI together. I want to be able to plug in a generic list and a generic input without them having to know about each other, and while using the built-in focus system and key handlers
r

Ruckus

02/23/2023, 5:20 PM
That feels like a strawman argument.
m

Manuel Unterhofer

02/23/2023, 5:20 PM
I’m exaggerating your argument to make it clear that the coupling of the two sides of my UI comes at a cost
Which you keep ignoring
r

Ruckus

02/23/2023, 5:22 PM
Ah, I think I see the issue. I apologize. Let me try to explain.
I've been operating from the assumption that you want something like all the examples you have given, where the UI elements are absolutely coupled (e.g. the search bar of the browser and the list of suggestions are absolutely coupled: the list cannot effectively/meaningfully exist without the input), so I've been offering suggestions based on those kinds of use cases. However, you seem to be asking/suggesting to allow any elements that may have nothing to do with each other whatsoever do all be able to handle input from the user at the same time. Am I understand that correctly now?
m

Manuel Unterhofer

02/23/2023, 5:30 PM
Yes
r

Ruckus

02/23/2023, 5:31 PM
Is it fair to say that is an entirely separate and unrelated use case from the kinds of things I've been suggesting, or am I still missing something?
m

Manuel Unterhofer

02/23/2023, 5:33 PM
I believe we can also just stop here and I’ll be happy with knowing that there aren’t any built-in tools for realizing this in Compose
Thanks for your time!
r

Ruckus

02/23/2023, 5:38 PM
Fair enough, but if I may, that suggestion actually sounds exactly like what you were suggesting as an exaggeration of my argument: "I can also hard-code all key handlers at the window root and build my own focus system to keep track of what is going on in the window." As ridiculous as that sounds, you may be on to something. You could create a
MultiFocus
composable that can handle any such use cases inside it and dispatch accordingly. You would need to come up with a good way of representing to the user what elements are and are not in focus, as well as how to add or remove elements (or just assume everything in it is always focused I guess), but it could be cool. Instead of the completion in an IDE (which I think still fits into the tightly coupled world), this would be more akin to multiple cursors in an IDE.
Indeed, thank you too! And sorry again for missing your point entirely most of the time. 🙂
m

Manuel Unterhofer

02/23/2023, 5:50 PM
No problem 🙂