底部导航栏是很多APP都在使用的设计,像QQ、微信、支付宝等,已经是每个Android应用必不可少的了。
本文将展示用两种方法实现。
一.BottomNavigationView+FrameLayout
实现效果如图:
思路:
做开发,在实现某些功能时不仅学习的是其实现过程,更重要的是理解其制作思路,才能举一反三。
底部导航功能的实现分为两块,一部分是底部的导航按钮,另一部分是根据底部导航更换要显示的内容部分,我们所看见的更换的内容其实是fragment。
思路:
1.使用BottomNavigationView制作其底部按钮。
2.在内容区域放上FrameLayout用于放置要添加的fragment
3.实现二者的联动
实现:
1.引入依赖
compile 'com.android.support:design:26.1.0'
2.在主界面activity_main中添加控件
<?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"
android:orientation="vertical"
tools:context="com.example.lenovo.bottomnavigation.MainActivity">
<!--用于切换fragment-->
<FrameLayout
android:id="@+id/fl_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/bnv_main"/>
<android.support.design.widget.BottomNavigationView
android:id="@+id/bnv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
BottomNavigationViewlai'来自于引入的design包
3.添加item
在主界面中添加了BottomNavigationView后就要为其设置item项,在item中设置按钮图标和文字
在res目录下新建menu文件夹,在该文件夹下新建menu resource file,命名navigation.xml
navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_home"
android:icon="@drawable/homeb"
android:title="@string/home" />
<item
android:id="@+id/navigation_buy"
android:icon="@drawable/shopb"
android:title="@string/order" />
<item
android:id="@+id/navigation_user"
android:icon="@drawable/userb"
android:title="@string/my" />
</menu>
要提前准备6张图片,分别表示按钮的选中和未选中状态,按钮标题提取到strings中
在此都静态设置为未选中状态的图标。
到这里如果运行的话会发现自定义的图标不会显示出来,不着急,我们会在下面解决
4.创建fragment
在此我们要创建3个不同的fragment
首页:
HeadFragment.java
public class HeadFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//该View表示该碎片的主界面,最后要返回该view
View view=inflater.inflate(R.layout.fragment_head,container,false);
//找到主界面view后,就可以进行UI的操作了。
//注意:因为主界面现在是view,所以在找寻控件时要用view.findViewById
TextView textView=view.findViewById(R.id.tv_head);
//textView.setText("");
return view;
}
}
fragment_head.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_head"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="首页"
android:textSize="30sp" />
</FrameLayout>
为简单起见,在fragment中只添加了一个TextView。
再按同样的方法创建其他两个fragment,
分别是OrderFragment.java+fragment_order.xml 和 UserFragment.java+fragment_user.xml
创建过程就不在此赘述,和创建HeadFragment一样
5.MainActivity.java
最后一部分也是重要的部分,直接上代码:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private BottomNavigationView navigationView;
//创建三个Fragment和存放他们的数组
private Fragment headFragment;
private Fragment orderFragment;
private Fragment userFragment;
public Fragment[] fragmentlist;
//用于标识上一个fragment
private int lastFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//fragment初始化
initFragment();
}
/**
* 初始化fragment,并将headFragment显示出来
*/
private void initFragment() {
navigationView = (BottomNavigationView) findViewById(R.id.bnv_main);
//配置菜单按钮显示图标
navigationView.setItemIconTintList(null);
//将三个fragment先放在数组里
headFragment = new HeadFragment();
orderFragment = new OrderFragment();
userFragment = new UserFragment();
fragmentlist = new Fragment[]{headFragment, orderFragment, userFragment};
//此时标识标识首页
//0表示首页,1表示orderFragment,2表示userFragment
lastFragment = 0;
//为navigationView设置点击事件
navigationView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
//设置默认页面为headFragment
getSupportFragmentManager().beginTransaction().replace(R.id.fl_main, headFragment)
.show(headFragment).commit();
navigationView.setSelectedItemId(R.id.navigation_home);
}
/**
* 给BottomNavigationView添加按钮的点击事件
*/
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
//每次点击后都将所有图标重置到默认不选中图片
resetToDefaultIcon();
switch (item.getItemId()) {
case R.id.navigation_home:
//判断要跳转的页面是否是当前页面,若是则不做动作
if (lastFragment != 0) {
switchFragment(lastFragment, 0);
lastFragment = 0;
}
//设置按钮的
item.setIcon(R.drawable.homea);
return true;
case R.id.navigation_buy:
if (lastFragment != 1) {
switchFragment(lastFragment, 1);
lastFragment = 1;
}
item.setIcon(R.drawable.shopa);
return true;
case R.id.navigation_user:
if (lastFragment != 2) {
switchFragment(lastFragment, 2);
lastFragment = 2;
}
item.setIcon(R.drawable.usera);
return true;
}
return false;
}
};
/**
*
* @param lastFragment 表示点击按钮前的页面
* @param index 表示点击按钮对应的页面
*/
private void switchFragment(int lastFragment, int index) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
//隐藏上个Fragment
transaction.hide(fragmentlist[lastFragment]);
//判断transaction中是否加载过index对应的页面,若没加载过则加载
if (fragmentlist[index].isAdded() == false) {
transaction.add(R.id.fl_main, fragmentlist[index]);
}
//根据角标将fragment显示出来
transaction.show(fragmentlist[index]).commitAllowingStateLoss();
}
/**
* 重新配置每个按钮的图标
*/
private void resetToDefaultIcon() {
navigationView.getMenu().findItem(R.id.navigation_home).setIcon(R.drawable.homeb);
navigationView.getMenu().findItem(R.id.navigation_buy).setIcon(R.drawable.shopb);
navigationView.getMenu().findItem(R.id.navigation_user).setIcon(R.drawable.userb);
}
}
代码中的注释都很详细,大致实现步骤是:
拿到BottomNavigationView实例-->为其设置按钮点击事件-->设置默认页面
其中,FragmentTransaction相当于是个容器,会将所有被添加的fragment保存起来,再配置把哪个显示、哪个隐藏。
刚才遗留的问题,也被解决了,因为BottomNavigationView有其默认的按钮图标,所以我们自定义的图标不会显示。我们
可以把BottomNavigationView默认icon设置为null。
navigationView.setItemIconTintList(null);
完成。