オプションメニューみたいなダイアログを無理やり実装してみた



Android端末のMENUキーを押すと、下からせり上がってくるダイアログがありますよね。
こんな感じのダイアログ



普通はMenuクラスを使ってオプションメニューを生成すれば良いのですが、
それだけだと物足りない人もいると思います。
今回は自前で実装しようと思い、どうやって作ってるのか色々調べたんですが、なかなか情報が出てきません。
仕方が無いので、なんだかそれっぽいのを無理やり実装してみました。(多分他にもやり方があると思います)


完成時のキャプチャ

(本当は動画を貼り付けたかったんですが、処理落ちが酷いので断念しました)

実装方法

ダイアログのテーマをカスタマイズして実装します。
具体的には

  • リソースを幾つか用意
  • メニューとなるレイアウトを作成しておく
  • アニメーションを作成
  • ダイアログのテーマを変更

リソースを用意する

メニューボタンを押したときの画像を3つ用意します。

左からbutton1.png, button2.png, button3.png とします。
これらを組み合わせてボタンを押したときの動作を定義しておきます。
(drawableフォルダに入れておきます)
btnstate.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- ? -->
    <item
        android:state_enabled="true"
        android:state_window_focused="false"
        android:drawable="@drawable/button3" />

    <!-- ? -->
    <item
        android:state_enabled="false"
        android:state_window_focused="false"
        android:drawable="@drawable/button3" />

    <!-- 押下中-->
    <item
        android:state_pressed="true"
        android:drawable="@drawable/button1" />

    <!-- 選択中 -->
    <item
        android:state_focused="true"
        android:state_enabled="true"
        android:drawable="@drawable/button2" />

    <!-- 非選択-->
    <item
        android:state_enabled="true"
        android:drawable="@drawable/button3" />

    <!-- 無効だけど選択中 -->
    <item
        android:state_focused="true"
        android:drawable="@drawable/button2" />
</selector>


オプションメニューとなるレイアウトの作成

レイアウトとなるViewの下側1/3だけ見せたいので、
ちょっとした小細工をしなければいけません。


menu_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#00000000">
    
    <LinearLayout
        android:layout_width="fill_parent"
        android:orientation="vertical"
        android:layout_height="fill_parent">
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1">
        </LinearLayout>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1">
        </LinearLayout>
        <LinearLayout
            android:background="#ff909090"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical"
            android:padding="4dip"
            android:layout_weight="1">
            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="horizontal"
                android:background="#FFF0F0F0"
                android:layout_weight="1">
                <Button
                    android:background="@drawable/btnstate"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:drawableTop="@android:drawable/ic_menu_add"
                    android:text="add"
                    android:layout_weight="1">
                </Button>
                <LinearLayout
                    android:layout_width="1px"
                    android:background="#ff909090"
                    android:layout_height="fill_parent">
                </LinearLayout>
                <Button
                    android:background="@drawable/btnstate"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:drawableTop="@android:drawable/ic_menu_call"
                    android:text="call"
                    android:layout_weight="1">
                </Button>
                <LinearLayout
                    android:layout_width="1px"
                    android:background="#ff909090"
                    android:layout_height="fill_parent">
                </LinearLayout>
                <Button
                    android:background="@drawable/btnstate"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:drawableTop="@android:drawable/ic_menu_camera"
                    android:text="camera"
                    android:layout_weight="1">
                </Button>
            </LinearLayout>
            <LinearLayout
                android:layout_width="fill_parent"
                android:background="#ff909090"
                android:layout_height="1px">
            </LinearLayout>
            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="horizontal"
                android:background="#FFF0F0F0"
                android:layout_weight="1">
                <Button
                    android:background="@drawable/btnstate"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:drawableTop="@android:drawable/ic_menu_compass"
                    android:text="hoge"
                    android:layout_weight="1">
                </Button>
                <LinearLayout
                    android:layout_width="1px"
                    android:background="#ff909090"
                    android:layout_height="fill_parent">
                </LinearLayout>
                <Button
                    android:background="@drawable/btnstate"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:drawableTop="@android:drawable/ic_menu_help"
                    android:text="foo"
                    android:layout_weight="1">
                </Button>
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>
</RelativeLayout>


アニメーションの作成

通常のダイアログだと、フェードインしながら表示されますが、
オプションメニューは下からせり上がってくるので、それと同じようなアニメーションも
作成します。
ダイアログが表示、非表示されたときの2パターンを作成します。(animフォルダに格納します)
dialog_anim_enter.xml (表示するとき)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromYDelta="20%"
        android:toYDelta="0"
        android:fillAfter="true"
        android:duration="200">
    </translate>
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0"
        android:duration="200"
        android:fillAfter="true">
    </alpha>
</set>



dialog_anim_exit.xml (非表示するとき)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromYDelta="0"
        android:toYDelta="20%"
        android:duration="200"
        android:fillAfter="true">
    </translate>
    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0.0"
        android:duration="200"
        android:fillAfter="true">
    </alpha>
</set>


ダイアログのテーマを変更

普通のダイアログだと黒い半透明の背景画像がセットされてますので、
これを完全に透明な画像と差し替えて、先程作ったアニメーションに変更します。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MenuDialog" parent="@android:style/Theme.Dialog">
        <item name="android:windowBackground">@drawable/button1</item>
        <item name="android:windowAnimationStyle">@style/Animation.MenuDialog</item>
    </style>
    <style name="Animation.MenuDialog" parent="@android:style/Animation.Dialog">
        <item name="android:windowEnterAnimation">@anim/dialog_anim_enter</item>
        <item name="android:windowExitAnimation">@anim/dialog_anim_exit</item>
    </style>
</resources>


ダイアログを実装してみる

HelloWorldを改造してボタンを押すとダイアログが表示されるようにしたいと思います。


main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center">
    <Button
        android:id="@+id/Button01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="show">
    </Button>
</LinearLayout>



Hello.java

package org.example.kyoto.japan.mofumofu.hello;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class Hello extends Activity implements OnClickListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ((Button)this.findViewById(R.id.Button01)).setOnClickListener(this);
    }

    public void onClick(View arg0) {
        
        MenuDialog d = new MenuDialog(this);
        d.show();
    }
    
    public class MenuDialog extends Dialog implements OnClickListener {
        
        public MenuDialog(Context context) {
            
            super(context, R.style.MenuDialog);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            this.setContentView(R.layout.menu_view);
            
            int []btn = {
                    R.id.Button01,  R.id.Button02,  R.id.Button03,
                    R.id.Button04,  R.id.Button05,
            };
            for (int id : btn) {
                ((Button)this.findViewById(id)).setOnClickListener(this);
            }
        }
        
        public void onClick(View v) {
            dismiss();
        }
    }
}


完成

ではビルドして動かしてみます。(動画じゃなくて残念です)



showボタンを押すと…



下からヌルヌルとせり上がってきました!
ボタンを押せばダイアログは閉じます。
何も無いところをクリックした時にダイアログを閉じたい場合は、
LinearLayoutにIDを付加して、OnTouchイベント実装すれば良いと思います。


参考サイト
throw Life Dialogをアニメーションさせる方法
Android Button の色や画像を変える