117
106

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

BottomNavigationView入門

Last updated at Posted at 2016-10-27

はじめに

FiNCという会社でAndroidのアプリ開発を行っているんですが、
ドロワーにある機能に対してユーザーの遷移率が芳しくありませんでした。
僕自身Android歴が長いので違和感を感じませんでした。

よくよく考えてみると、かの有名なSNSアプリなどを利用する際にも、
自分はドロワーを利用する頻度はほとんどないなということに気づきました。
現状のドロワーの実装を進展させるために新しくリリースされた、
BottomNavigationViewを実装してみました。

BottomNavigationViewとは

image

これです。
この役割ってなんなの?というところなんですが、公式ドキュメント曰く、
Bottom navigation bars make it easy to explore and switch between top-level views in a single tap.
公式ドキュメント
ワンタップで、トップレベルのビューの行き来できる魔法のようなものらしいです。
iOSとかでいうグローバルナビゲーションですね。(今更感が否めないですが)

自分の記憶が正しければ、マテリアルデザインガイドラインには、2016年の5, 6月?くらいには記載されていたと思うのですが、実際にリリースされるプロダクトのAPIとして提供されておりませんでした。

そのAPIが先日リリースされました。
support library revision history

BottomNavigationViewの構成クラス群

スクリーンショット 2016-10-27 9.45.24.png

  • a.s.d.widget.BottomNavigationView (FrameLayout)
  • a.s.d.internal.BottomNavigationPresenter
  • a.s.d.internal.BottomNavigationMenuView (ViewGroup)
  • a.s.d.internal.BottomNavigationItemView (FrameLayout)

BottomNavigationViewを構成するクラスは主に上記なんですが、実際に利用する一番上のクラス以外はinternalで直接扱うことは恐らくないです。
このクラス群はMVPの構造になっているようです。(後ほど記載)

具体的な実装ステップ

ちゃっかり実装自体は、とても簡単です。

  • Step1: menu.xmlを作成する
  • Step2: layout.xmlを作成する
  • Step3: listenerをセットする。

・Steps1

build.gradleでsupport libraryのバージョンを最新に

build.gradle
dependencies {
    // これでBottomNavigationViewが利用可能
    compile 'com.android.support:appcompat-v7:25.0.0'
    
    // 他のdesign support libsも使いたいので以下を追加
    compile 'com.android.support:design:25.0.0'
}

res/menu内にxmlファイルを追加。
よくあるOptionMenuの実装と同じようにする。

item_bottom_navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/item1"
        android:icon="@android:drawable/ic_btn_speak_now"
        android:title="item1" />

    <item
        android:id="@+id/item2"
        android:icon="@android:drawable/ic_delete"
        android:title="item2" />

    <item
        android:id="@+id/item3"
        android:icon="@android:drawable/ic_dialog_alert"
        android:title="item3" />

</menu>

・Step2

レイアウトのxmlを実装する。
Step1で作成した、menuのxmlをappパッケージのネームスペースのmenuにセットする。
(※公式はdesignパッケージ以下のネームスペースらしいですが、上手く動かないそうです。2016/10/26現在)
ここはCoordinatorでなくてもいいです。BottomNavigationViewはFrameLayoutのサブクラスです。

activity_main.xml
<!-- xml -->
<a.s.d.w.CoordinatorLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <a.s.d.w.BottomNavigationView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom" 
        app:menu="@menu/item_bottom_navigation" />

</a.s.d.w.CoordinatorLayout>

BottomNavigationViewにはセットできる属性がいくつかあります。

属性 Javaメソッド 内容
itemBackground setItemBackgroundResource BottomNavigationViewの背景色全体を変更する。
itemIconTint setItemIconTintList itemのアイコンカラーを変更する。
itemTextColor setItemTextColor itemのテキストカラーを変更する。

・Step3

BottomNavigationViewにアイテムを選択した際のリスナーをセットする。
選択時の処理は自分が表示したいFragmentをセットします。

アニメーションに関してですが、マテリアルガイドラインによると、
BottomNavigationViewを利用している各ページにおいて、
選択状態のページを再度押すとそのページの一番TOPにスクロールするそうです。
(なので、switchはitem.isChecked()とかで切り分けするのがいいのかも。)

MainActivity.java
bnv.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.item1:
                setFragment();
                return true;
            case R.id.item2:
                setFragment();
                return true;
            case R.id.item3:
                setFragment();
                return true;
            }
        return false;
    }
});

その他

アイテム数の上限

  • Itemをmenu.xmlに6個以上追加すると、以下のIllegalArgumentExceptionが起こります。ビジネスの要望などで、6個以上追加しようとするので、エンジニアを救うための救済策でしょうか?Googleナイス。

Maximum number of items supported by BottomNavigationView is 5.
Limit can be checked with BottomNavigationView#getMaxItemCount()

Custom Behaviorが必要

  • BottomNavigationViewでは、スクロール to Bottomした際にスクリーンアウトする必要があります。現状のCoordinatorLayoutのbehaviorのプロパティではこの動きを実現できません。ですので、独自でカスタムBehaviorクラスを実装して、xmlでその部分を指定します。(完成したらアップします。以下の内部を実装する予定。)
public class BisonBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> {

    public BisonBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, BottomNavigationView child, View dependency) {
        return dependency instanceof FrameLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, BottomNavigationView child, View dependency) {
        return true;
    }

}

xmlの組み方をどうするか?

自分はこんな感じで組んだんですが、まだActivityとFragmentで上手く切り分けられていない気がしています。

<CoordinatorLayout>
    <AppBarLayout>
        <Toolbar /> 
    </AppBarLayout>
    <FrameLayout /> <!-- ここにページごとのFragmentをセットする。 -->
    <BottomNavigationView />  
</CoordinatorLayout>

おまけ

Kobito.H9YAS9.png

BottomNavigationViewはMVPで実装されています。
BottomNavigationViewは内部にPresenterを保持していて、そのPresenterがMenuとMenuItemをmenu.xmlからパース(モデル化)して、各viewに繋ぎこんでいます。

所感

BottomNavigationViewというくらいなので、Viewとしての役割を意識させたかったのかなと思っています。
なので、Fragmentに入れちゃうのもいいのかななんて考えています。
はじめはガイドライン読んでなかったので、
BottomNavigationView + ViewPagerのようにSwipeでページングするものとの実装を行っていました。
(これはダメな実装です。)
BottomNavigationViewで移動できるのはアイテムをクリックした時のみです。
少し触っただけなので、実際に実装する際のベストプラクティスはまだまだ模索中です。
もう少し触って色々確かめてみたいと思います。

117
106
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
117
106

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?