layout_weightについて(0dipとfill_parentの違いについて)

=前置き=

 layout_weightの概念がわかりにくかったので、自分用も兼ねてまとめておく。

 ここではLinearLayoutを使ってA・B・Cを縦に並べる状況を考える。layout_weightはA・B・Cに設定することになる。以下では高さの設定でlayout_heightも使うので、layout_weightとの字面の紛らわしさに注意。

=「余白」という概念=

 layout_weightは「余白の分割比」である。「親の空間の分割比」ではないのでその違いの説明が必要だが、まずその前に「余白」の概念も単純ではないのでそれを説明する。

 「余白」というのは「親の持っている空間(LinearLayoutのlayout_height)」のことではなく、「親の持っている空間から、自分達の主張するサイズ(A・B・Cのlayout_height)を引いたもの」になる。「それぞれの子供が自分の取り分(layout_height)をゲット」→「その後、余った空間(LinearLayoutのlayout_height - A・B・Cのlayout_height)を分割してゲット」という流れなので、子供のサイズが違えば最初の「取り分」が違うため、余白をゲットする比率が同じであっても最終的なスペースが異なる。

 上の話はA・B・Cのlayout_heightが「wrap_content」や「120dip」などサイズ固定であった場合の話で、「fill_parent」の場合は少し状況が異なる。
「fill_parent」の場合、「子(A・B・C)が主張するサイズ」は「親(LinearLayout)のサイズ」と同じになる。そのため、「親のサイズから子供の主張するサイズを引く」とスペースが余らないどころか「LinearLayoutのサイズの2倍の大きさがはみ出す」という状態になる。(AがLinearLayoutのサイズを奪い、BとCがはみ出す)
 そしてAndroidではその「はみ出した幅」を「マイナスの余白」として扱う。つまり、「マイナスの余白を分割してゲット」することになり、これによって「主張するサイズ+マイナスの余白=主張より小さいサイズ」となって画面に収まるように調整される。

=余白の分割=

 layout_weightは上で書いたような「余白」の分割比である。「親の空間」の分割比ではないため、「2,2,1」と設定しても「自分のスペースを確保した後、余白を2:2:1で分け合う」ことになり、見た目は「2:2:1」にはならない。

 さらにfill_parentを使う場合、「2,2,1」と指定すると「マイナスの余白を2:2:1で分け合う」ことになる。つまり、「2の方がマイナスを受け取る比率が高い」=「2の方が1よりも小さく表示される」という状況になる。つまり、設定した比率と実際の表示の比率が逆転しているように見える。

 つまり、「見た目を2:2:1にする」ためには「余白をゲットしたあとの比率が0.4:0.4:0.2になっている」必要があり、「主張する比率(1)+余白(-2)×layout_weight / (子のlayout_weightの合計)」が0.4や0.2になれば良いので、例えば「0.3, 0.3, 0.4」という風に設定することになる。

=直感的な比率指定=

 上の分割方法を毎回指定するのは面倒くさい。「1:1:1」みたいな当分割であれば余白の分割も等しくなるので問題ないが、毎回そういう比率とは限らない。そもそも「主張するサイズ」を全て0にできれば、親のサイズがまるまる余白となって指定した比率で分割できるはずだ。

 というわけで、「fill_parent」の代わりに「0dip」を指定すれば直感的な比率の指定が可能になる。

=まとめ=

  • layout_weightは「親のサイズの分割比」ではなく「余白の分割比」である
  • fill_parentを使うと主張サイズが親のサイズになるので余白がマイナスになっておかしく見える
  • 0dipを使えば主張サイズが0で「親のサイズ=余白」になるので直感的な比率指定が可能

=参考リンク=