Slide 1

Slide 1 text

DroidKaigi 2018付録1 詳解 RelativeLayoutの 内部実装 株式会社ノハナ 瀬戸優之 @seto_hi

Slide 2

Slide 2 text

RelativeLayoutのポイント =Graph

Slide 3

Slide 3 text

Graph グラフ(英: Graph)とは、 ノード(頂点)群とノード間の連結関係を表す エッジ(枝)群で構成される抽象データ型、 and・orその実装である具象データ型である。 (wikipedia)

Slide 4

Slide 4 text

DependencyGraph ● 有向グラフ ● mNodes = 子Viewすべて、ArrayList ● mKeyNodes = IDを持つ子View、SparseArray Node ● dependents = 参照しているNode ● dependencies = 参照されているNode

Slide 5

Slide 5 text

RelativeLayout#onMeasure

Slide 6

Slide 6 text

RelativeLayout#onMeasure 1. DependencyGraphを作る 2. 横方向でGraphのrootからmeasure、仮レイアウト 3. 縦方向でGraphのrootからmeasure、仮レイアウト ○ 自身のサイズも仮決定

Slide 7

Slide 7 text

RelativeLayout#onMeasure 4. 自身がwrap_contentなら ○ 子のサイズとMeasureSpecから自身のサイズを修正 ○ 中央寄せのViewの位置を修正 5. Gravityによって位置を本決め 6. setMeasuredDimensions

Slide 8

Slide 8 text

mesureでの仮レイアウト ● 参照のGraphのrootからmeasure + 仮レイアウトしていく ● measure対象のViewが参照しているViewは 必ず仮レイアウト済み ● measureさえすればmeasure対象のViewの 仮レイアウト位置が確定できる

Slide 9

Slide 9 text

子ViewのmeasureSpec 1. 左右(or上下)ともに参照しているViewがある ○ 左右(or上下)のViewの間のサイズ + EXACTLY 2. 1.でない場合 ○ 子Viewがサイズ決め打ち ■ 子Viewのサイズと余りサイズの最小値 + EXACTLY ○ 子Viewがmatch_parent ■ RelativeLayoutの余りサイズ + EXACTLY※ ○ 子Viewがwrap_content ■ RelativeLayoutの余りサイズ + AT_MOST※ ※余りがなければ0 + UNSPECIFIED

Slide 10

Slide 10 text

RelativeLayout#onLayout

Slide 11

Slide 11 text

RelativeLayout#onLayout ● measure通りにレイアウトするだけ ○ RelativeLayout.LayoutParamsが位置と座標を持つ ■ mLeft, mTop, mRight, mBottom ● シンプル!

Slide 12

Slide 12 text

循環参照の検知

Slide 13

Slide 13 text

循環参照の検知 ● RelativeLayoutで循環参照は禁止 ○ rightOfのleftOfが自身のような場合 ○ ConstraintLayoutは一部OK(Chainになる) ● グラフの参照で解決

Slide 14

Slide 14 text

DependencyGraph ● mNodes = 子Viewすべて、ArrayList ● mKeyNodes = IDを持つ子View、SparseArray Node ● dependents = 参照しているNode ● dependencies = 参照されているNode

Slide 15

Slide 15 text

DependencyGraph#getSortedViews 1. GraphのrootをDequeに入れる 2. Dequeからグラフの頂点のNodeをpoll 3. 2.を参照している子Nodeに対して 3.1. 参照されているNodeがないならばDequeに追加 3.2. 参照されているNodeがあれば何もしない 4. Dequeが空ならば5、 Dequeが空でないならば2.に戻る 5. すべてのEdgeをDequeに追加できていない場合は 例外を投げる

Slide 16

Slide 16 text

循環参照の検知(正常系) A B C Dequeue

Slide 17

Slide 17 text

循環参照の検知(正常系) A B C Dequeue A 1.RootをDequeueに追加

Slide 18

Slide 18 text

循環参照の検知(正常系) A B C Dequeue B 2.pollして消去 3.1.Dequeueに追加

Slide 19

Slide 19 text

循環参照の検知(正常系) B C Dequeue C 3.1.Dequeueに追加 2.pollして消去

Slide 20

Slide 20 text

循環参照の検知(正常系) C Dequeue 2.pollして消去

Slide 21

Slide 21 text

循環参照の検知(正常系) Dequeue 5.Dequeueが空で すべてのEdgeを参照したので終了

Slide 22

Slide 22 text

循環参照の検知(異常系) A B C Dequeue 循環参照

Slide 23

Slide 23 text

循環参照の検知(異常系) A B C Dequeue A 1.RootをDequeueに追加

Slide 24

Slide 24 text

循環参照の検知(異常系) A B C Dequeue 2.pollして消去 3.2.参照があるので Dequeueに追加しない

Slide 25

Slide 25 text

循環参照の検知(異常系) B C Dequeue 5.Dequeueが空なのにすべてのEdgeが参照できていない 例外を投げる