【Android/Kotlin】BottomNavigationVeiwを使って自分好みのメニューを作る方法

【Android/Kotlin】BottomNavigationVeiwを使って自分好みのメニューを作る方法

今回はBottomNavigationViewを使って、画面の下にメニューを表示するを作っていきます。

たとえば、YouTubeとか

Instagramとか

で採用されているものです。

私はNavigationDrawerより使いやすくて、好きですが、あまり使われているレイアウトではないんですよね。

はい、では早速、作っていきましょう。

AndroidStudioの「Bottom Navigation Activity」を使ってベースを作る

AndroidStudioにて提供されているActivityの1つになっていますので、選択するだけで簡単に作ることができます。

Activiryの作成する中に、「Bottom Navigation」を選択して、

このような画面が表示されるので、そのまま作成すると、出来上がり。

こんな感じで作られます

  • ボトムメニューの表示
  • タップ時のアニメーション(テキスト表示/タップ動作)
  • タップ後にアイコンとテキストの色変更

などが実装されています。

おー、これで十分じゃないの!

となりそうですが、かなり物足りないので、そのカスタマイズを説明していきますね。

Advertisement

メニューを追加する

BottomNavigationでは、メニュー情報はxmlにて定義しています。

res -> menu -> navigation.xml が作成されていると思いますので、こちらに設定を追加することで、メニューを増やすことが可能です。

アイコンを追加する方法

メニュー追加するにあたって、アイコンの追加が必要になりますので、簡単にアイコンの増やし方の説明しますね!

material.io

こちらのサイトからアイコンを作成(SVG)、ダウンロードしてください。

次に、ファイルの取り込みになります。

App -> res -> drawable にて  new -> vector assetを選択してください。

このようなダイアログが表示されると思います。

こちらにて、任意の名前を設定、ダウンロードしてきたアイコンファイルを指定してください。

OKをクリックすれば取り込み終了です。

設定ファイルにメニュー情報を追加

追加したいメニューをxmlファイルに追加していきます。

res -> menu -> navigation.xml を以下のように設定します。

<?xml version="1.0"encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
       android:id="@+id/navigation_home"
       android:icon="@drawable/ic_home_black_24dp"
       android:title="@string/title_home"/>
    <item
       android:id="@+id/navigation_dashboard"
       android:icon="@drawable/ic_dashboard_black_24dp"
       android:title="@string/title_dashboard"/>
    <item
       android:id="@+id/navigation_notifications"
       android:icon="@drawable/ic_notifications_black_24dp"
       android:title="@string/title_notifications"/>

 ※ ここを追加
    <item
       android:id="@+id/navigation_bookmark"
       android:icon="@drawable/ic_baseline_bookmarks_24px"
       android:title="@string/title_bookmark"/>
 ※ ここまで

</menu>

以上を設定することで、メニューが追加されます

メニューのカスタマイズ

次にボトムメニューを少しカスタマイズしていきましょう。

カスタマイズしていくためには、ヘルパークラスを作る必要があります。

BottomNavigationViewは全体を制御してしていますが、

メニューの表示位置などはBottomNavigationMenuViewで、

メニュー内のアイコン、テキストはBottomNavigationItemViewにて制御をしているためです。

前後関係もあるので、まずはソース全体

class BottomNavigationHelper() {

    @SuppressLint("RestrictedApi")
    fun disableMode(view : BottomNavigationView) {
        var menuView : BottomNavigationMenuView = view.getChildAt(0) as BottomNavigationMenuView

        //アニメーションをなくす
        val mode = menuView.javaClass.getDeclaredField("mShiftingMode")
        mode.isAccessible = true
        mode.setBoolean(menuView, false)
        mode.isAccessible = false

        //テキストを常に表示/等間隔に表示
        for (i in 0 until menuView.childCount){
            val itemView = menuView.getChildAt(i) as BottomNavigationItemView
            itemView.setShiftingMode(false)
            itemView.setChecked(itemView.itemData.isChecked)
        }
    }
}

こちらのヘルパークラスのメソッドをActivityからCallすることで制御していきます。

※ Activityからの抜粋 

BottomNavigationHelper().disableMode(bottom_navigation)

テキストを常に表示する/等間隔表示

作成したアプリでは、タップするとテキストが表示され、選択されていないとテキストは非表示担っています。

これを常に表示する方法ですね。

こちらの対応をしているのは、ここ

//テキストを常に表示/等間隔に表示

for (i in 0 until menuView.childCount){

    val itemView = menuView.getChildAt(i) as BottomNavigationItemView

    itemView.setShiftingMode(false)

    itemView.setChecked(itemView.itemData.isChecked)
}

こちらにて、テキストが表示されています。

Advertisement

アニメーションをなくす

こちらを制御している部分はこちらです。

//アニメーションをなくす

val mode = menuView.javaClass.getDeclaredField("mShiftingMode")
mode.isAccessible = true
mode.setBoolean(menuView, false)
mode.isAccessible = false

こちらのように等間隔で表示されるようになりました!

アイコン/テキストの色変更

次にアイコン、テキストの色を変更していきます。

初期表示、タップ時、選択されている場合の3つのケースで指定します。

色の設定情報を追加していきます。

resフォルダを選択後、右クリック、「Resource Directory」をクリックしてください。

ダイアログが表示されるので、TypeをColorにして、設定ファイルを作成してください。

作成したxmlファイルに以下の設定を追加します。

<?xml version="1.0"encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:color="#888" />
    <item android:state_pressed="true" android:color="#111" />
    <item android:color="#EEEEEE" />
</selector>

デフォルト、タップされた時、タップされた後の色の指定をしていきます。

あと、この設定ファイルををBottomNavigationViewから読み込むようにすれば終わりです。

<android.support.design.widget.BottomNavigationView
   android:id="@+id/bottom_navigation"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_gravity="bottom"
   android:background="?android:attr/windowBackground"
   app:menu="@menu/navigation"

  ※ ここを追加
   app:itemIconTint="@color/buttom_navi"
   app:itemTextColor="@color/buttom_navi"

   />

実行してみると、色が変更されています

Advertisement

スクロール時にメニューを非表示にする

最後に、スクロールしたときにメニューを非表示にする方法です。

常時見えていても構わないですが、広く使いたい等の要望もあると思いますので、下にスクロールした時、非表示にしていきます。

CoodinaterLayoutの追加

スクロールを検知するため、CoordinaterLayoutを利用します。

こちらのように、対象となるViewをCoordinaterLayout内に定義するようにしてください。

<android.support.design.widget.CoordinatorLayout
   android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
       android:id="@+id/recyclerView"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_marginBottom="8dp"
        tools:listitem="@layout/item_list">
    </android.support.v7.widget.RecyclerView>

    <android.support.design.widget.BottomNavigationView
       android:id="@+id/bottom_navigation"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="bottom"
       android:background="?android:attr/windowBackground"
       app:layout_behavior="apps.test.marketableskill.biz.bottmmenu.BottomBarBehavior"
       app:menu="@menu/navigation"
       app:itemIconTint="@color/buttom_navi"
       app:itemTextColor="@color/buttom_navi"
        />
</android.support.design.widget.CoordinatorLayout>

囲むだけですので、特段難しくはないはずです。

動作時に実行するクラスの追加(behaviorクラス)

検知後の処理は、CoordinatorLayout.Behaviorを利用します。

このクラスを継承することで、スクロールを検知して、その後の処理を実装することができます。

class BottomBarBehavior<V : View>(context: Context?, attrs: AttributeSet?)
   : CoordinatorLayout.Behavior<BottomNavigationView>(context, attrs) {

    private var ch: Int = 0

    override fun onLayoutChild(parent: CoordinatorLayout?, child: BottomNavigationView?, layoutDirection: Int): Boolean {
        ch = child!!.height
        return super.onLayoutChild(parent, child, layoutDirection)
    }
    override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: BottomNavigationView, directTargetChild: View, target: View, axes: Int, type: Int): Boolean {
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL
    }
    override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: BottomNavigationView, target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int) {
        if (dyConsumed > 0) {
            child.visibility = View.INVISIBLE
            slideDown(child)
        } else if (dyConsumed < 0) {
            child.visibility = View.VISIBLE
            slideUp(child)
        }
    }
    private fun slideUp(child: BottomNavigationView) {
        child.clearAnimation()
        child.animate().translationY(0F).duration = 200
    }

    private fun slideDown(child: BottomNavigationView) {
        child.clearAnimation()
        child.animate().translationY(ch.toFloat()).duration = 200
    }
}

BottomNavigationにlayout_behaviorの追加

先程作成したクラウスをBottomNavigationViewのlayout_behavior属性の値として設定します。

    <android.support.design.widget.BottomNavigationView
       android:id="@+id/bottom_navigation"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="bottom"
       android:background="?android:attr/windowBackground"
       app:menu="@menu/navigation"
       app:itemIconTint="@color/buttom_navi"
       app:itemTextColor="@color/buttom_navi"

    ※ ここを追加
       app:layout_behavior="apps.test.marketableskill.biz.bottmmenu.BottomBarBehavior"
        />

以上の対応で、下にスクロールした時にメニューを非表示することができます。

はい、以上がBottomNavigationViewをカスタマイズする方法でした。

今回は設定ファイルを変更するだけでなく、Helper、behaviorなどのクラスを作り、他のViewの設定を変更する仕組みに取り組みました。

Android開発の一端を垣間見れたと思います。

こちらを踏まえて、ガシガシと自分好みにカスタマイズしていきましょう〜