您的位置:首页 > 移动开发 > Android开发

Android 原生导航 IV-实现Drawer+ToolBar+Tab

2016-02-02 16:30 651 查看

概述:

要实现这个组合, 先要了解结构层次. 合理的组合应该是Drawer封装ToolBar, 然后ToolBar再封装Tab.

Drawer:

首先是Drawer, Drawer的层次结构比较简单, 可以在layout中直接实现.

为Drawer创建一个layout:

Layout的结构是

<android.support.v4.widget.DrawerLayout …>

     <!--Your contents ToolBar-->

     <android.support.design.widget.NavigationView …/>

 </android.support.v4.widget.DrawerLayout>

其中NavigationView是Material Design中推荐的用法, 它可以在Drawer中显示一个这样的页面:



其中蓝色的头部区域是可选的, 下面的菜单区域是必选的. 它的完整用法是这样:

    <android.support.design.widget.NavigationView

            android:layout_width="wrap_content"

            android:layout_height="match_parent"

            android:layout_gravity="start"

            app:headerLayout="@layout/drawer_header"

            app:menu="@menu/drawer"/>


其中, 有两个属性, 一个是app:headerLayout, 它是可选的, 指定了一个header. App:menu则指定了一个菜单资源, 代表header下面的菜单(可以在运行时更新). 最简单的drawer菜单是一些checkable菜单项:

<group android:checkableBehavior="single">

    <item

        android:id="@+id/navigation_item_1"

        android:checked="true"

        android:icon="@drawable/ic_android"

        android:title="@string/navigation_item_1"/>

    <item

        android:id="@+id/navigation_item_2"

        android:icon="@drawable/ic_android"

        android:title="@string/navigation_item_2"/>

</group>


选中的菜单项将会在drawer中高亮显示, 以确保让用户知道当前选中的是哪个. 还可以在菜单中使用subheader来指定一个独立组的item:

<item

    android:id="@+id/navigation_subheader"

    android:title="@string/navigation_subheader">

    <menu>

        <item

            android:id="@+id/navigation_sub_item_1"

            android:icon="@drawable/ic_android"

            android:title="@string/navigation_sub_item_1"/>

        <item

            android:id="@+id/navigation_sub_item_2"

            android:icon="@drawable/ic_android"

            android:title="@string/navigation_sub_item_2"/>

    </menu>

</item>


现在假设我们已经拥有了一个这样的Drawer的layout, 它来自Android的Sample:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/my_drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>

    <android.support.design.widget.NavigationView android:id="@+id/nav_view"
        android:layout_width="wrap_content" android:layout_height="match_parent"
        android:layout_gravity="start" android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main" app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>

这里的NavigationVIew也可以使用一个LIstView来代替, 以显示一个简单的菜单, 它的headerLayout和menu的实现稍后再研究, 我们先拿它作为一个整体来看待. 在主layout中有了这些之后我们就拥有了一个Drawer的基本框架, 它在隐藏和显示的时候分别长这样:





而在MainActivity中不需要添加额外的代码, 设置Activity的Content即可.

ToolBar:

现在要为APP添加layout, 只需要修改Drawer layout中的主界面内容为一个appbar就可以了.

为ToolBar添加Layout:

添加一个新建的layout, 很简单, 一个Toolbar + 主界面内容:

<?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:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/my_own_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:elevation="4dp"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

    <include layout="@layout/content_main" />
</LinearLayout>

并将Drawer中的FrameLayout改为引入Toolbar的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout …>

    <include layout="@layout/app_bar_my_own" android:layout_height="match_parent"
        android:layout_width="match_parent"/>

    …
</android.support.v4.widget.DrawerLayout>

这时候就可以看到已经拥有一个ToolBar了, 但是上面是空的, 什么也没有:





关联ToolBar与Drawer:

现在我们需要在Activity中添加一些代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_own);

//设置Toolbar
    Toolbar myToolbar = (Toolbar) findViewById(R.id.my_own_toolbar);
    setSupportActionBar(myToolbar);
    //关联Drawer
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.my_drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, myToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.setDrawerListener(toggle);
    toggle.syncState();
}

上面的代码包括两部分, 一个是设置Toolbar, 还有就是关联Drawer与Toolbar. setSupportActionBar()之后, Activity的名字就会出现在ToolBar上面. 下面关联Drawer这段可以参考Android
原生导航 III-Drawer导航. 它添加了对Drawer显示/隐藏事件的监听. syncState()则是用来在ToolBar上为Drawer添加一个指示器. 这个指示器可以通过drawerArrowStyle属性修改. 完成这些代码之后, 主界面变成了这样, 并且图标会因为Drawer显示而发生变化:



Tab:

Tab的实现比较复杂, 基础逻辑是TabLayout+ ViewPager.

实现Tab的Layout:

因为Tab是AppBar的子view, 所以要修改AppBar的layout文件, 添加TabLayout和ViewPager元素, 修改之后的AppBar的layout文件如下:

<?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:orientation="vertical">

    <android.support.v7.widget.Toolbar

        android:id="@+id/my_own_toolbar"

        android:layout_width="match_parent"

        android:layout_height="?attr/actionBarSize"

        android:background="?attr/colorPrimary"

        android:elevation="4dp"

        android:theme="@style/ThemeOverlay.AppCompat.ActionBar"/>

   <android.support.design.widget.TabLayout

       
android:id="@+id/tab_layout"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

    </android.support.design.widget.TabLayout>

    <android.support.v4.view.ViewPager

       android:id="@+id/pager"

        android:layout_width="match_parent"

        android:layout_height="match_parent">

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


</LinearLayout>
这时界面没有变化, 因为想让它们起作用还得设置一下.

关联TabLayout和VIewPager:

首先是TabLayout, 它比较简单, 添加如下代码到onCreate()中即可:

TabLayout tabLayout= (TabLayout)findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));
这时候就可以看到Tab了.



然后添加ViewPager, ViewPager需要用到FragmentPagerAdapter或者FragmentStatePagerAdapter. 这里使用FragmentPagerAdapter:

public class SectionsPagerAdapter extends FragmentPagerAdapter {
    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment = new DummySectionFragment();
        Bundle args = new Bundle();
        args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getCount() {
        return 3;
    }
}

public static class DummySectionFragment extends Fragment {
    public static final String ARG_SECTION_NUMBER = "section_number";
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.content_main, container, false);
        TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
        dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
        return rootView;
    }
}

这里添加一个Fragment作为页面内容, 显示Tab的号码. 有了FragmentPagerAdapter就可以将它设置给ViewPager了, 在onCreate()中添加如下代码:

mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

tabLayout.setOnTabSelectedListener(this);

现在完整的onCreate()代码是这样的:

SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;

@Override protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_my_own);
    Toolbar myToolbar = (Toolbar) findViewById(R.id.my_own_toolbar);
    setSupportActionBar(myToolbar);

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.my_drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, myToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.setDrawerListener(toggle);
    toggle.syncState();

    TabLayout tabLayout = (TabLayout)findViewById(R.id.tab_layout);
    tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
    tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
    tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));

    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

    tabLayout.setOnTabSelectedListener(this);
}

由于要监听Tab的点击事件, 还要添加implements TabLayout.OnTabSelectedListener到Activity. 并且实现它的回调方法:

@Override
public void onTabSelected(TabLayout.Tab tab) {
    mViewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabUnselected(TabLayout.Tab tab) {

}

@Override
public void onTabReselected(TabLayout.Tab tab) {

}

至此这个Android最常用的导航的基本样子就已经有了, 它是这样的, 并且可以响应点击和滑动改变Tab的事件:





在栗子中, NavigationView和TabLayout这两种很重要的类都来自于android.support.design, 它提供了Material Design的支持, 很好用.

 

参考: https://github.com/googlesamples/android-HorizontalPaging/
https://github.com/googlesamples/android-NavigationDrawer/

http://stackoverflow.com/questions/26540078/use-tab-with-new-toolbar-appcompat-v7-21
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息