前言
在谷歌官方发布BottomNavigationView控件之前我们可以自己组合控件实现,比如LinearLayout + TextView(使用android:drawableTop属性+selector状态切换)、RadioGroup + RadioButton等等组合控件的方法自定义实现复杂效果。除了第三方外,现在我们多了一个选择,就是使用bottomnavigation结合viewpager的实现。后期会有文章介绍前面的几种实现方式,对比下来这种代码量最少,而且特别清晰。
一 使用LinearLayout + TextView实现了底部导航栏的效果
学习一种新的技术首先要看在gradle中的配置(菇凉能力有限这篇文章只讲解这个控件是怎么用的,感兴趣的小伙伴可以去看源代码):
1.1 build.gradle中
compile'com.android.support:design:25.0.1'
compile'com.android.support:support-v4:25.0.1'
1.2 xml文件中
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.bottomnavigationview.MainActivity">
<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_selector"
app:itemTextColor="@drawable/bottom_selector"
app:menu="@menu/bottom_menu" />
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_above="@id/bottom_navigation"
android:background="@drawable/bottomshadow" />
</RelativeLayout>
这里简单说一下
android.support.design.widget.BottomNavigationView
中的一些属性:
- app:itemIconTint="@drawable/bottom_selector" :这个是底部栏图片颜色变化的selector
- app:itemTextColor="@drawable/bottom_selector":这个是底部栏文字颜色变化的selector
- app:menu="@menu/bottom_menu":这个是底部栏模块item的定义,包括文字和图片
1.3 在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/icon_navigation_home_01"
android:title="首页" />
<item
android:id="@+id/item_lib"
android:icon="@mipmap/icon_navigation_shop_01"
android:title="搜索" />
<item
android:id="@+id/item_find"
android:icon="@mipmap/icon_navigation_ucenter_01"
android:title="我的" />
<item
android:id="@+id/item_more"
android:icon="@mipmap/icon_navigation_home_01"
android:title="主页" />
</menu>
1.4 在drawable下新建.xml文件 颜色和文字变化的颜色一样selector,代码如下
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/p_select_color" android:state_checked="true" />
<item android:color="@color/p_99_color" android:state_checked="false" />
</selector>
1.5 MainActivity中的主要代码:
package com.bottomnavigationview;
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;
public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
private MenuItem menuItem;
private BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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用起来虽然简单,但是有一个很坑的问题,就是它内部在item>4的时候出现动画的效果。如下:
在平时的开发中这种效果也是特别崩溃的,因为官方没有默认的方法取消这种效果,这时候需要我们用到反射。
创建一个Helper类
package com.bottomnavigationview;
import android.annotation.TargetApi;
import android.os.Build;
import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import java.lang.reflect.Field;
/**
* Created by 凉菇凉 on 2017/8/2.
*/
public class BottomNavigationViewHelper {
@TargetApi(Build.VERSION_CODES.KITKAT)
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();
}
}
}
使用的时候
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
1.6 其实避了这个坑是特别简单的,viewpager就不在这里详细说了。来上一张效果动图。
补充 :
BaseFragment中的代码
public class BaseFragment extends Fragment {
private static final String EXTRA_CONTENT = "content";
public static BaseFragment newInstance(String content){
Bundle arguments = new Bundle();
arguments.putString(EXTRA_CONTENT, content);
BaseFragment tabContentFragment = new BaseFragment();
tabContentFragment.setArguments(arguments);
return tabContentFragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.fragment_tab_content, null);
((TextView)contentView.findViewById(R.id.tv_content)).setText(getArguments().getString(EXTRA_CONTENT));
return contentView;
}
}