どうもこんばんわ。
忘れそうなので
本題
Modifier.onGlobalPosition { }
っていうModifier
を使うことで、表示されているコンポーネントの位置が取れる便利なやつなのですが...
ちょっと困った事があって
画面外にいると取れない?
というわけで横に長い、スクロールするような画面を用意しました。
横並びで文字を入れてあるので、ちゃんとスクロール出来ていることがわかります。
もちろん動かせますよ。
で、ここからです。
赤い四角が画面外に行くようにスクロールすると・・・おや?座標が取れないですね。。。
なんなら画面外に赤い四角を追いやるでもダメですね。
う~~~ん。
こまった。
わんちゃんあるかも boundsInParent
さて、スクロールして画面外から消えたらなんで座標まで取れなくなるのかと言うと、、、
boundsInWindow()
を使ってるからなんですね。
https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/package-summary#(androidx.compose.ui.layout.LayoutCoordinates).boundsInWindow()
関数の名前から予想できる通り、Window
(アプリの領域)から見た座標ですね。
Window
(アプリの領域)から消えてしまったらそりゃ取れなくなりますわ、
で、boundsInParent
とか言うのがワンちゃん使える可能性があります。
- Box (スクロールできるやつ)
- Box ( requiredWidth で無理やり画面外にコンポーネントを拡大 )
- Box (赤い四角)
↑ 別にBox
である必要はないですが。
こんな感じに親がすぐrequiredWidth
というか、画面外にはみ出しているコンポーネントの場合はおそらく取れます。
boundsInParent()
を使うように直せばおっけ~
最終手段
先に答えを出すと、はみ出しているコンポーネントでModifier.onGloballyPositioned { }
を使って、LayoutCoordinates
をもらいます。
次に、座標が欲しいコンポーネントのModifier.onGloballyPositioned { }
でも、LayoutCoordinates
をもらいます。
最後に、はみ出しているLayoutCoordinates
でlocalBoundingBoxOf()
を呼び出し、引数に座標が欲しいコンポーネントの方のLayoutCoordinates
を入れると、はみ出しているコンポーネントからみた座標が取れます。
説明難しいのでコード見て。
画面外にスクロールしましたが、ちゃんと座標が残ったままです!
何をしているのか
boundsInRoot()
の中身をちょっと見てちょっとだけ分かった気がする。
LayoutCoordinates
てのがサイズを測った結果の何からしいんだけど、これにlocalBoundingBoxOf()
って関数があって、
引数に別のコンポーネントのLayoutCoordinates
を渡すとそいつの座標が返ってくる。
boundsInRoot()
は任意のLayoutCoordinates
から根っこのコンポーネントのLayoutCoordinates
が取れるまで再帰的に探して(親のLayoutCoordinates
が取れるので)、
そのあとLayoutCoordinates#localBoundingBoxOf
を呼び出して根っこから見た座標を取っているらしい。
が、別に今回は根っこのコンポーネントじゃなくて任意のコンポーネントのLayoutCoordinates
でいいので、基準とするコンポーネントのLayoutCoordinates
をModifier.onGloballyPositioned { }
で取って使ってる。
ただ、このレイアウト構造だとboundsInParent()
とやってること変わらないのでどっち使っても変化はないです。はい。
複雑なレイアウトだと役に立つかも!
ソースコード
https://github.com/takusan23/JetpackComposeGlobalPositionOutView
おわりに
スクロール出来てかつ、ドラッグアンドドロップを使った時にonGloballyPositioned
動かなくてハマった。ので書きました。
もっといい方法があったらごめん。