プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

【Android】画面レイアウトでステータスバーの大きさを考慮する方法

『ちょっとだけ立体風地図ビューワ』の画面レイアウトを作った時のことをまとめておきます。

このアプリを作成した際に、私がやりたかったのは、

  • タイトルバーは消す
  • ステータスバーは表示する
  • 残った領域をほぼ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. 実行結果

結果はみたほうがはやいですね。

均等な大きさのView

意図したようにレイアウトとしては、上から、

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になります)。結局、このアプローチでも今回の目的には使えないことがわかりました。

(参考)Viewの幅と高さを取得する方法を考える

別の使い方をする場合、この方法で対応できます。例えば、intentで画面を切り替えるアプリの場合、一つ目の画面が表示された際にこのサイズを取得し、2つめの画面に移る際にステータスバーのサイズを渡せば、2つ目の画面を作る時にステータスバーのサイズを考慮して自由に画面を作ることができると思います。

 

結局、思いついた方法が、今回紹介したLinearLayoutのweightを使う方法でした。

調べればもっと素直ないい方法があるかも知れませんが、こういう実現方法もあるという一例として、ご参考にしてください。

 

以上