Android 導航

一.導航抽屜Navigation Drawer

想必用過Android的人都熟悉導航抽屜,這算是一個比較經典的導航方式了,我的也很是喜歡這種導航方式。下面介紹這種導航方式的開發方法。
導航抽屜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>

這裏有一些須要注意的地方:web

  • 要添加一個導航抽屜,首先應該用support庫提供的DrawerLayout佈局來做爲你的主佈局的根佈局,在根佈局中,應該包含顯示主要內容的佈局和drawer的佈局。app

  • 第一個佈局必須是你的主要內容的佈局(由於XML文件是根據z軸的順序來顯示,而抽屜要在主要內容的上面)ide

  • 主要內容佈局須要將長寬都設置爲鋪滿父容器,由於當抽屜隱藏時,它是主要顯示的容器。函數

  • 抽屜view(the ListView)必須指定horizontal_gravity,經過設置android:layout_gravity。爲了支持從右向左的語言,最好指定值爲"start"而不是left佈局

  • 爲了讓用戶能看見主頁面的一部分,抽屜view的寬度應該用dp來設置,而且儘可能不要超過320dp。this

初始化Drawer List


在你的activity中,第一件事就應該去初始化導航抽屜列表的每一項。無論你怎麼去組織你的app內容,一個導航抽屜一般都是由一個列表組成的,因此咱們應該從一個適配器Adapter開始入手(好比ArrayAdapter或者SimpleCursorAdapter)。
例如,這段代碼演示瞭如何經過一個string array來初始化你的列表。spa

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()接收導航抽屜的列表點擊事件。接下來展現如何實現這個接口和當選擇一項時改變主頁面。code

處理導航點擊事件


當用戶點擊抽屜的列表時,系統會在你經過setOnItemClickListener()設置的監聽器OnItemClickListener()上調用onItemClick()
你的onItemClick()的功能取決於你的app的功能。在下面的例子中,選擇每一項都會動態的插入一個不一樣的Fragment到主頁面(FrameLayout)中。xml

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);
    }
    ...
}

最後給一個例子的完整版
導航抽屜完整版

未完待續……

相關文章
相關標籤/搜索