『ちょっとだけ立体風地図ビューワ』の画面レイアウトを作った時のことをまとめておきます。
このアプリを作成した際に、私がやりたかったのは、
- タイトルバーは消す
- ステータスバーは表示する
- 残った領域をほぼ2分割して異なるViewを表示する
といった画面レイアウトでした(ほぼとしたのは、中央に境界線を入れているので、その分を省いているためです)。
これに意外と苦労したので、やり方をサンプルコードとともに示します。
1. 考え方
結論から先に書くと、LinearLayoutのweightパラメータを使うことで実現できます。
ここに書いたサンプルでは、画面の縦方向にImageViewを2つ置き、一番下にViewを一つ置き、ImageView2つが同じ大きさになるようにしようと思います。
2. タイトルバーを消す
タイトルバーを消すには、ActivityのonCreateメソッド内で
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
とします。
(参考) フルスクリーンモードの作り方
3. weightを設定する
LinearLayoutでView(widget)を順番に配置した時、wrap_contentを使っていると、画面内に空きスペースが生じると思います。レイアウトパラメータのweightを使うと、この空いているスペースをどのように各widgetで分配するかを決めることができるようです。
具体的には、weightが0以外のViewで値に応じてViewが引き伸ばされるようです。
(参考) LinearLayout.LayoutParamのリファレンス
ここでは、ImageViewの高さとしてwrap_contentを指定していますが、View生成時には画像(src)を指定していません。このため、中身は無い状態になります。そこで、weightパラメータとして2つのImageViewに同じ値を与えると、空き領域を均等に分けて、同じ高さのImageViewが作られるようにします。
4. サンプルコード
まずレイアウトのxmlファイルを示します。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"> <ImageView android:id="@+id/ImageView01" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"></ImageView> <ImageView android:id="@+id/ImageView02" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"></ImageView> </LinearLayout>
xmlファイル内ではViewは2つしか指定していません。最下部に表示されるVIewはコードで動的に追加することになります。
次に、このレイアウトファイルを使ったサンプルコードが下記になります。途中で、Viewを動的に生成して、高さ25ピクセルに設定しています。また、onDrawをオーバーライドして灰色の背景に斜めの緑の線を書いています(深い意味はありません)。
package com.mori_soft.android.layouttest; import android.app.Activity; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; /** レイアウトのテスト * 中身を含まないImageViewを同じ大きさで配置する方法 * LinearLayout.LayoutParam の weight がポイント * * @author mor * */ public class LayoutTestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // タイトルなし this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); // ImageView 1 の背景色 ImageView imgv = (ImageView)findViewById(R.id.ImageView01); imgv.setBackgroundColor(Color.RED); // 境界線を描いてみる View v = new View(this) { @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GRAY); Paint paint = new Paint(); paint.setStyle(Style.FILL_AND_STROKE); paint.setColor(Color.GREEN); paint.setStrokeWidth(2f); canvas.drawLine(0, 0, getWidth()-1, getHeight()-1, paint); } }; v.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, 25)); LinearLayout ll = (LinearLayout)findViewById(R.id.LinearLayout01); ll.addView(v); // ImageView 2 の背景色 ImageView imgv2 = (ImageView)findViewById(R.id.ImageView02); imgv2.setBackgroundColor(Color.BLUE); } }
5. 実行結果
結果はみたほうがはやいですね。
意図したようにレイアウトとしては、上から、
ImageView1 ImageView2 View
の順番にならんでいます。
また、画面からステータスバーと最下部のViewを除いた残りの部分で、2つのImageViewが同じ高さになっていることがわかります。
6. 経緯
今後の参考のために、なぜ上記のような方法にしたのか、経緯を含めてまとめておきます。
最初に考えた方法は、直接ステータスバーの大きさを取得する方法でした。しかし、調べてみるとなかなかステータスバーの大きさを取得するいい方法が見つかりません。そのうち、下記のWebページが見つかったので、直接ステータスバーの大きさを取得することはあきらめました。
(参考)
http://groups.google.com/group/android-developers/browse_thread/thread/05ac30eb42d34c04
次に考えた方法は、画面全部を占める大きさのViewを作り、Viewが生成された後なら、その高さを取得することができるので、画面サイズからViewのサイズを引けばステータスバーのサイズがわかる、というものでした。
今回の私の用途だと、最初のonCreate内のViewの生成時にステータスバーの大きさが分かっている必要があります。しかし、どうも、onCreateが完了するまではViewのサイズは確定しないようです(getWidth(),getHeight()が0になります)。結局、このアプローチでも今回の目的には使えないことがわかりました。
別の使い方をする場合、この方法で対応できます。例えば、intentで画面を切り替えるアプリの場合、一つ目の画面が表示された際にこのサイズを取得し、2つめの画面に移る際にステータスバーのサイズを渡せば、2つ目の画面を作る時にステータスバーのサイズを考慮して自由に画面を作ることができると思います。
結局、思いついた方法が、今回紹介したLinearLayoutのweightを使う方法でした。
調べればもっと素直ないい方法があるかも知れませんが、こういう実現方法もあるという一例として、ご参考にしてください。
以上