底部导航BottomNavigationView+ViewPager+Fragment

Android端采用底部导航栏的APP很是多,好比微信、微博、支付宝...等等,这也不能说是盲目学习iOS,毕竟好东西你们均可以用,各家操做系统也都在博采众长,互相学习。Android端的底部导航栏有着一套规范, 详情 。php

这篇文章为你们带来html

1.官方BottomNavigationView的使用方法java

2.结合ViewPager、Fragment实现一个流行UI布局!android

3.并用反射解决ViewPager与BottomNavigationView侧滑联动时的一个小问题。git

最终实现效果:github

BottomNavigationView.gif微信

在谷歌官方发布BottomNavigationView控件以前咱们能够本身组合控件实现,好比LinearLayout + TextView(使用android:drawableTop属性+selector状态切换)、RadioGroup + RadioButton等等组合控件的方法自定义实现复杂效果。除了第三方外,如今咱们多了一个选择。app

开始框架

1.新建project而后导入如下support:design library,BottomNavigationView就在这个design库中。顺带导入这个V4包,由于待会要使用到ViewPager(这里其实不用记这么麻烦的库跟版本怎么写,直接在AS 的design面板把控件拖进来就会自动导入了。)less

compile'com.android.support:design:25.0.1'
compile'com.android.support:support-v4:25.0.1'

2.在res下新建menu文件夹,新建一个menu菜单,多少个本身看着办吧:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/item_news" android:icon="@mipmap/ic_news_gray" android:title="新闻" />
    <item android:id="@+id/item_lib" android:icon="@mipmap/ic_library_gray" android:title="图书" />
    <item android:id="@+id/item_find" android:icon="@mipmap/ic_discovery_gray" android:title="发现" />
    <item android:id="@+id/item_more" android:icon="@mipmap/ic_more_gray" android:title="更多" />
</menu>

3.接着是布局文件主要代码以下(最下面的View效果是加一个阴影):

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@+id/bottom_navigation" />

<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottom_navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
   android:layout_alignParentBottom="true" 
   app:itemIconTint="@drawable/bottom_navigation_selector"
   app:itemTextColor="@drawable/bottom_navigation_selector"
   app:menu="@menu/menu_bottom_navigation" />

<View
    android:layout_width="match_parent"
    android:layout_height="5dp"
    android:layout_above="@id/bottom_navigation"
    android:background="@drawable/bottom_shadow" />

app:itemIconTint="@drawable/bottom_navigation_selector" 为icon着色,写个selector便可。

app:itemTextColor="@drawable/bottom_navigation_selector"该属性为文字着色,一样写个selector实现点击颜色切换的效果。

4.写完布局写代码,完整activity文件以下:

实例化控件后为NavigationView添加监听事件便可,代码以下:

package com.fedming.bottomnavigationdemo; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.BottomNavigationView; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; /** * Created by bruce on 2016/11/1. * HomeActivity 主界面 */ public class HomeActivity extends AppCompatActivity { private ViewPager viewPager; private MenuItem menuItem; private BottomNavigationView bottomNavigationView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); viewPager = (ViewPager) findViewById(R.id.viewpager); bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation); //默认 >3 的选中效果会影响ViewPager的滑动切换时的效果,故利用反射去掉 BottomNavigationViewHelper.disableShiftMode(bottomNavigationView); bottomNavigationView.setOnNavigationItemSelectedListener( new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case R.id.item_news: viewPager.setCurrentItem(0); break; case R.id.item_lib: viewPager.setCurrentItem(1); break; case R.id.item_find: viewPager.setCurrentItem(2); break; case R.id.item_more: viewPager.setCurrentItem(3); break; } return false; } }); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (menuItem != null) { menuItem.setChecked(false); } else { bottomNavigationView.getMenu().getItem(0).setChecked(false); } menuItem = bottomNavigationView.getMenu().getItem(position); menuItem.setChecked(true); } @Override public void onPageScrollStateChanged(int state) { } }); //禁止ViewPager滑动 // viewPager.setOnTouchListener(new View.OnTouchListener() { // @Override // public boolean onTouch(View v, MotionEvent event) { // return true; // } // }); setupViewPager(viewPager); } private void setupViewPager(ViewPager viewPager) { ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); adapter.addFragment(BaseFragment.newInstance("新闻")); adapter.addFragment(BaseFragment.newInstance("图书")); adapter.addFragment(BaseFragment.newInstance("发现")); adapter.addFragment(BaseFragment.newInstance("更多")); viewPager.setAdapter(adapter); } }

能够看到BottomNavigationView+ViewPager+Fragment能够实现流行的布局框架,能够像微信那样左右滑动,也能够像支付宝那样点击切换。

截图20161211104920.png

细心的朋友可能发现了,上面的代码为何用了反射呢?

缘由就是官方的BottomNavigationView默认有个放大的ShiftingMode效果,可是还没有支持代码层级的切换。在3个menu item及如下时默认关闭,而到了4个及以上时就懵逼了,由于咱们是要作ViewPager的侧滑啊!

20161211105617.png

滑动时,ViewPager是切换过去了,下面这item也切换过去了,可是你说说这效果是否是坑爹!!?

没办法了,查了一圈资料,发现官方这个控件还不支持代码层级的切换选项(若是你发现了,请告诉我)。无可奈何,只能看源码,开启上帝(反射)模式了!

mShiftingMode.png

public class BottomNavigationViewHelper { public static void disableShiftMode(BottomNavigationView navigationView) { BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt(0); try { Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode"); shiftingMode.setAccessible(true); shiftingMode.setBoolean(menuView, false); shiftingMode.setAccessible(false); for (int i = 0; i < menuView.getChildCount(); i++) { BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(i); itemView.setShiftingMode(false); itemView.setChecked(itemView.getItemData().isChecked()); } } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } }

咱们经过反射拿到了BottomNavigationMenuView,至于为何是BottomNavigationView 的第一个子View这就要看源码了,AS中直接能够点进去看。而后咱们知道了这个效果是由mShiftingMode来决定的,那么上面的代码就好理解了。

在实例化BottomNavigationView后调用一次这行代码便可:

BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

若是不须要配置侧滑切换的话,直接默认效果就好,不要去反射修改了。禁止滑动时,为ViewPager添加setOnTouchListener接口,在onTouch下直接消费掉点击事件。添加下面这段代码:

//禁止ViewPager滑动 viewPager.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return true; } });

最后来看下效果:

BottomNavigationView.gif

大功告成!附上源码: 这里 。但愿能跟你们成为点赞之交,哈哈。