Android底部导航栏最常用的两种写法
先来看看底部导航栏的效果
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底部导航栏最常用的两种写法相关推荐
- 转载:Android底部导航栏,三种风格和实现
原文出处 标题:Android底部导航栏,三种风格和实现 作者:阿飞__ 原文链接:Android底部导航栏,三种风格和实现_阿飞__的博客-CSDN博客_android导航栏 一.效果图展示 如果动 ...
- Android底部导航栏的三种风格实现
一.效果图展示 如果动图没有动的话,也可以看下面这个静态图 以下挨个分析每个的实现,这里只做简单的效果展示,大家可以基于目前代码做二次开发. 二.BottomNavigationView 这是 Goo ...
- Android 底部导航栏-极致简单版
底部导航栏是常用的一个工具,大多数的APP都带有底部导航栏,底部导航栏可以方便用户一只手操作,切占用内存比常规的Activity少,底部导航栏使用Fragment+RadioGroup方法来实现,示意 ...
- Android底部导航栏切换页面填坑
** Android底部导航栏切换页面填坑 ** 这个效果的实现关键点就是给选项赋予两种状态,focused和normal,在主程序中用监听判断是否被选中,就给被选中的选项设focused为true, ...
- Android底部导航栏+消息提醒
Android底部导航栏+消息提醒 最近想在网上找一些Android底部导航栏切换并能提供消息提醒的案例,虽然有很多案例但都不是我想要的.我就开始自己瞎研究了,废话不多说了,直接上代码. 1.先创建一 ...
- android 固定底部导航,如何设置android底部导航栏位置固定在android
请帮我设置底部导航栏位置固定在底部, ,因为我在输入editText字段时遇到问题,底部导航栏向上移动并覆盖其他领域如何设置android底部导航栏位置固定在android 代码: xmlns:and ...
- android fragment 底部菜单栏,一句话搞定Android底部导航栏,一键绑定Fragment、ViewPager...
现在大多数App都会用到底部导航栏,比如常见的聊天工具QQ.微信.购物App等等,有了底部导航栏,用户可以随时切换界面,查看不同的内容.它的实现方式也很多,以前大多使用TabHost来实现,但是现在我 ...
- Android 底部导航栏+页面切换
lzyprime 博客 (github) 更新时间: 2020.12.21 创建时间:2020.11.25 qq及邮箱:2383518170 kotlin & android 笔记 更新 20 ...
- Android 底部导航栏添加消息数目提示
效果图 写一篇短小精悍,好用的知识积累吧.开发中时常会出现信息提醒,新内容提示等等一堆问题.其实就是在各种控件或者是item上面加"小圆点".网上一搜一大堆...但是感觉说的好多. ...
最新文章
- 百度地图轨迹回放,自定义路书,边走边画线
- docker安装nginx实例
- 并发量与RAID_RAID 技术全解 – RAID0、RAID1、RAID5、RAID10-宿主机磁盘阵列-香港母机...
- sql datetime转字符串_datetime的用法,时间戳转换
- 您需要了解的WordPress漏洞以及如何修复它们
- 3月13 论文学习步骤:google的cartographer的论文《Real-Time Loop Closure in 2D LIDAR SLAM》
- 罗翔老师转谈记录,不同认知出发//心之所向,素履以往,生如逆旅,一苇以航。
- Proteus仿真——常用元件
- 谷歌搜索通告:疫情期间不要关站会影响网站排名
- iMX6UL lvgl开发备忘
- 腾讯云服务器竞价实例是什么意思?
- 密码学应用的四个进化阶段 | 博文精选
- Python实现数据保存为PSV文件(先创建CSV,转换成PSV)
- Doxygen使用教程
- 基于QT的电子相册设计与实现
- 电子商务网站开发流程[转]
- 出租车计价 (15分)
- windows笔记本重置网络
- ucenter api php,UCenter API使用入门
- 国产技术迎来突破,光量子芯片横空出世,中文编程也有好消息
热门文章
- linux dig命令_如何在Linux上使用dig命令
- 计算机内图标wps云盘怎么去掉,Win10资源管理器WPS云文档图标如何清除
- jrtplib for android,Jthread1.3.1 Jrtplib3.9.1跨平台交叉编译之Android(二)
- 推荐一个查询基金宏观数据
- Unity插件_绘制草地的插件和大地图草刷
- Laravel框架中,Post请求返回419或者500,因为默认有csrf验证
- @html.textbox的使用方法,ASP.NET中 TextBox 文本输入框控件的使用方法
- zzulioj1007
- brat事件标注平台使用教程
- 基于ArcGIS的栅格数据重分类