Facebook アプリのようなリッチなメニュー一覧を表示するドロワーレイアウト (DrawerLayout)

フェイスブックを代表する、"iPhone スタイルのアプリケーション" では早くから左からスライドしてくるパネルに、 リッチなメニュー項目が表示されていました。

Android でもこれを模したアプリケーションを実装することは可能でしたが、やはり面倒なものです。

API レベル 18 のサポートライブラリではここで紹介する DrawerLayout (ドロワーレイアウト) なるものがサポートされ、 簡単に左側からスライドするメニューを実装できるようになりました。

最近の UI デザインガイドラインに "ドロワーナビゲーション" を利用すべき状況等の説明がありますので、確認しておくとよいでしょう。

ともあれ、最近 Google がリリースするアプリケーションではほぼ例外なくドロアーナビゲーションがサポートされているため、 これに慣れてきたユーザーも急速に増えてきていると予想されます。

例えば、Google Analytics では左上のアイコンをタップすると、次のようなメニューが表示されます。

ドロワーレイアウト

つい先日発表された Google One Today は次のようになります。

ドロワーレイアウト

ここではこうしたメニューを表示するための、ドロワーレイアウトについて説明します。

実際の出来上がりは次の通りです。

画面左上にドロワーナビゲーションの存在を示すアイコンが表示されています。

ドロワーレイアウト

これをタップすると左側から右側へ、ナビゲーションがスライドして出てきます。

ドロワーレイアウト

この中の項目をタップすると・・・

ドロワーレイアウト

タップした項目に応じた内容(ここでは単に項目番号)が、表示されます。

ドロワーレイアウト

簡単なドロワーレイアウトの実装

まずレイアウトファイルですが、メインのレイアウトは次のようになります。

<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
  android:id="@+id/content_frame"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:textSize="72sp"
    />
</RelativeLayout>
<ListView
  android:id="@+id/drawer_listview"
  android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp"
    android:background="#EEE"/>
</android.support.v4.widget.DrawerLayout>

親のレベルの要素が android.support.v4.widget.DrawerLayout となります。

width と height を両方とも match_parent とします。

ここではスライドしてくるメニュー項目はリストビュー (ListView) を利用しています。 リストビューはListView の基本的な使い方 などを参考にしてください。このページではあまり説明しません。

また、左上のアイコンとして次のようなアイコン (ドローワブル) を用意します。

mdpi (16x16)hdpi (24x24)xhdpi (32x32)

»ドロワー画像のダウンロード

次に後ほど利用する string リソースを追加しておきます。

<?xml version="1.0" encoding="utf-8"?>
<resources>
  ...
  <string name="drawer_open">Open Drawer</string>
  <string name="drawer_close">Close Drawer</string>
</resources>

コードは次の通りです。

package com.example.drawertest1;

import android.os.Bundle;
import android.app.Activity;
import android.content.res.Configuration;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity
  implements ListView.OnItemClickListener {
  
  static String[] menuItems = { "Item 1", "Item 2", "Item 3" };
  static ArrayAdapter<String> adapter;
  
  DrawerLayout drawerLayout;
  ListView drawerListView;
  ActionBarDrawerToggle drawerToggle;
  
  TextView textView1;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViews();
    setListView();
    setDrawer();
  }
  
  protected void findViews(){
    drawerLayout =
      (DrawerLayout) findViewById(R.id.drawer_layout);
    drawerListView =
      (ListView) findViewById(R.id.drawer_listview);
    textView1 =
      (TextView) findViewById(R.id.textView1);
  }
  
  protected void setListView(){
    // データアダプタ
    adapter = new ArrayAdapter<String>(
    this,
    android.R.layout.simple_list_item_1,
    menuItems);
    drawerListView.setAdapter(adapter);
    
    // アイテムの選択
    drawerListView.setOnItemClickListener(this);
  }
  
  @Override
  public void onItemClick(
    AdapterView<?> parent, View view, int position, long id) {
    textView1.setText((position + 1) + "");
    drawerLayout.closeDrawers();
  }
  
  protected void setDrawer(){
    getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);

    drawerToggle = new ActionBarDrawerToggle(
      this,
      drawerLayout,
      R.drawable.ic_drawer1,
      R.string.drawer_open,
      R.string.drawer_close);
    drawerLayout.setDrawerListener(drawerToggle);
  }
  
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    if (drawerToggle.onOptionsItemSelected(item)) {
      return true;
    }
    return super.onOptionsItemSelected(item);
  }
  
  @Override
  protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    drawerToggle.syncState();
  }
  
  @Override
  public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    drawerToggle.onConfigurationChanged(newConfig);
  }
}

ポイントは setDrawer メソッドの中に詰め込んでます。

アクションバーの設定で setDisplayHomeAsUpEnabled と setHomeButtonEnabled を true を引数にして呼び出すことで、 アイコンが左上のアイコンが使えるようになります。

次に ActionBarDrawerToggle でドロワーのアイコンとアクセシビリティに関わるドロワーのオープンとクローズの文字列リソース ID を設定します。

その他、onOptionsItemSelected メソッドをこう書いておかないと、左上のホームアイコンのタップに応答しません。onPostCreate と onConfigurationChanged ではドロワーのスライドにあわせて、アイコンがやや左に隠れる動作になります。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門