BottomNavigationViewのカスタマイズ - Re.Ra.Ku アドベントカレンダー day 18
Re.Ra.Ku アドベントカレンダー 18日目です。
こんにちは。安部です。
BottomNavigationViewのカスタマイズを試してみました。
ちょっと無理やりやってる感じの箇所もあります。
Version
使用したSupportLibraryは25.1.0
です。
BottomNavigationViewの基本
基本的な使い方は以前、私の書いたものを参照してください。
BottomNavigationViewを試してみる - Qiita
アイコンとテキストの色を状態によって変更する
未選択の状態、タップされてる状態、選択された状態で色を変更する方法です。
res/color/bottom_navigation.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="#FF0000" /> <item android:state_pressed="true" android:color="#00FF00" /> <item android:color="#FFFFFF" /> </selector>
次にそれをレイアウトで指定してあげます。app:itemIconTint
とapp:itemTextColor
です。
<android.support.design.widget.BottomNavigationView android:id="@+id/navigation" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimaryDark" app:itemIconTint="@color/bottom_navigation" app:itemTextColor="@color/bottom_navigation" app:menu="@menu/bottom_navigation" />
常にテキストを表示させる
メニューの数が3つを超えると選択されているメニュー以外のテキストが表示されなくなってしまいます。それを無理やり表示する方法です。
正直よろしくない方法だと思います。現状で頑張った結果です。
MatrialDesignの仕様を確認すると3つ超えるとテキスト出てないので、別に無理やりやる必要はないのですが、なんか要望とかであがってきそうなパターンだなって思ってやってみました。
BottomNavigationView navigationView = (BottomNavigationView) findViewById(R.id.navigation); BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt(0); for (int i = 0; i < menuView.getChildCount(); i++) { BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(i); itemView.setShiftingMode(false); itemView.setChecked(false); // Viewの状態を反映させるために呼んでいる }
スクロール時に隠す
RecyclerView等をスクロールしたときにBottomNavigationViewを隠す方法です。Toolbarでよくあるやつですね。
CoordinatorLayout.Behavior
を継承した下記のクラスを作成します。スクロールに合わせてViewの位置を変更しています。
public class BottomNavigationBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> { private int defaultTop; private int defaultBottom; private int defaultHeight; public BottomNavigationBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onLayoutChild(CoordinatorLayout parent, BottomNavigationView child, int layoutDirection) { defaultTop = child.getTop(); defaultBottom = child.getBottom(); defaultHeight = defaultBottom - defaultTop; return super.onLayoutChild(parent, child, layoutDirection); } @Override public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child, View directTargetChild, View target, int nestedScrollAxes) { return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL; } @Override public void onNestedScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { ViewCompat.offsetTopAndBottom(child, dyConsumed); if (dyConsumed > 0 && child.getTop() > defaultBottom) { child.setTop(defaultBottom); } else if (child.getTop() < defaultTop) { child.setTop(defaultTop); } child.setBottom(child.getTop() + defaultHeight); } }
次にレイアウトファイルです。ちょっと長いですが全部のせておきます。
BottomNavigationView
のapp:layout_behavior
に先程のクラスを指定します。これでスクロール時に隠れるようになります。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <android.support.design.widget.BottomNavigationView android:id="@+id/navigation" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background="@color/colorPrimaryDark" app:itemIconTint="@android:color/white" app:itemTextColor="@android:color/white" app:layout_behavior="com.star_zero.example.bottomnavigation.BottomNavigationBehavior" app:menu="@menu/bottom_navigation" /> </android.support.design.widget.CoordinatorLayout> </LinearLayout>
まとめ
BottomNavigationView
は制限がけっこうあって、5つより多くのメニューを設定しようとするとExceptionが投げられてクラッシュしたり、アイコンやテキストの大きさを自由に変えたりがかなり厳しいです。
あとはバグがそれなりある気がします。試した感じSnackbarがうまく表示できていない感じでした。Issue Trackerにもあがっています。
現状ではアプリの仕様によっては実現が難しいものが出てくるかもしれませんので慎重に導入を検討したいですね。