android导航栏相关控件使用学习笔记

顶部导航栏效果图:

这里写图片描述

底部导航栏效果图:

这里写图片描述

关于android导航栏的实现方法有很多,像TabHost+TabWidget,RadioButton+RadioGroup,FragmentTabHost等等。随着androidapi的更新,个人认为,目前实现导航栏最易用且美观的方式是TabLayout和BottomNavigationView,TabLayout实现顶部导航栏,BottomNavigationView实现底部导航栏。这两个控件都是位于android.support.design.widget包中,TabLayout是android5.0(api21)添加的,而BottomNavigationView是android7.1.1(api25)添加的,目前已发布的android官方开发文档中还没有关于BottomNavigationView的介绍,需要去官网文档才能看到。下面就对这些控件实现android导航栏时的使用方法做一些记录,方便以后查阅。

首先,添加对design包的依赖,如下所示:

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

实际根据项目不同,后面的版本号可能需要变动。

底部导航栏的使用

直接在布局中添加BottomNavigationView,如下所示:

<android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:menu="@menu/navigation" />

其中,注意android:layout_gravity和app:menu两个属性,不指定layout_gravity属性为bottom导航栏可能会飞到上面。飞到上面不久成了顶部导航栏了么?在逻辑上来讲确实没有问题,但是通过观察可以发现,顶部导航栏和底部导航栏的样式还是有差别的,如果反过来用看着就很别扭。app:menu属性就是为导航栏设置每个item了,看一下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/ic_home_black_24dp"
        android:title="@string/title_home" />

    <item
        android:id="@+id/navigation_dashboard"
        android:icon="@drawable/ic_dashboard_black_24dp"
        android:title="@string/title_dashboard" />

    <item
        android:id="@+id/navigation_notifications"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_notifications" />

</menu>

menu文件很简单,其中为每个item指定的icon和title在底部导航栏显示时就是每一项的图标和文字描述了。现在BottomNavigationView就已经添加好了,下面怎么在代码中使用他呢,也很简单,BottomNavigationView中目前提供了两个接口,如下图所示:

这里写图片描述

和给大部分控件设置点击方法一样,对应的方法就是这两个啦,如下图所示:

这里写图片描述

在代码中通过上述的两个方法给BottomNavigationView设置点击事件,在接口中判断MenuItem的id就可以执行相应的逻辑啦,本例中仅仅是改变了一个TextView中的文字,相关代码如下所示:

private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    mTextMessage.setText(R.string.title_home);
                    return true;
                case R.id.navigation_dashboard:
                    mTextMessage.setText(R.string.title_dashboard);
                    return true;
                case R.id.navigation_notifications:
                    mTextMessage.setText(R.string.title_notifications);
                    return true;
            }
            return false;
        }

    };
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

上面两片代码在程序结构上并不位于同一个变量作用域中,所以分成了两个代码片。其实细心的朋友可以发现mOnNavigationItemSelectedListener接口是类成员变量,而navigation呢就是BottomNavigationView啦。在接口中可以看到,通过判断点击的item的id给TextView设置了不同的文字。

下面问题来了,介绍了OnNavigationItemSelectedListener接口,那么OnNavigationItemReselectedListener接口又是干什么的呢?当时也是看了半天文档没想明白,不过没关系,做个实验就知道了。我给navigation又添加了OnNavigationItemReselectedListener接口,代码如下所示:

private BottomNavigationView.OnNavigationItemReselectedListener itemReselectedListener=new BottomNavigationView.OnNavigationItemReselectedListener() {
        @Override
        public void onNavigationItemReselected(@NonNull MenuItem item) {
            String msg=null;
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    msg="home";
                    break;
                case R.id.navigation_dashboard:
                    msg="dashboard";
                    break;
                case R.id.navigation_notifications:
                    msg="notifications";
                    break;
            }
            Toast.makeText(MainActivity.this, "item "+msg+" is reselected", Toast.LENGTH_SHORT).show();
        }
    };
navigation.setOnNavigationItemReselectedListener(itemReselectedListener);

下面来看看实验效果吧:

这里写图片描述

很明显吧,再次点击已选中的item就会触发setOnNavigationItemReselectedListener,那么这玩意有什么用呢?当时马上想到了新浪微博,相信各位都有一个已经习以为常的操作,就是点击home button刷新微博。剩下的不用多说了,嘿嘿。。。

在生活中更常见到的是点击底部导航栏的图标,上面的界面随之滑动切换。这里并没有实现这样的效果,但是思路也并不难,在处理点击事件的接口中设置viewPager的currentItemId就好了。但是还要注意一个地方,就是在用户手动滑动viewPager时底部导航栏的选中图标也该随之切换。是不是感觉有点麻烦,嗯。在顶部导航栏控件TabLayout中有这样一个方法,如下所示:

这里写图片描述

这个方法就是专门用来设置TabLayout与ViewPager协同工作的。在用户手动滑动ViewPager时TabLayout中的选中项也会随之切换,甚至还有动画。讲道理BottomNavigationView中也应该提供这样的方法,因为这些导航控件大多数时候都是要和ViewPager一起工作的,然而目前BottomNavigatoinView中并没有这样的方法,不过我相信未来会有的。

底部导航栏的基本使用大概就这些,下面开始说顶部导航栏。

顶部导航栏的使用

在顶部导航栏的例子中,是让TabLayout和ViewPager协同工作的。首先在布局文件中添加这两个控件就非常简单啦,代码如下所示:

<android.support.design.widget.TabLayout
        android:id="@+id/tab_top"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></android.support.design.widget.TabLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v4.view.ViewPager>

官方文档中还提供了另外一种写法,如下所示:

<android.support.v4.view.ViewPager
     android:layout_width="match_parent"
     android:layout_height="match_parent">

     <android.support.design.widget.TabLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="top" />

 </android.support.v4.view.ViewPager>

下面开始说在代码中的使用,关于ViewPager及其Fragment适配器和Fragment的创建这里就不说了,我们将重点放在TabLayout的使用上。TabLayout的使用也很简单,如下所示,注意看注释:

//获取TabLayout实例
tabTop=(TabLayout)findViewById(R.id.tab_top);

//设置TabLayout中tabs的行为模式
tabTop.setTabMode(TabLayout.MODE_FIXED);

//设置协同工作的ViewPager
tabTop.setupWithViewPager(viewPager);

以上并称TabLayout使用三部曲,是不是很简单。那么TabLayout的标题是从哪来的呢?这一点可以从官方文档中得到答案,TabLayout会自动从ViewPager的适配器获取标题,在FragmentPagerAdapter中有这样一个方法,如下图所示:

这里写图片描述

实际上这个方法继承自PagerAdapter,TabLayout正是通过这个方法来获取每一个tab的标题,在本例中,FragmentPagerAdapter中的getPageTitle方法是这样写的:

@Override
    public CharSequence getPageTitle(int position) {
        return "title"+(position+1);
    }

所以就有了示例顶部导航栏中每一项的标题。还有一个问题,那就是TabLayout中的tabs的行为模式是个什么意思?不急给出答案,做个实验,实验做完自然就有答案了。setTabMode方法的参数可选值只有两个,如下所示:

这里写图片描述

也就是MODE_FIXED和MODE_SCROLLABLE,我们将行为模式设置为MODE_SCROLLABLE,ViewPager适配器的getCount方法返回值改为8,也就是TabLayout中有8个Tab,然后运行一下。其实从参数名字上也能猜出一二,还是看实验结果吧,这样更直观更形象,实验结果请看下图:

这里写图片描述

怎么样,很直观很形象吧。但是改了之后这些tab变小了啊,没关系,在布局中可以给TabLayout指定app:tabMinWidth属性来规定tab的最小宽度,这里没有指定tab的最小宽度,使用的是默认最小宽度。还有很多属性可以去看官方文档。总之,如果需要很多tab的话就使用MODE_SCROLLABLE并为tab设置合适的宽度,使用MODE_FIXED模式的话不管有多少tab,这些tab都会蜷缩在一屏内并平分屏幕的宽度,这样如果tab很多就会很挤而且使用也不方便,一般来说tab在5个以内可以使用MODE_FIXED,再多就改用MODE_SCROLLABLE。

OK,TabLayout的基本使用方法大概也就这些。

如果将顶部导航栏和底部导航栏结合到一起,且都使用ViewPager的话,需要考虑的一个严重问题就是滑动冲突。

好了,今天就记录到这里。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值