美文网首页
Android 导航

Android 导航

作者: kaiviak | 来源:发表于2015-09-24 20:48 被阅读338次

    一.导航抽屉Navigation Drawer

    想必用过Android的人都熟悉导航抽屉,这算是一个比较经典的导航方式了,个人也非常喜欢这种导航方式。下面介绍这种导航方式的开发方法。


    导航抽屉导航抽屉

    创建一个抽屉布局DrawerLayout


    <android.support.v4.widget.DrawerLayout    
    xmlns:android="http://schemas.android.com/apk/res/android"    
    android:id="@+id/drawer_layout"    
    android:layout_width="match_parent"    
    android:layout_height="match_parent">    
    
    <!-- The main content view -->    
    <FrameLayout        
    android:id="@+id/content_frame"        
    android:layout_width="match_parent"        
    android:layout_height="match_parent" />    
    
    <!-- The navigation drawer -->    
    <ListView android:id="@+id/left_drawer"        
    android:layout_width="240dp"        
    android:layout_height="match_parent"        
    android:layout_gravity="start"        
    android:choiceMode="singleChoice"        
    android:divider="@android:color/transparent"        
    android:dividerHeight="0dp"        
    android:background="#111"/>
    </android.support.v4.widget.DrawerLayout>
    
    

    这里有一些需要注意的地方:

    • 要添加一个导航抽屉,首先应该用support库提供的DrawerLayout布局来作为你的主布局的根布局,在根布局中,应该包含显示主要内容的布局和drawer的布局。
    • 第一个布局必须是你的主要内容的布局(因为XML文件是根据z轴的顺序来显示,而抽屉要在主要内容的上面)
    • 主要内容布局需要将长宽都设置为铺满父容器,因为当抽屉隐藏时,它是主要显示的容器。
    • 抽屉view(the ListView)必须指定horizontal_gravity,通过设置android:layout_gravity。为了支持从右向左的语言,最好指定值为"start"而不是left
    • 为了让用户能看见主页面的一部分,抽屉view的宽度应该用dp来设置,并且尽量不要超过320dp。

    初始化Drawer List


    在你的activity中,第一件事就应该去初始化导航抽屉列表的每一项。不管你怎么去组织你的app内容,一个导航抽屉通常都是由一个列表组成的,所以我们应该从一个适配器Adapter开始入手(比如ArrayAdapter或者SimpleCursorAdapter)。
    例如,这段代码演示了如何通过一个string array来初始化你的列表。

    public class MainActivity extends Activity {    
      private String[] mPlanetTitles;   
      private DrawerLayout mDrawerLayout;  
      private ListView mDrawerList;    
      ...    
      @Override    
      public void onCreate(Bundle savedInstanceState) {        
        super.onCreate(savedInstanceState);        
        setContentView(R.layout.activity_main);        
        mPlanetTitles =  getResources().getStringArray(R.array.planets_array);        
        mDrawerLayout = (DrawerLayout)  findViewById(R.id.drawer_layout);        
        mDrawerList = (ListView) findViewById(R.id.left_drawer);    //  为list设置一个适配器    
        mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mPlanetTitles));   // 设置一个监听器
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());        ...    
      }
    }
    
    

    通过setOnItemClickListener()接收导航抽屉的列表点击事件。接下来展示如何实现这个接口和当选择一项时改变主页面。

    处理导航点击事件


    当用户点击抽屉的列表时,系统会在你通过setOnItemClickListener()设置的监听器OnItemClickListener()上调用onItemClick()
    你的onItemClick()的功能取决于你的app的功能。在下面的例子中,选择每一项都会动态的插入一个不同的Fragment到主页面(FrameLayout)中。

    private class DrawerItemClickListener implements ListView.OnItemClickListener {    
      @Override    
      public void onItemClick(AdapterView parent, View view, int position, long id) {
            selectItem(position);
        }
    }
    /** 替换主页面中的fragment */
    private void selectItem(int position) {
        // Create a new fragment and specify the planet to show based on position
        Fragment fragment = new PlanetFragment();
        Bundle args = new Bundle();
        args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
        fragment.setArguments(args);
        // 通过替换已存在的fragment来插入
        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction()// 开始事务
                       .replace(R.id.content_frame, fragment)// 替换
                       .commit();// 提交
        // 高亮选中项,设置标题,关闭抽屉
        mDrawerList.setItemChecked(position, true);
        setTitle(mPlanetTitles[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
    }
    @Overridepublic void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }
    
    

    监听打开和关闭抽屉事件


    要监听打开和关闭事件,首先应该在你的DrawerLayout上设置监听器setDrawerListener(),还要实现DrawerLayout.DrawerListener,这个接口提供回调函数,比如 onDrawerOpened()onDrawerClosed()

    回调函数解析

    然而,与其实现这个接口,如果你的activity包含了actionbar,你可以替换为使用ActionBarDrawerToggle类,这个类实现了DrawerLayout.DrawerListener这个接口,你仍可以去重载那些回调函数,但是使用ActionBarDrawerToggle可以促进action bar的图标和导航抽屉的正确的交互。

    当抽屉可见时,你应该改变action bar的内容,像是改变标题,移除action items来适应主页面的内容,下面的代码通过一个ActionBarDrawerToggle类展示了如何去重载DrawerLayout.DrawerListener回调函数。

    public class MainActivity extends Activity {
        private DrawerLayout mDrawerLayout;
        private ActionBarDrawerToggle mDrawerToggle;
        private CharSequence mDrawerTitle;
        private CharSequence mTitle;
        ...
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ...
            mTitle = mDrawerTitle = getTitle();
            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
            mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                    R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
                /** 当抽屉完全关闭时调用*/
                public void onDrawerClosed(View view) {                super.onDrawerClosed(view);
                    getActionBar().setTitle(mTitle);
                    invalidateOptionsMenu(); // 创建调用onPrepareOptionsMenu()
                }
                /** 当抽屉完全打开时调用 */
                public void onDrawerOpened(View drawerView) {
                    super.onDrawerOpened(drawerView);
                    getActionBar().setTitle(mDrawerTitle);
                    invalidateOptionsMenu(); // 创建调用onPrepareOptionsMenu()
                }
            };
            // 设置toggle为抽屉监听器
            mDrawerLayout.setDrawerListener(mDrawerToggle);
        }
        /* 当调用invalidateOptionsMenu()时调用 */
        @Override
        public boolean onPrepareOptionsMenu(Menu menu) {
            // 如果导航抽屉式打开的,根据内容隐藏action items
            boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
            menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
            return super.onPrepareOptionsMenu(menu);
        }
    }
    
    

    下个部分介绍ActionBarDrawerToggle的构造函数参数和与action icon交互的其他要求。

    通过App Icon来打开和关闭抽屉


    用户能够通过右滑来打开抽屉,但是如果你使用action bar,那么你也应该允许用户通过点击App Icon来打开和关闭抽屉。同时也应该通过一个特殊的icon来显示隐藏抽屉的存在。你能够通过之前介绍的ActionBarDrawerToggle来实现。

    为了使ActionBarDrawerToggle工作,在这里创建一个例子和他的构造函数,他需要以下的元素:

    • 托管抽屉的Activity
    • DrawerLayout
    • 一个图片资源用作抽屉开关的指示器
      图片资源
    • 一个描述抽屉打开的string(为了用户友好)
    • 一个描述抽屉关闭的string(为了用户友好)

    不管你是否创建了ActionBarDrawerToggle的子类作为你抽屉监听器,你需要在你的activity的整个生命周期中能够调用ActionBarDrawerToggle

    public class MainActivity extends Activity {
        private DrawerLayout mDrawerLayout;
        private ActionBarDrawerToggle mDrawerToggle;
        ...
        public void onCreate(Bundle savedInstanceState) {
            ...
            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
            mDrawerToggle = new ActionBarDrawerToggle(                this,                  /* host Activity */
                    mDrawerLayout,         /* DrawerLayout object */
                    R.drawable.ic_drawer,  /* nav drawer icon to replace 'Up' caret */
                    R.string.drawer_open,  /* "open drawer" description */
                    R.string.drawer_close  /* "close drawer" description */
                    ) {
    
                /** Called when a drawer has settled in a completely closed state. */
                public void onDrawerClosed(View view) {
                    super.onDrawerClosed(view);
                    getActionBar().setTitle(mTitle);
                }
                /** Called when a drawer has settled in a completely open state. */
                public void onDrawerOpened(View drawerView) {
                    super.onDrawerOpened(drawerView);
                    getActionBar().setTitle(mDrawerTitle);
                }        };
    
            // Set the drawer toggle as the DrawerListener        mDrawerLayout.setDrawerListener(mDrawerToggle);
    
            getActionBar().setDisplayHomeAsUpEnabled(true);
            getActionBar().setHomeButtonEnabled(true);
        }
        @Override
        protected void onPostCreate(Bundle savedInstanceState) {
            super.onPostCreate(savedInstanceState);
            // Sync the toggle state after onRestoreInstanceState has occurred.
            mDrawerToggle.syncState();
        }    @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            mDrawerToggle.onConfigurationChanged(newConfig);
        }
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Pass the event to ActionBarDrawerToggle, if it returns
            // true, then it has handled the app icon touch event
            if (mDrawerToggle.onOptionsItemSelected(item)) {
              return true;
            }
            // Handle your other action bar items...
            return super.onOptionsItemSelected(item);
        }
        ...
    }
    
    

    最后给一个例子的完整版
    导航抽屉完整版

    未完待续……

    相关文章

      网友评论

          本文标题:Android 导航

          本文链接:https://www.haomeiwen.com/subject/zjaicttx.html