お使いのブラウザは、バージョンが古すぎます。

このサイトは、Internet Explore8・Internet Explore9には対応しておりません。
恐れ入りますが、お使いのブラウザをバージョンアップしていただきますよう宜しくお願いいたします。

【Android】PopupWindowをカスタマイズする

こんにちわ、pencoです。
今回はPopupWindowにカスタムのViewを設定する方法について書いていきたいと思います。
 
完成イメージはこんな感じです。
popup01
リストビューの一行をロングタップすると、ポップアップが表示されるようにします。ポップアップには、長くて”…”表示になっているリストのテキスト全文と、共有ボタンを表示します。
 

レイアウトの作成

 
まずは、ポップアップに設定するViewのレイアウトを作ります。
popupwindow.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/popup"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/pouuptext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:text="@string/text_notitle"
        android:textColor="#ffffff"
        android:textSize="18sp" />

    <ImageView
        android:id="@+id/share"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:background="@xml/popup_share" />

</LinearLayout>

 
LinearLayoutの背景に吹き出しの画像を設定しています。
このポップアップはTextViewに設定されるテキストの長さによってサイズを可変にしたいため、吹き出し画像は9patchで作成しています。
 

ポップアップの作成

 
次にポップアップを作る!…と、その前に下準備をしておきます。

下準備

 
リストビューの一行をロングタップした場合に表示するので、ListViewにOnItemLongClickListenerを設定し、onItemLongClick()の中でポップアップの設定を行います。今回はListFragmentを継承したクラスでListViewの設定をしています。(ListFragmentについては説明を割愛させて頂きます。)

@Override
public void onActivityCreated(Bundle bundle) {
    ...
    getListView().setOnItemLongClickListener(this);
    ...
}

@Override
public boolean onItemLongClick(AdapterView<?> parent, View v, int pos, long id) {
    LinearLayout layout = (LinearLayout)getActivity().getLayoutInflater().inflate(R.layout.popupwindow, null);
    TextView text = (TextView)layout.findViewById(R.id.pouuptext);
    String title = ((TextView) v.findViewById(R.id.titleText)).getText().toString();
    text.setText(title);
    ImageView share = (ImageView)layout.findViewById(R.id.share);
    share.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            shareFile(file);
        }
    });

    return true;
}

 
LayoutInflaterを使って先程作ったレイアウトをinflateします。
このonItemLongClick()の引数View vは、ロングタップしたリストの一行に設定されているビューが入ります。アダプターに渡しているやつですね。そこからidを使用しTextViewを取得、そこからテキストを取得しています。
共有ボタンが押された時の処理も書いてしまいます。
 

ポップアップ

 
では、本題のポップアップです。
onItemLongClick()内に続けて書いていきます。

PopupWindow popupWindow = new PopupWindow(getActivity()); 
popupWindow.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
popupWindow.setContentView(layout);
popupWindow.showAsDropDown(v);

 
レイアウト作成時にも述べましたが、ポップアップのサイズはテキストの長さによって可変にしたいため、popupWindowにもWRAP_CONTENTを設定します。
ちなにみこのsetWindowLayoutMode()を省くとポップアップが表示されませんでした。
 
作成したpopupWindowインスタンスに先程読み込んだlayoutをビューとして設定します。最後にshowAsDropDown()でポップアップを表示します。
 
showAsDropDown()の引数は、アンカーとして使用するビューです。リストビューの一行を渡すことで、ロングタップした項目の下にポップアップが表示されます。
アンカーのビューとポップアップは紐付けられているため、アンカーのビューが動くとそれに付随してポップアップも移動します。
 
この状態で実行すると、こんな感じになります。
popup02
 

位置の調整

…いろいろ気になるところはありますが、まずは表示位置を直します。
先程はポップアップの表示にshowAsDropDown(View anchor)を使用しましたが、これをshowAsDropDown(View anchor, int xoff, int yoff)に変更します。
 
第二、第三引数は、アンカーのビューの左下を(0,0)とした場合のオフセット値です。

int xoff = getListView().getWidth();
int yoff = v.getHeight();
popupWindow.showAsDropDown(v, xoff, -yoff);

 
リストの横にポップアップが表示されるよう、リスト全体の幅、リストの一行の高さ分オフセットをかけました。これでもう一度実行してみます。
popup03
 
これで位置は意図するものになりました。
 

角丸をきちんと出したい!

 
しかしよく見ると、吹き出しの背景にグレーの四角が…
これは、ポップアップにビューを設定しないとわかるのですが、ポップアップのデフォルトの背景です。これをなんとか透明にしたいですね。
 
ここが今回のミソなのですが、
通常Viewの背景を透明にする場合は、背景に#00000000などを指定します。
ところが、このPopupWindowにはsetBackgroundDrawable()しか背景を設定するメソッドがありません。
 
そこで、適当なサイズの透明な画像を用意し、背景に設定します。
今回は16×16の透明なPNGを用意し、背景に設定しました。
サイズは適当ですが、ポップアップ自体にWRAP_CONTENTを設定しているので、表示したい大きさ(今回は吹き出しのサイズ)よりは小さい方が良いと思います。

popupWindow.setBackgroundDrawable(getResources().getDrawable(R.drawable.popup_bg));

 
これでやっと完成形と同じ表示に出来ました!

ポップアップを消す処理をつけよう

  
あと少し、動作について修正を行いましょう。
現状ではポップアップを消す処理がないため、出したはいいが消せません。
そこで、setOutsideTouchable()を使います。
このメソッドにtrueを設定すると、ポップアップの外側をタッチした時に消えるようになります。
 
しかしこれだけだと、下のビューもイベントを受けてしまう為、setFocusable()にもtrueを設定し、ポップアップ表示中のフォーカスを自分に設定します。
 
これで完成です!!

まとめのコード

 
最後にポップアップ設定部分のコードをまとめるとこの様になります。

@Override
public boolean onItemLongClick(AdapterView<?> parent, View v, int pos, long id) {
	
    LinearLayout layout = (LinearLayout)getActivity().getLayoutInflater().inflate(R.layout.popupwindow, null);
    TextView text = (TextView)layout.findViewById(R.id.pouuptext);
    String title = ((TextView) v.findViewById(R.id.titleText)).getText().toString();
    text.setText(title);
    ImageView share = (ImageView)layout.findViewById(R.id.share);
    share.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            shareFile(file); //共有ボタンが押されたら呼ばれる
        }
    });
		
    PopupWindow popupWindow = new PopupWindow(getActivity());  
    popupWindow.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    popupWindow.setBackgroundDrawable(getResources().getDrawable(R.drawable.popup_bg));
    popupWindow.setContentView(layout);
    popupWindow.setOutsideTouchable(true);
    popupWindow.setFocusable(true);
    int xoff = getListView().getWidth();
    int yoff = v.getHeight();
    popupWindow.showAsDropDown(v, xoff, -yoff);
		
    return true;
}

 
長くなってしまいましたが、以上です!
閲覧ありがとうございます。

コメントをどうぞ

メールアドレスは公開されません。* が付いている欄は必須項目です。


お気軽にお問い合わせください。

日本VTR実験室では、お仕事のご依頼、ブログ・コラムのご感想などを受け付けております。
アプリ開発・コンテンツ制作でお困りでしたら、お気軽にご相談ください。
ご連絡お待ちしております。

お問い合わせはこちらから

03-3541-1230

info@nvtrlab.jp

電話受付対応時間:平日AM9:30〜PM6:00