参考文章:Android 使用BottomNavigationView实现底部导航栏
本文学习自链接文章,对其介绍的方法进行了修改和封装,仅用作学习笔记,如有不当请指正
实现
1.导入以下support:design library,BottomNavigationView就在这个design库中。design版本号和项目的tagetSdkVersion相同
compile 'com.android.support:design:27.1.1'
2.在res下新建一个menu,然后在menu下建一个bottom_navigation_view_menu.xml(在四个item中,放置了四个icon)。
bottom_navigation_view_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/function_navigation_item"
android:icon="@drawable/ic_function"
android:title="功能" />
<item
android:id="@+id/store_list_navigation_item"
android:icon="@drawable/ic_store_list"
android:title="商户列表" />
<item
android:id="@+id/personal_navigation_item"
android:icon="@drawable/ic_personal"
android:title="个人" />
</menu>
3.layout下新建布局文件bottom_navigation_view.xml:
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--视图翻页工具-->
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<!--导航栏控件-->
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:layout_alignParentBottom="true"
android:background="?android:attr/windowBackground"
app:itemBackground="@null"
app:itemIconTint="@drawable/bottom_navigation_selector"
app:itemTextColor="@drawable/bottom_navigation_selector"
app:menu="@menu/bottom_navigation_view_menu" />
</LinearLayout>
4.在drawable中新建bottom_navigation_selector.xml(设置文字和icon选中和未选中的颜色):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/tab_checked" android:state_checked="true" />
<item android:color="@color/tab_unchecked" android:state_checked="false" />
</selector>
5.color中增加两个颜色值:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="tab_checked">#ED6A2C</color>
<color name="tab_unchecked">#757575</color>
</resources>
6.新建BottomNavigationViewController类用于控制该组件
(使用了单例模式和建造者模式, 建造者模式用于更加方便快捷的调用,单例模式非必须,可根据具体问题修改)
/**
* 底部导航栏控制器
*
* Created by @桀骜
* 2018/10/5
*/
public class BottomNavigationViewController {
private static class Holder {
private static final BottomNavigationViewController INSTANCE = new BottomNavigationViewController();
}
private BottomNavigationView bottomNavigationView;
private MenuItem menuItem;
private List<Integer> menuItemIdList;
private ViewPager viewPager;
private ViewPagerAdapter viewPagerAdapter;
private List<Fragment> fragmentList;
private AppCompatActivity activity;
private BottomNavigationViewController() {
}
private void init() {
//设置bottomNavigationView的事件监听
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
menuItem = item;
int itemId = item.getItemId();
for (int i = 0; i < menuItemIdList.size(); i++) {
if (itemId == menuItemIdList.get(i)) {
viewPager.setCurrentItem(i);
return true;
}
}
return false;
}
}
);
//设置viewPager的事件监听
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) {
}
});
viewPagerAdapter.setList(fragmentList);
viewPager.setAdapter(viewPagerAdapter);
//
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
}
public static BottomNavigationViewController getInstance() {
return Holder.INSTANCE;
}
public static class Builder {
private final BottomNavigationViewController INSTANCE;
public Builder() {
INSTANCE = Holder.INSTANCE;
INSTANCE.menuItemIdList = new ArrayList<>();
INSTANCE.fragmentList = new ArrayList<>();
}
public Builder setActivity(AppCompatActivity activity) {
INSTANCE.activity = activity;
INSTANCE.viewPagerAdapter = new ViewPagerAdapter(activity.getSupportFragmentManager());
return this;
}
public Builder setBottomNavigationView(int bottomNavigationViewId) {
INSTANCE.bottomNavigationView = INSTANCE.activity.findViewById(bottomNavigationViewId);
return this;
}
public Builder setViewPager(int viewPagerId) {
INSTANCE.viewPager = INSTANCE.activity.findViewById(viewPagerId);
return this;
}
public Builder addFragmentAndMenuItem(Fragment fragment, Integer menuItemId) {
INSTANCE.fragmentList.add(fragment);
INSTANCE.menuItemIdList.add(menuItemId);
return this;
}
public BottomNavigationViewController build() {
INSTANCE.init();
return INSTANCE;
}
}
}
7.视图翻页工具的适配器ViewPagerAdapter:
/**
* Created by 桀骜 on 2018/9/4.
*/
public class ViewPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> list;
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
public void setList(List<Fragment> list) {
this.list = list;
notifyDataSetChanged();
}
//重写getItem()和getCount()方法,用于内部调用list中的内容以显示
@Override
public Fragment getItem(int position) {
return list.get(position);
}
@Override
public int getCount() {
return list != null ? list.size() : 0;
}
}
8.UI修改
(1) 取消位移动画
/**
* Created by 桀骜 on 2018/9/4.
*/
public class BottomNavigationViewHelper {
@SuppressLint("RestrictedApi")
public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.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 item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e("BNVHelper", "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e("BNVHelper", "Unable to change value of shift mode", e);
}
}
}
(2) 取消导航栏的点击效果(类似水波纹的效果)只需在bottom_navigation_view.xml文件中添加一个属性:
app:itemBackground="@null"
(3) 取消导航栏的每项点击文字和图片放大的效果
我们需要在values中的demens.xml中设置:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--BottomNavigationView 的选中没有选中的字体大小-->
<dimen name="design_bottom_navigation_active_text_size">10dp</dimen>
<dimen name="design_bottom_navigation_text_size">10dp</dimen>
<!--BottomNavigationView 只放图标时的设置-->
<!--<dimen name="design_bottom_navigation_active_text_size">0dp</dimen>-->
<!--<dimen name="design_bottom_navigation_text_size">0dp</dimen>-->
<!--<dimen name="design_bottom_navigation_margin">16dp</dimen>-->
</resources>
使用
(1) 在对应活动中通过BottomNavigationViewController的Builder子类传入需要的变量和控件id即建造完成
new BottomNavigationViewController.Builder()
.setActivity(this)
.setBottomNavigationView(R.id.bottomNavigationView)
.setViewPager(R.id.view_pager)
.addFragmentAndMenuItem(new Fragment(1), R.id.function_navigation_item)
.addFragmentAndMenuItem(new Fragment(2), R.id.store_list_navigation_item)
.addFragmentAndMenuItem(new Fragment(3), R.id.personal_navigation_item)
.build();
(2) 在活动的布局中引入bottom_navigation_view.xml
<include layout="@layout/bottom_navigation_view" />