Support LibraryのNavigationViewでどこまでできるのか試してみる
久しぶりにサイドメニューのコードいじろうかと思ったのですが、デザインのカスタマイズ性の都合でサードパーティライブラリを使うのが辛く、ここから整理するよりSupport LibraryのNavigationViewを使って書き直した方が楽ではないか、と思ったので、どこまでできるのか試してみます。
内容
- ライブラリのバージョンについて
- 下記のコードを試す上で基本となるレイアウトなどのソースコード
- HeaderViewのレイアウトを変更する
- サイドメニューの項目を変更する場合
- サイドメニューの項目にバッジをつけたい場合
- 下に固定のfooterをつけたい場合
ライブラリのバージョンについて
gradleで指定していたバージョンは下記。
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support:design:23.4.0' compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha3' }
下記のコードを試す上で基本となるレイアウトなどのソースコード
Android Studioに用意されているNavigation Drawer Activityのプロジェクトのものをほとんどそのまま利用しています。
一応見たいという方はこちらよりご確認ください。
HeaderViewのレイアウトを変更する
NavigationView.removeHeaderView(View view)
とNavigationView.addHeaderView(View view)
を使えば特に難しいことを考えずサクッと入れ替えられました。
fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // HeaderViewを変更できるテストとしてHeaderViewが1個以上あれば // HeaderViewを消すテスト if(navigationView.getHeaderCount() >= 1) { navigationView.removeHeaderView(navigationView.getHeaderView(0)); } else { navigationView.inflateHeaderView(R.layout.nav_header_main); } } });
サイドメニューの項目を変更する場合
一部の項目の表示/非表示にする場合。
boolean isMenuGroup1Visible = true; FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 一部のmenuの項目の表示/非表示を切り替えるテスト navigationView.getMenu().setGroupVisible(R.id.menu_group_1, !isMenuGroup1Visible); isMenuGroup1Visible = !isMenuGroup1Visible; } });
サイドメニューの項目をがらっと変えたい場合。
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // サイドメニューの項目をmenuリソースから生成し直す場合 navigationView.getMenu().clear(); navigationView.inflateMenu(R.menu.test); } });
<!-- test.xml --> <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="Gallery" /> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow" /> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="Tools" /> </menu>
サイドメニューの項目にバッジをつけたい場合
menuリソースのitem要素の属性に、バッジの元となるWidgetのクラスとしてTextViewを指定して...とありましたが、この方法だと、どうも追加した要素の高さをうまく調整できなかったので、MenuItemCompat.setActionView(MenuItem menuItem, int layoutRes)
メソッドで、バッジ用に用意したレイアウトを与えて、そのレイアウトを変更してやる方がいじりやすそうでした。
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="Gallery" /> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow" /> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="Tools" /> </menu>
<!-- nav_menu_badge.xml --> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:textColor="@android:color/white" android:id="@+id/badge_text" android:background="@color/colorAccent" android:padding="4dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
MenuItem galleryItem = MenuItemCompat.setActionView(navigationView.getMenu().findItem(R.id.nav_gallery), R.layout.nav_menu_badge); TextView badgeText = (TextView) galleryItem.getActionView().findViewById(R.id.badge_text); badgeText.setText("99"); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // バッジを消したり、内容を変更したりするテスト LinearLayout galleryBadge = (LinearLayout) MenuItemCompat.getActionView(navigationView.getMenu().findItem(R.id.nav_gallery)); TextView badgeText = (TextView) galleryBadge.findViewById(R.id.badge_text); if(badgeText.getText() == "99+") { MenuItemCompat.setActionView(navigationView.getMenu().findItem(R.id.nav_gallery), null); } else { badgeText.setText("99+"); } } });
下に固定のfooterをつけたい場合
NavigationView
の中にandroid:layout_gravity="bottom"
の指定をつけて要素を追加したらよさそうでした。
<!-- activity_main.xml --> <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:openDrawer="start"> <include layout="@layout/app_bar_main" android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" app:menu="@menu/activity_main_drawer" > <TextView android:text="Footerのテスト" android:gravity="center" android:layout_gravity="bottom" android:background="@color/colorAccent" android:padding="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.design.widget.NavigationView> </android.support.v4.widget.DrawerLayout>
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.setDrawerListener(toggle); toggle.syncState(); }
追加したFooterとかぶった部分についてスクロールさせたいときはどうするかについては、対処が若干微妙で、アイコン透明なものを用意した選択不可能なメニューをその部分に追加するのが自分が探した中で綺麗な方の解決方法でした....^^;