下载demo:https://github.com/linliangliang/BottomNavagationBar
二级导航栏的实现是在之前学习导航栏的两种实现方式的基础上实现的。
1、https://blog.csdn.net/qq_25066049/article/details/84647988
2、https://blog.csdn.net/qq_25066049/article/details/84646650
首先还是先用BottomNavigation实现底部导航栏,再次基础上用tabLayout实现二级导航栏,
1、添加依赖:
implementation 'com.android.support:appcompat-v7:26.0.0'
compile 'com.ashokvarma.android:bottom-navigation-bar:2.0.3'
implementation 'com.android.support:support-v4:26.0.0'
compile 'com.android.support:design:26.0.0'
2、主界面布局activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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.zhengyuan.twolevelnavigationbar.MainActivity">
<FrameLayout
android:id="@+id/layFrame"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<com.ashokvarma.bottomnavigation.BottomNavigationBar
android:id="@+id/bottom_navigation_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
</LinearLayout>
3、为一级导航栏写四个fragment:
fragment_attention.xml
fragment_discovery.xml
fragment_profile.xml
fragment_home.xml
这四个fragment前三个布局一模一样,只是fragment_home.xml 因为要添加子导航栏,会有一些不一样:fragment_home.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:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/sub_bottom_tab_layout"
android:layout_width="match_parent"
android:layout_height="20dp"
app:tabIndicatorHeight="1dp"
app:tabSelectedTextColor="#03A9F4"
app:tabTextColor="@android:color/darker_gray"></android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/subViewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="none"></android.support.v4.view.ViewPager>
</LinearLayout>
其余三个只是显示一个text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="attention" />
</LinearLayout>
4、为一级导航栏写好布局后,就可以写mainActivity.以及为每一个布局写对应的实体类了
mainActivity.class:
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import com.ashokvarma.bottomnavigation.BottomNavigationBar;
import com.ashokvarma.bottomnavigation.BottomNavigationItem;
import com.ashokvarma.bottomnavigation.TextBadgeItem;
import com.zhengyuan.twolevelnavigationbar.fragment.FragmentAttention;
import com.zhengyuan.twolevelnavigationbar.fragment.FragmentDiscovery;
import com.zhengyuan.twolevelnavigationbar.fragment.FragmentHome;
import com.zhengyuan.twolevelnavigationbar.fragment.FragmentProfile;
public class MainActivity extends AppCompatActivity implements BottomNavigationBar.OnTabSelectedListener {
private final String TAG = "MainActivity";
private FragmentManager fragmentManager;//管理更新fragment;
private FragmentTransaction fragmentTransaction;
private BottomNavigationBar bottomNavigationBar;
private FragmentProfile fragmentProfile;
private FragmentAttention fragmentAttention;
private FragmentHome fragmentHome;
private FragmentDiscovery fragmentDiscovery;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFragment();
init();
}
private void init() {
bottomNavigationBar = findViewById(R.id.bottom_navigation_bar);
bottomNavigationBar.setMode(BottomNavigationBar.MODE_FIXED);
bottomNavigationBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC);
bottomNavigationBar.setInActiveColor(R.color.colorPrimaryDark);//文字图片的背景色
bottomNavigationBar.setActiveColor(R.color.colorAccent);//bar背景颜色
TextBadgeItem numberBadgeItem = new TextBadgeItem();
numberBadgeItem.setText("9") //显示的文本
.setBackgroundColor("#FF0000") //背景色
.setTextColor("#FFFFFF") //文本颜色
.setBorderColor("#000000") //border颜色
.setBorderWidth(5) //border宽度px
.setBackgroundColorResource(R.color.colorPrimaryDark) //背景色,资源文件获取
.setBorderColorResource(R.color.colorPrimary) //border颜色,资源文件获取
.setTextColorResource(R.color.colorAccent) //文本颜色,资源文件获取
.setAnimationDuration(30) //隐藏和展示的动画速度,单位毫秒,和setHideOnSelect一起使用
.setGravity(Gravity.RIGHT | Gravity.TOP) //位置,默认右上角
.setHideOnSelect(true); //true:当选中状态时消失,非选中状态显示,moren false
//添加并设置图标、图标的颜色和文字
bottomNavigationBar
.addItem(new BottomNavigationItem(R.drawable.tab_home_selector, "首页").setBadgeItem(numberBadgeItem))
.addItem(new BottomNavigationItem(R.drawable.tab_attention_selector, "爱好"))
.addItem(new BottomNavigationItem(R.drawable.tab_discovery_selector, "发现"))
.addItem(new BottomNavigationItem(R.drawable.tab_profile_selector, "我的"))
.setFirstSelectedPosition(0)
.initialise();
bottomNavigationBar.setTabSelectedListener(this);
setDefaultFragment();
}
//设置初始界面
private void setDefaultFragment() {
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.layFrame, FragmentHome.newInstance("首页"));
fragmentTransaction.commit();
}
private void initFragment() {
Log.i("test==", "首页== null");
fragmentProfile = FragmentProfile.newInstance("我的");
fragmentAttention = FragmentAttention.newInstance("爱好");
fragmentHome = FragmentHome.newInstance("主页");
fragmentDiscovery = FragmentDiscovery.newInstance("发现");
}
@Override
public void onTabSelected(int position) {
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
switch (position) {
case 0:
if (fragmentHome == null) {
Log.i("test==", "首页== null");
fragmentHome = FragmentHome.newInstance("首页");
}
fragmentTransaction.replace(R.id.layFrame, fragmentHome);
break;
case 1:
if (fragmentAttention == null) {
fragmentAttention = FragmentAttention.newInstance("爱好");
}
fragmentTransaction.replace(R.id.layFrame, fragmentAttention);
break;
case 2:
if (fragmentDiscovery == null) {
fragmentDiscovery = FragmentDiscovery.newInstance("发现");
}
fragmentTransaction.replace(R.id.layFrame, fragmentDiscovery);
break;
case 3:
if (fragmentProfile == null) {
fragmentProfile = FragmentProfile.newInstance("我的");
}
fragmentTransaction.replace(R.id.layFrame, fragmentProfile);
break;
default:
break;
}
//事务提交
fragmentTransaction.commit();
}
@Override
public void onTabUnselected(int position) {
Log.d(TAG, "onTabUnselected() called with: " + "position = [" + position + "]");
}
@Override
public void onTabReselected(int position) {
}
}
为四个fragment写对应的类:
先写一个baseFragment:
import android.support.v4.app.Fragment;
import android.view.View;
/**
* Created by 林亮 on 2018/11/29
*/
public abstract class BaseFragment extends Fragment {
/**
* Fragment当前状态是否可见
*/
public boolean isVisible;
/**
* inflate布局文件 返回的view
*/
public View mView;
/**
* 简化 findViewById
*
* @param viewId
* @param <T>
* @return
*/
protected <T extends View> T find(int viewId) {
return (T) mView.findViewById(viewId);
}
/**
* setUserVisibleHint是在onCreateView之前调用的
* 设置Fragment可见状态
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
/**
* 判断是否可见
*/
if (getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
private void onVisible() {
lazyLoad();
}
private void onInvisible() {
}
/**
* 延迟加载
* 子类必须重写此方法
*/
public abstract void lazyLoad();
}
然后是FragmentAttention.java
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.zhengyuan.bottomnavigationbar.fragment.BaseFragment;
import com.zhengyuan.twolevelnavigationbar.R;
/**
* Created by 林亮 on 2018/11/30
*/
public class FragmentAttention extends BaseFragment {
/**
* 标志位,标志已经初始化完成
*/
private boolean isPrepared;
/**
* 是否已被加载过一次,第二次就不再去请求数据了
*/
private boolean mHasLoadedOnce;
TextView textView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (mView == null) {
// 需要inflate一个布局文件 填充Fragment
mView = inflater.inflate(R.layout.fragment_attention, container, false);
initView();
isPrepared = true;
//实现懒加载
lazyLoad();
}
//缓存的mView需要判断是否已经被加过parent, 如果有parent需要从parent删除,要不然会发生这个mView已经有parent的错误。
ViewGroup parent = (ViewGroup) mView.getParent();
if (parent != null) {
parent.removeView(mView);
}
return mView;
}
/**
* 初始化控件
*/
private void initView() {
}
@Override
public void lazyLoad() {
if (!isPrepared || !isVisible || mHasLoadedOnce) {
return;
}
//填充各控件的数据
mHasLoadedOnce = true;
}
public static FragmentAttention newInstance(String param1) {
FragmentAttention fragment = new FragmentAttention();
Bundle args = new Bundle();
args.putString("agrs1", param1);
fragment.setArguments(args);
return fragment;
}
}
FragmentDiscovery.java 和FragmentProfile.java两个类和上面一样,只是替换布局,更改对应的类名即可,
如何FargmentHome.calss和上面写的一样的话就是一级导航栏,但是我们要在home中实现二级导航栏,就会不一样:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.zhengyuan.bottomnavigationbar.fragment.BaseFragment;
import com.zhengyuan.twolevelnavigationbar.R;
import com.zhengyuan.twolevelnavigationbar.adapter.SubFragmentPagerAdapter;
/**
* Created by 林亮 on 2018/11/30
*/
public class FragmentHome extends BaseFragment {
private TabLayout mTabLayout;
private ViewPager mViewPager;
private SubFragmentPagerAdapter subFragmentPagerAdapter;
/**
* 标志位,标志已经初始化完成
*/
private boolean isPrepared;
/**
* 是否已被加载过一次,第二次就不再去请求数据了
*/
private boolean mHasLoadedOnce;
TextView textView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (null != mView) {
ViewGroup parent = (ViewGroup) mView.getParent();
if (null != parent) {
parent.removeView(mView);
}
} else {
mView = inflater.inflate(R.layout.fragment_home, null);
initView();// 控件初始化
}
mViewPager = find(R.id.subViewPager);
subFragmentPagerAdapter = new SubFragmentPagerAdapter(getChildFragmentManager());
mViewPager.setAdapter(subFragmentPagerAdapter);
//将TabLayout与ViewPager绑定在一起
mTabLayout = (TabLayout) find(R.id.sub_bottom_tab_layout);
mTabLayout.setupWithViewPager(mViewPager);
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
return mView;
/*//if (mView == null) {
// 需要inflate一个布局文件 填充Fragment
mView = inflater.inflate(R.layout.fragment_home, container, false);
initView();
isPrepared = true;
//实现懒加载
//lazyLoad();
//}*/
/*//缓存的mView需要判断是否已经被加过parent, 如果有parent需要从parent删除,要不然会发生这个mView已经有parent的错误。
ViewGroup parent = (ViewGroup) mView.getParent();
if (parent != null) {
parent.removeView(mView);
}
return mView;*/
}
/**
* 初始化控件
*/
private void initView() {
Log.i("test==", "FragmentHome initView");
//使用适配器将ViewPager与Fragment绑定在一起
}
@Override
public void lazyLoad() {
if (!isPrepared || !isVisible || mHasLoadedOnce) {
return;
}
//填充各控件的数据
mHasLoadedOnce = true;
}
public static FragmentHome newInstance(String param1) {
FragmentHome fragment = new FragmentHome();
Bundle args = new Bundle();
args.putString("agrs1", param1);
fragment.setArguments(args);
return fragment;
}
}
5、当然还需要为二级导航栏写三个fragment和三个对应的class
如下:sub_fragment_first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="subFragmentFirst" />
</LinearLayout>
sub_fragment_second.xml
sub_fragment_third.xml一样只显示一个text,不再重复贴代码
有了子fragment还需要为他们添加对应的类:FragmentSubFirst
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.zhengyuan.twolevelnavigationbar.R;
/**
* Created by 林亮 on 2018/11/30
*/
public class FragmentSubFirst extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.sub_fragment_first, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
其余两个如法炮制。
6、然后为二级导航栏添加一个适配器SubFragmentPagerAdapter.java:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.zhengyuan.twolevelnavigationbar.subfragment.FragmentSubFirst;
import com.zhengyuan.twolevelnavigationbar.subfragment.FragmentSubSecond;
import com.zhengyuan.twolevelnavigationbar.subfragment.FragmentSubThird;
/**
* Created by 林亮 on 2018/11/30
*/
public class SubFragmentPagerAdapter extends FragmentPagerAdapter {
private String[] mTitles = new String[]{"爱好", "发现", "主页"};
public SubFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
if (position == 0) {
return new FragmentSubFirst();
} else if (position == 1) {
return new FragmentSubSecond();
}
return new FragmentSubThird();
}
@Override
public int getCount() {
return mTitles.length;
}
//ViewPager与TabLayout绑定后,这里获取到PageTitle就是Tab的Text
@Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}
7、代码就完成了其中涉及的文图,需要导入资源。