Android底部导航——BottomNavigationView+ViewPager+Fragment

简介: Android底部导航——BottomNavigationView+ViewPager+Fragment

前言:

Android端采用底部导航栏的APP非常多,比如微信、微博、支付宝…等等,这也不能说是盲目学习iOS,毕竟好东西大家都可以用,各家操作系统也都在博采众长,互相学习。Android端的底部导航栏有着一套规范,详情


这篇文章为大家带来

1.官方BottomNavigationView的使用方法

2.结合ViewPager、Fragment实现一个流行UI布局!

3.并用反射解决ViewPager与BottomNavigationView侧滑联动时的一个小问题。


最终实现效果:


image.png

image.png在谷歌官方发布BottomNavigationView控件之前我们可以自己组合控件实现,比如LinearLayout + TextView(使用android:drawableTop属性+selector状态切换)、RadioGroup + RadioButton等等组合控件的方法自定义实现复杂效果。除了第三方外,现在我们多了一个选择。


开始

1.新建project然后导入以下support:design library,BottomNavigationView就在这个design库中。顺带导入这个V4包,因为待会要使用到ViewPager(这里其实不用记这么麻烦的库跟版本怎么写,直接在AS 的design面板把控件拖进来就会自动导入了。)


compile'com.android.support:design:25.0.1'

compile'com.android.support:support-v4:25.0.1'

1

2

2.在res下新建menu文件夹,新建一个menu菜单,多少个可以根据自己的需要:


<menu xmlns:android="http://schemas.android.com/apk/res/android">

   <item android:id="@+id/item_news" android:icon="@mipmap/ic_news_gray" android:title="新闻" />

   <item android:id="@+id/item_lib" android:icon="@mipmap/ic_library_gray" android:title="图书" />

   <item android:id="@+id/item_find" android:icon="@mipmap/ic_discovery_gray" android:title="发现" />

   <item android:id="@+id/item_more" android:icon="@mipmap/ic_more_gray" android:title="更多" />

</menu>

1

2

3

4

5

6

3.接着是布局文件主要代码如下(最下面的View效果是加一个阴影):

 <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_navigation_selector"
        app:itemTextColor="@drawable/bottom_navigation_selector"
        app:menu="@menu/menu_bottom_navigation" />
    <View 
        android:layout_width="match_parent" 
        android:layout_height="5dp" 
        android:layout_above="@id/bottom_navigation" 
        android:background="@drawable/bottom_shadow" />

app:itemIconTint="@drawable/bottom_navigation_selector" 为icon着色,写个selector即可。

app:itemTextColor="@drawable/bottom_navigation_selector"该属性为文字着色,同样写个selector实现点击颜色切换的效果。


4.写完布局写代码,完整activity文件如下:

实例化控件后为NavigationView添加监听事件即可,代码如下:

package com.fedming.bottomnavigationdemo;
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;
import com.example.think.shaiwangbaodian.R;
import com.example.think.shaiwangbaodian.base.BaseFragment;
/**
 * Created by 程大龙 on 2018/10/15.
 * HomeActivity 主界面
 */
public class HomeActivity extends AppCompatActivity {
    private ViewPager viewPager;
    private MenuItem menuItem;
    private BottomNavigationView bottomNavigationView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        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) { }
                });
        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+ViewPager+Fragment可以实现流行的布局框架,可以像微信那样左右滑动,也可以像支付宝那样点击切换。image.png

不知道细心的朋友是否可能发现了,上面的代码为什么用了反射呢?

原因就是官方的BottomNavigationView默认有个放大的ShiftingMode效果,但是尚未支持代码层级的切换。在3个menu item及以下时默认

image.png

关闭,而到了4个及以上时就懵逼了,因为我们是要做ViewPager的侧滑没办法了,查了一圈资料,发现官方这个控件还不支持代码层级的切换选项(如果你发现了,请告诉我)。迫不得已,只能看源码,开启反射模式了image.png

import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import java.lang.reflect.Field;
public class BottomNavigationViewHelper {
    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();
        }
    }
}

我们通过反射拿到了BottomNavigationMenuView,至于为什么是BottomNavigationView 的第一个子View这就要看源码了,AS中直接可以点进去看。然后我们知道了这个效果是由mShiftingMode来决定的,那么上面的代码就好理解了。


在实例化BottomNavigationView后调用一次这行代码即可:


BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

1

如果不需要配置侧滑切换的话,直接默认效果就好,不要去反射修改了。禁止滑动时,为ViewPager添加setOnTouchListener接口,在onTouch下直接消费掉点击事件。添加下面这段代码:


//禁止ViewPager滑动

//禁止ViewPager滑动

viewPager.setOnTouchListener(new View.OnTouchListener(){

   @Override

     public boolean onTouch(View v,MotionEvent event){

       return true;

       }

});

1

2

3

4

5

6

7

8

最后来看下效果:


image.png

在文章的最后附上源码大家有什么意见或者补充的可以指出。


目录
相关文章
|
4月前
|
XML Java Android开发
Android Studio App开发之实现底部标签栏BottomNavigationView和自定义标签按钮实战(附源码 超详细必看)
Android Studio App开发之实现底部标签栏BottomNavigationView和自定义标签按钮实战(附源码 超详细必看)
71 0
|
8月前
|
Android开发
Android 使用BottomNavigationView和Novigation组件实现底部导航功能
Android 使用BottomNavigationView和Novigation组件实现底部导航功能
150 0
|
8月前
|
Android开发
Android 中使用RadioGroup+Fragment实现底部导航栏的功能
Android 中使用RadioGroup+Fragment实现底部导航栏的功能
75 0
|
11月前
|
XML Android开发 数据格式
Android 底部导航栏(四、ViewPager+RadioGroup+Fragment)简单易懂
底部导航栏在Android应用中随处可见,今天使用ViewPager+RadioGroup+Fragment这三个控件来实现此功能。前面写了有三种实现方式,有兴趣可以去看看
|
11月前
|
XML Android开发 数据格式
Android 底部导航栏(三、ViewPager+TabLayout+Fragment)简单易懂
底部导航栏在Android应用中随处可见,今天使用ViewPager+TabLayout+Fragment这三个控件来实现此功能。 前面使用了另外两个方法来实现导航栏,不过我还是更喜欢Viewpager,代码也少,毕竟前两个不能左右滑动。
|
11月前
|
XML Android开发 数据格式
Android 底部导航栏(二、自定义View+Fragment)
上一片文章用的是BottomNavigationView+Menu+Fragment,但是可能有时候需求不一样,menu的样式不太够,所以需要自定义View来实现。
|
11月前
|
XML Android开发 数据格式
Android 底部导航栏(一、BottomNavigationView+Menu+Fragment)
现在常用的App主页都会有一个底部导航栏,根据需求也使用过好几种方法进行实现,于是想着还是总结一下,今天还写一个简单的BottomNavigationView方法来实现这个功能
|
XML API Android开发
Android笔记:底部导航栏的动态替换方案
Android笔记:底部导航栏的动态替换方案
107 0
|
Android开发 容器 数据格式
Android实践(一)| Fragment实现底部导航栏(解决重叠问题)
最初学习Android的时候,是边学习边做着一个小项目的,因为项目需求,需要实现一个底部导航栏的功能,由于基础知识受限,百度了很多博客,大致就找到两种实现方案:第一种就是直接用Fragment实现(点击切换),第二种是ViewPager+Fragment实现(除了点击切换,还支持左右滑动切换)。
2251 0