先来看看底部导航栏的效果

Android 底部导航栏有很多种写法,例如:

RadioGroup , Tablayout, TabHost  , LinearLayout + ImageView + TextView  ,BottomNavigationView

我们就来看最常用的两种底部导航栏的用法

一. LinearLayout  + ImageView + TextView

这种是用  LinearLyaout + ImageView + TextView 布局UI,  xml 代码如下

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:id="@+id/fl_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/line"/>
    <View
        android:id="@+id/line"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorTextGrey"
        android:layout_above="@+id/ll"
        />
    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:background="@color/bg_white"
        android:orientation="horizontal"
        >
        <LinearLayout
            android:id="@+id/ll_tab1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical">
            <ImageView
                android:id="@+id/iv1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/selector_page1" />
            <TextView
                android:id="@+id/tv1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="2dp"
                android:gravity="center"
                android:text="@string/menu_bottom_navigation1"
                android:textColor="@color/colorTextGrey"
                android:textSize="11sp" />
        </LinearLayout>
        <LinearLayout
            android:id="@+id/ll_tab2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical">
            <ImageView
                android:id="@+id/iv2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/selector_page2" />
            <TextView
                android:id="@+id/tv2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="2dp"
                android:gravity="center"
                android:text="@string/menu_bottom_navigation2"
                android:textColor="@color/colorTextGrey"
                android:textSize="11sp" />
        </LinearLayout>
        <LinearLayout
            android:id="@+id/ll_tab3"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical">
            <ImageView
                android:id="@+id/iv3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/selector_page3" />
            <TextView
                android:id="@+id/tv3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="2dp"
                android:gravity="center"
                android:text="@string/menu_bottom_navigation3"
                android:textColor="@color/colorTextGrey"
                android:textSize="11sp" />
        </LinearLayout>
    </LinearLayout>
</android.support.percent.PercentRelativeLayout>

此布局最外层是百分比布局 PercentRelativeLayout (适配各种机型屏幕), 而后   是一个

帧布局 FrameLayout(用于Fragment),最后就是这个布局的重点 :  父LinearLayout

<LinearLayout
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_alignParentBottom="true"
    android:background="@color/bg_white"
    android:orientation="horizontal"
   >

这个LinearLayout  ,  宽为match_paren, 高为 50dp ,  位于父布局底部,子布局水平排列。

有人就会有疑问了:为什么 高为50dp?

因为底部导航栏其实有两种不同标准的高,一个 48dp , 一个 56dp(通过不断积累的经验:这样好看)。

而我给50dp, 算是取个中间整数。

下面看 父 LinearLayout 里面的 第一个 子 LinearLayout

<LinearLayout
    android:id="@+id/ll_tab1"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:gravity="center"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/iv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/selector_page1" />
    <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="2dp"
        android:gravity="center"
        android:text="@string/menu_bottom_navigation1"
        android:textColor="@color/colorTextGrey"
        android:textSize="11sp" />
</LinearLayout>

这个LinearLayout  ,  宽为0dp, 高为 match_paren , 权重为1(为了让 子LinearLayout 平分

总LinearLayout 的宽),内容居中, 子布局垂直排列:里面有 ImageView 和 TextView。

第一个子LinearLayout效果:

依葫芦画瓢,按第一个 子Linearlayout 写 第二个 子LinearLayout 和 第三个 子LinearLayout

总效果:

selector_page1 代码:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/img_1" android:state_enabled="true"></item>
    <item android:drawable="@mipmap/img_1_selected" android:state_enabled="false"></item>

selector_page2,selector_page3依葫芦画瓢

下面看Activity 代码:

public class BottomNavigationActivity1 extends AppCompatActivity {@BindView(R.id.fl_fragment)FrameLayout flFragment;
    @BindView(R.id.iv1)ImageView iv1;
    @BindView(R.id.tv1)TextView tv1;
    @BindView(R.id.ll_tab1)LinearLayout llTab1;
    @BindView(R.id.iv2)ImageView iv2;
    @BindView(R.id.tv2)TextView tv2;
    @BindView(R.id.ll_tab2)LinearLayout llTab2;
    @BindView(R.id.iv3)ImageView iv3;
    @BindView(R.id.tv3)TextView tv3;
    @BindView(R.id.ll_tab3)LinearLayout llTab3;
    Unbinder unbinder;
    Fragment1 fragment1;
    Fragment2 fragment2;
    Fragment3 fragment3;
    private Fragment fragment_now = null;
    private List<ImageView> iv_list;
    private List<TextView> tv_list;

    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bottom_navigation1);
        unbinder = ButterKnife.bind(this);
        inint();
    }private void inint() {iv_list = new ArrayList<>();
        tv_list = new ArrayList<>();
        iv_list.add(iv1);
        iv_list.add(iv2);
        iv_list.add(iv3);
        tv_list.add(tv1);
        tv_list.add(tv2);
        tv_list.add(tv3);
        changePageSelect(0);
        changePageFragment(R.id.ll_tab1);
    }@OnClick({R.id.iv1, R.id.ll_tab1, R.id.iv2, R.id.ll_tab2, R.id.iv3, R.id.ll_tab3})public void onViewClicked(View view) {changePageFragment(view.getId());
    }/**
     * 选中的tab 和 没有选中的tab 的图标和字体颜色
     *
     * @param index
     */
    public void changePageSelect(int index) {for (int i = 0; i < iv_list.size(); i++) {if (index == i) {iv_list.get(i).setEnabled(false);
                tv_list.get(i).setTextColor(getResources().getColor(R.color.colorLightRed));
            } else {iv_list.get(i).setEnabled(true);
                tv_list.get(i).setTextColor(getResources().getColor(R.color.colorTextGrey));
            }}}/**
     * 当点击导航栏时改变 fragment
     *
     * @param id
     */
    public void changePageFragment(int id) {switch (id) {case R.id.ll_tab1:case R.id.iv1:if (fragment1 == null) {//减少new fragmnet,避免不必要的内存消耗
                    fragment1 = Fragment1.newInstance();
                }changePageSelect(0);
                switchFragment(fragment_now, fragment1);
                break;
            case R.id.ll_tab2:case R.id.iv2:if (fragment2 == null) {fragment2 = Fragment2.newInstance();
                }changePageSelect(1);
                switchFragment(fragment_now, fragment2);
                break;
            case R.id.ll_tab3:case R.id.iv3:if (fragment3 == null) {fragment3 = Fragment3.newInstance();
                }changePageSelect(2);
                switchFragment(fragment_now, fragment3);
                break;
        }}/**
     * 隐藏显示fragment
     *
     * @param from 需要隐藏的fragment
     * @param to   需要显示的fragment
     */
    public void switchFragment(Fragment from, Fragment to) {if (to == null)return;
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (!to.isAdded()) {if (from == null) {transaction.add(R.id.fl_fragment, to).show(to).commit();
            } else {// 隐藏当前的fragment,add下一个fragment到Activity中并显示
                transaction.hide(from).add(R.id.fl_fragment, to).show(to).commitAllowingStateLoss();
            }} else {// 隐藏当前的fragment,显示下一个
            transaction.hide(from).show(to).commit();
        }fragment_now = to;

    }@Overrideprotected void onDestroy() {super.onDestroy();
        //解除绑定
        unbinder.unbind();
    }
}

首先 build.gradle 添加

implementation 'com.jakewharton:butterknife:8.8.1'

用 butterKnife找到控件并设置点击事件,并用List<ImageView>  iv_list 将 ImageView add,

List<TextView> tv_list将 TextView add,

然后是fragment

Fragment1 代码 :

public class Fragment1 extends Fragment {public Fragment1() {}   public static Fragment1 newInstance() {Fragment1 fragment = new Fragment1();
        return fragment;
    }@Override
    public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
    }@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_1, container, false);
    }}

Fragment1布局  fragment_1:

<FrameLayout 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"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第一个fragment"
        android:layout_gravity="center"/>
</FrameLayout>

Fragment2, Fragment3 及其布局 依葫芦画瓢

然后写changePageSelect() 改变 选中的tab 和 没有选中的tab 的图标和字体颜色

public void changePageSelect(int index) {for (int i = 0; i < iv_list.size(); i++) {if (index == i) {iv_list.get(i).setEnabled(false);
            tv_list.get(i).setTextColor(getResources().getColor(R.color.colorLightRed));
        } else {iv_list.get(i).setEnabled(true);
            tv_list.get(i).setTextColor(getResources().getColor(R.color.colorTextGrey));
        }}
}

然后写switchFragment() 添加 ,显示, 隐藏 frament

public void switchFragment(Fragment from, Fragment to) {if (to == null)return;
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    if (!to.isAdded()) {if (from == null) {transaction.add(R.id.fl_fragment, to).show(to).commit();
        } else {// 隐藏当前的fragment,add下一个fragment到Activity中并显示
             transaction.hide(from).add(R.id.fl_fragment,to).show(to).commitAllowingStateLoss();
        }} else {// 隐藏当前的fragment,显示下一个
        transaction.hide(from).show(to).commit();
    }fragment_now = to;

}

此方法传入 Fragment form , Fragment to 。 首先判断 Fragment to 是否为 null,

Fragment to为 null 则 return;Fragment to不为 null  往下走得到  FragmnetTranscation transcation。

然后判断 Fragment to 是否添加到Activity,

Fragment to 没有添加到了 Activity 则 判断 Fragment  form 是否为 null ,

Fragment form 为 null 则将  Fragment to 添加到Activity 中 并显示;

Fragment form 不为null 则 隐藏Fragment form,将Fragment to 添加到Activity 中 并显示;

Fragment to 添加到了 Activity  则隐藏Fragment form, 显示 Fragment to;

最后将 Fragment to 赋值给 Fragment fragment_now

最后写changepageFragment() , 调用 changePageSelect() 与 switchFragment() 并给点击事件调用

public void changePageFragment(int id) {switch (id) {case R.id.ll_tab1:case R.id.iv1:if (fragment1 == null) {//减少new fragmnet,避免不必要的内存消耗
                fragment1 = Fragment1.newInstance();
            }changePageSelect(0);
            switchFragment(fragment_now, fragment1);
            break;
        case R.id.ll_tab2:case R.id.iv2:if (fragment2 == null) {fragment2 = Fragment2.newInstance();
            }changePageSelect(1);
            switchFragment(fragment_now, fragment2);
            break;
        case R.id.ll_tab3:case R.id.iv3:if (fragment3 == null) {fragment3 = Fragment3.newInstance();
            }changePageSelect(2);
            switchFragment(fragment_now, fragment3);
            break;
    }
}
@OnClick({R.id.iv1, R.id.ll_tab1, R.id.iv2, R.id.ll_tab2, R.id.iv3, R.id.ll_tab3})
public void onViewClicked(View view) {changePageFragment(view.getId());

}

changepageFragment() 的妙处就是调用 switchFragment() 第一个参数 传了 Fragment fragment_now,

这样 Fragment fragment_now() 与  switchFragment() 就通过 Fragment fragment_now 紧密联系起来

到此底部导航栏 LinearLyaout + ImageView + TextView 的写法到此就介绍完毕了!

二.  BotoomNavigationView

绝多数app都用底部导航栏,所以 google 爸爸为了方便开发者在 Design Support Library中添加了 BotoomNavigationView控件,我们就不用苦逼的LinearLyaout + ImageView + TextView 布局写法了!

首先 build.gradle 添加

implementation 'com.android.support:design:27.0.1'

然后布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout 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"
   >
    <FrameLayout
        android:id="@+id/fl_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/bottomNavigationView"
        />
    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        app:itemIconTint="@drawable/selector_bottom_navigation"
        app:itemTextColor="@drawable/selector_bottom_navigation"
        app:menu="@menu/menu_bottom_navigation"
        />
</android.support.percent.PercentRelativeLayout>

app:itemIconTint 为图标颜色变化 , app:itemtextColor 为为文字 颜色变化

然后在drawable下 创建 selector_bottom_navigantion

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:color="@color/colorLightGreen"  />
    <item  android:state_checked="false" android:color="@color/colorTextGrey" />
</selector>

然后在res 创建 menu文件夹,并在下面创建 menu_bottom_navigation

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/item_1"
        android:icon="@mipmap/img_1"
        android:title="@string/menu_bottom_navigation1"
        />
    <item
        android:id="@+id/item_2"
        android:icon="@mipmap/img_2"
        android:title="@string/menu_bottom_navigation2"
      />

    <item
        android:id="@+id/item_3"
        android:icon="@mipmap/img_3"
        android:title="@string/menu_bottom_navigation3"
        />
</menu>

最后Activity代码

public class BottomNavigationActivity2 extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener{@BindView(R.id.fl_fragment)FrameLayout flFragment;
    @BindView(R.id.bottomNavigationView)BottomNavigationView bottomNavigationView;
    Unbinder unbinder;
    Fragment1 fragment1;
    Fragment2 fragment2;
    Fragment3 fragment3;
    private Fragment fragment_now = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bottom_navigation2);
        unbinder = ButterKnife.bind(this);
        inint();
    }@SuppressLint("NewApi")private void inint() {bottomNavigationView.setOnNavigationItemSelectedListener(this);//设置 NavigationItemSelected 事件监听
        BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);//改变 BottomNavigationView 默认的效果
        //选中第一个item,对应第一个fragment
        bottomNavigationView.setSelectedItemId(R.id.item_1);
    }@Override
    protected void onDestroy() {super.onDestroy();
        unbinder.unbind();
    }//NavigationItemSelected 事件监听
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {changePageFragment(item.getItemId());
        return true;
    }/**
     * 当点击导航栏时改变fragment
     *
     * @param id
     */
    public void changePageFragment(int id) {switch (id) {case R.id.item_1:if (fragment1 == null) { //减少new fragmnet,避免不必要的内存消耗
                    fragment1 = Fragment1.newInstance();
                }switchFragment(fragment_now, fragment1);
                break;
            case R.id.item_2:if (fragment2 == null) {fragment2 = Fragment2.newInstance();
                }switchFragment(fragment_now, fragment2);
                break;
            case R.id.item_3:if (fragment3 == null) {fragment3 = Fragment3.newInstance();
                }switchFragment(fragment_now, fragment3);
                break;
        }}/**
     * 隐藏显示fragment
     *
     * @param from 需要隐藏的fragment
     * @param to   需要显示的fragment
     */
    public void switchFragment(Fragment from, Fragment to) {if (to == null)return;
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (!to.isAdded()) {if (from == null) {transaction.add(R.id.fl_fragment, to).show(to).commit();
            } else {// 隐藏当前的fragment,add下一个fragment到Activity中
                transaction.hide(from).add(R.id.fl_fragment, to).commitAllowingStateLoss();
            }} else {// 隐藏当前的fragment,显示下一个
            transaction.hide(from).show(to).commit();
        }fragment_now = to;
    }
}

switchFragment() 与第一种写法一致; changePageFragment() 与第一种写法区别在于没有changePageSelect(), 因为BottomNavigationView 已经在布局app:itemIconTint 与 app:itemtextColor做了这个事。

最后设置 BottomNavigationView 的 item 选择事件监听调用changePageFragment()

public class BottomNavigationActivity2 extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener
bottomNavigationView.setOnNavigationItemSelectedListener(this); @Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {changePageFragment(item.getItemId());
    return true;
}

如果BottomNavigationView 的 item >3 则会出现 位移效果,而我们不要位移效果怎么办?

BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
public class BottomNavigationViewHelper {@RequiresApi(api = Build.VERSION_CODES.KITKAT)@SuppressLint("RestrictedApi")public static void disableShiftMode(BottomNavigationView navigationView) {BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt(0);
        try {// 利用反射,改变 item 中 mShiftingMode 的值 ,从而改变 BottomNavigationView 默认的效果
            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();
        }}
}

有人会问:这样为什么可以改变默认大小?

在此先简单分析(以后分析BottomNavigationView源码 ):

通过 BottomNavigationView 找到 BottomNavigationMenuView , 在BottomNavigationMenuView 看到

private boolean mShiftingMode = true;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {final int width = MeasureSpec.getSize(widthMeasureSpec);
    final int count = getChildCount();

    final int heightSpec = MeasureSpec.makeMeasureSpec(mItemHeight, MeasureSpec.EXACTLY);

    if (mShiftingMode) {final int inactiveCount = count - 1;
        final int activeMaxAvailable = width - inactiveCount * mInactiveItemMinWidth;
        final int activeWidth = Math.min(activeMaxAvailable, mActiveItemMaxWidth);
        final int inactiveMaxAvailable = (width - activeWidth) / inactiveCount;
        final int inactiveWidth = Math.min(inactiveMaxAvailable, mInactiveItemMaxWidth);
        int extra = width - activeWidth - inactiveWidth * inactiveCount;
        for (int i = 0; i < count; i++) {mTempChildWidths[i] = (i == mSelectedItemPosition) ? activeWidth : inactiveWidth;
            if (extra > 0) {mTempChildWidths[i]++;
                extra--;
            }}} else {final int maxAvailable = width / (count == 0 ? 1 : count);
        final int childWidth = Math.min(maxAvailable, mActiveItemMaxWidth);
        int extra = width - childWidth * count;
        for (int i = 0; i < count; i++) {mTempChildWidths[i] = childWidth;
            if (extra > 0) {mTempChildWidths[i]++;
                extra--;
            }}}int totalWidth = 0;
    for (int i = 0; i < count; i++) {final View child = getChildAt(i);
        if (child.getVisibility() == GONE) {continue;
        }child.measure(MeasureSpec.makeMeasureSpec(mTempChildWidths[i], MeasureSpec.EXACTLY),
                heightSpec);
        ViewGroup.LayoutParams params = child.getLayoutParams();
        params.width = child.getMeasuredWidth();
        totalWidth += child.getMeasuredWidth();
    }setMeasuredDimension(View.resolveSizeAndState(totalWidth,
                    MeasureSpec.makeMeasureSpec(totalWidth, MeasureSpec.EXACTLY), 0),
            View.resolveSizeAndState(mItemHeight, heightSpec, 0));
}

BottomNavigationMenuView 通过 mShiftingMode 为标识 ,  measure 它的各子view 的宽高,而宽在不断变化,从而产生位移变化。

有人会问:为什么是item >3 则会出现 位移效果?

因为在BottomNavigationMenuView 的 buildMenuView()中的mShiftingMode = mMenu.size() > 3

public void buildMenuView() {removeAllViews();
    if (mButtons != null) {for (BottomNavigationItemView item : mButtons) {mItemPool.release(item);
        }}if (mMenu.size() == 0) {mSelectedItemId = 0;
        mSelectedItemPosition = 0;
        mButtons = null;
        return;
    }mButtons = new BottomNavigationItemView[mMenu.size()];
    mShiftingMode = mMenu.size() > 3;
    for (int i = 0; i < mMenu.size(); i++) {mPresenter.setUpdateSuspended(true);
        mMenu.getItem(i).setCheckable(true);
        mPresenter.setUpdateSuspended(false);
        BottomNavigationItemView child = getNewItem();
        mButtons[i] = child;
        child.setIconTintList(mItemIconTint);
        child.setTextColor(mItemTextColor);
        child.setItemBackground(mItemBackgroundRes);
        child.setShiftingMode(mShiftingMode);
        child.initialize((MenuItemImpl) mMenu.getItem(i), 0);
        child.setItemPosition(i);
        child.setOnClickListener(mOnClickListener);
        addView(child);
    }mSelectedItemPosition = Math.min(mMenu.size() - 1, mSelectedItemPosition);
    mMenu.getItem(mSelectedItemPosition).setChecked(true);
}

如果你想有滑动切换效果,可以 添加 ViewPager

build.gradle 添加

implementation 'com.android.support:support-v4:27.0.1'

布局修改为

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout 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"
   >
    <!--<FrameLayout-->
        <!--android:id="@+id/fl_fragment"-->
        <!--android:layout_width="match_parent"-->
        <!--android:layout_height="match_parent"-->
        <!--android:layout_above="@+id/bottomNavigationView"-->
        <!--/>-->
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/bottomNavigationView" />
    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        app:itemIconTint="@drawable/selector_bottom_navigation"
        app:itemTextColor="@drawable/selector_bottom_navigation"
        app:menu="@menu/menu_bottom_navigation"
        />
</android.support.percent.PercentRelativeLayout>

Activity代码修改为

public class BottomNavigationActivity2 extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener,ViewPager.OnPageChangeListener,ViewPager.OnTouchListener{    @BindView(R.id.bottomNavigationView)BottomNavigationView bottomNavigationView;
    @BindView(R.id.viewpager)ViewPager viewPager;
    Unbinder unbinder;
    Fragment1 fragment1;
    Fragment2 fragment2;
    Fragment3 fragment3;
    BottomnavigationViewPagerAdapter pagerAdapter;
    List<Fragment> fragments;
    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bottom_navigation2);
        unbinder = ButterKnife.bind(this);
        inint();
    }@SuppressLint("NewApi")private void inint() {fragments = new ArrayList<>();
        fragment1 = Fragment1.newInstance();
        fragment2 = Fragment2.newInstance();
        fragment3 = Fragment3.newInstance();
        if(!fragments.contains(fragment1)){fragments.add(fragment1);
        }if(!fragments.contains(fragment2)){fragments.add(fragment2);
        }if(!fragments.contains(fragment3)){fragments.add(fragment3);
        }bottomNavigationView.setOnNavigationItemSelectedListener(this);//设置 NavigationItemSelected 事件监听
        BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);//改变 BottomNavigationView 默认的效果
        //选中第一个item,对应第一个fragment
        bottomNavigationView.setSelectedItemId(R.id.item_1);
        pagerAdapter = new BottomnavigationViewPagerAdapter(getSupportFragmentManager(),fragments);
        viewPager.setAdapter(pagerAdapter);
        viewPager.addOnPageChangeListener(this);
        // 如果想禁止滑动,可以把下面的代码取消注释
//        viewPager.setOnTouchListener(this);
    }@Override
    protected void onDestroy() {super.onDestroy();
        unbinder.unbind();
    }//NavigationItemSelected 事件监听
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {        switch (item.getItemId()){case  R.id.item_1:viewPager.setCurrentItem(0);
                break;
            case  R.id.item_2:viewPager.setCurrentItem(1);
                break;
            case  R.id.item_3:viewPager.setCurrentItem(3);
                break;
        }return true;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Override
    public void onPageSelected(int position) {bottomNavigationView.getMenu().getItem(position).setChecked(true);
    }@Override
    public void onPageScrollStateChanged(int state) {}@Override
    public boolean onTouch(View v, MotionEvent event) {return true;
    }
}

最后 注意BottomNavigationView item 范围 1~5 个 (早期版本是 3~5 个)

public final class BottomNavigationMenu extends MenuBuilder {public static final int MAX_ITEM_COUNT = 5;

   ..............@Override
    protected MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {if (size() + 1 > MAX_ITEM_COUNT) {throw new IllegalArgumentException("Maximum number of items supported by BottomNavigationView is " + MAX_ITEM_COUNT
                            + ". Limit can be checked with BottomNavigationView#getMaxItemCount()");
        }stopDispatchingItemsChanged();
        final MenuItem item = super.addInternal(group, id, categoryOrder, title);
        if (item instanceof MenuItemImpl) {((MenuItemImpl) item).setExclusiveCheckable(true);
        }startDispatchingItemsChanged();
        return item;
    }
}

到此底部导航栏 BottomNavigationView 的用法到此就介绍完毕了!

最后效果

代码地址:https://github.com/ccWenTian/notes,   如果觉得还行,请点个赞。

Android底部导航栏最常用的两种写法相关推荐

  1. 转载:Android底部导航栏,三种风格和实现

    原文出处 标题:Android底部导航栏,三种风格和实现 作者:阿飞__ 原文链接:Android底部导航栏,三种风格和实现_阿飞__的博客-CSDN博客_android导航栏 一.效果图展示 如果动 ...

  2. Android底部导航栏的三种风格实现

    一.效果图展示 如果动图没有动的话,也可以看下面这个静态图 以下挨个分析每个的实现,这里只做简单的效果展示,大家可以基于目前代码做二次开发. 二.BottomNavigationView 这是 Goo ...

  3. Android 底部导航栏-极致简单版

    底部导航栏是常用的一个工具,大多数的APP都带有底部导航栏,底部导航栏可以方便用户一只手操作,切占用内存比常规的Activity少,底部导航栏使用Fragment+RadioGroup方法来实现,示意 ...

  4. Android底部导航栏切换页面填坑

    ** Android底部导航栏切换页面填坑 ** 这个效果的实现关键点就是给选项赋予两种状态,focused和normal,在主程序中用监听判断是否被选中,就给被选中的选项设focused为true, ...

  5. Android底部导航栏+消息提醒

    Android底部导航栏+消息提醒 最近想在网上找一些Android底部导航栏切换并能提供消息提醒的案例,虽然有很多案例但都不是我想要的.我就开始自己瞎研究了,废话不多说了,直接上代码. 1.先创建一 ...

  6. android 固定底部导航,如何设置android底部导航栏位置固定在android

    请帮我设置底部导航栏位置固定在底部, ,因为我在输入editText字段时遇到问题,底部导航栏向上移动并覆盖其他领域如何设置android底部导航栏位置固定在android 代码: xmlns:and ...

  7. android fragment 底部菜单栏,一句话搞定Android底部导航栏,一键绑定Fragment、ViewPager...

    现在大多数App都会用到底部导航栏,比如常见的聊天工具QQ.微信.购物App等等,有了底部导航栏,用户可以随时切换界面,查看不同的内容.它的实现方式也很多,以前大多使用TabHost来实现,但是现在我 ...

  8. Android 底部导航栏+页面切换

    lzyprime 博客 (github) 更新时间: 2020.12.21 创建时间:2020.11.25 qq及邮箱:2383518170 kotlin & android 笔记 更新 20 ...

  9. Android 底部导航栏添加消息数目提示

    效果图 写一篇短小精悍,好用的知识积累吧.开发中时常会出现信息提醒,新内容提示等等一堆问题.其实就是在各种控件或者是item上面加"小圆点".网上一搜一大堆...但是感觉说的好多. ...

最新文章

  1. 百度地图轨迹回放,自定义路书,边走边画线
  2. docker安装nginx实例
  3. 并发量与RAID_RAID 技术全解 – RAID0、RAID1、RAID5、RAID10-宿主机磁盘阵列-香港母机...
  4. sql datetime转字符串_datetime的用法,时间戳转换
  5. 您需要了解的WordPress漏洞以及如何修复它们
  6. 3月13 论文学习步骤:google的cartographer的论文《Real-Time Loop Closure in 2D LIDAR SLAM》
  7. 罗翔老师转谈记录,不同认知出发//心之所向,素履以往,生如逆旅,一苇以航。
  8. Proteus仿真——常用元件
  9. 谷歌搜索通告:疫情期间不要关站会影响网站排名
  10. iMX6UL lvgl开发备忘
  11. 腾讯云服务器竞价实例是什么意思?
  12. 密码学应用的四个进化阶段 | 博文精选
  13. Python实现数据保存为PSV文件(先创建CSV,转换成PSV)
  14. Doxygen使用教程
  15. 基于QT的电子相册设计与实现
  16. 电子商务网站开发流程[转]
  17. 出租车计价 (15分)
  18. windows笔记本重置网络
  19. ucenter api php,UCenter API使用入门
  20. 国产技术迎来突破,光量子芯片横空出世,中文编程也有好消息

热门文章

  1. linux dig命令_如何在Linux上使用dig命令
  2. 计算机内图标wps云盘怎么去掉,Win10资源管理器WPS云文档图标如何清除
  3. jrtplib for android,Jthread1.3.1 Jrtplib3.9.1跨平台交叉编译之Android(二)
  4. 推荐一个查询基金宏观数据
  5. Unity插件_绘制草地的插件和大地图草刷
  6. Laravel框架中,Post请求返回419或者500,因为默认有csrf验证
  7. @html.textbox的使用方法,ASP.NET中 TextBox 文本输入框控件的使用方法
  8. zzulioj1007
  9. brat事件标注平台使用教程
  10. 基于ArcGIS的栅格数据重分类