Navigation Drawer详解-Google推出的用来取代Sliding Menu的控件(一
2019獨角獸企業重金招聘Python工程師標準>>>
相信Sliding Menu很多人都用過,在Android和iOS的app中,越來越多的開發者都會把自己的菜單界面放在一個列表里,然后讓用戶通過向右(或者向左)滑動的操作看到應用所有的功能。Google官方的應用也基本都選擇了這種交互方式,不同的是,Google使用的是Navigation Drawer,而我們大部分用的還是Sliding Menu。
大家對Sliding Menu這個開源項目可能已經很熟悉了,但是Navigation Drawer我們有些童鞋可能了解的還比較少,它是Google I/O 2013剛推出不久的一個在support v4包里面的一個控件,下面我就通過一個demo跟大家介紹一下Navigation Drawer的使用方法。http://safe.ijiami.cn/
這個demo是google官方的,大家可以到這里下載一下:http://developer.android.com/training/implementing-navigation/nav-drawer.html,我下面寫的代碼說明也基本就是翻譯了一下這個教程,英語比較好的童鞋建議還是直接看官方的吧。
創建一個抽屜
導航抽屜是一個位于屏幕左側邊緣用來顯示應用程序導航項的一個面板。導航抽屜在大部分時間是不顯示的,但兩種情況下會進行顯示:一是發生從屏幕左側邊緣向右滑的手勢,二是點擊了工具欄中應用圖標。導航抽屜在SupportLibrary??中提供支持,在使用導航抽屜時,需要符合導航抽屜設計原則(NavigationDrawer),看看你是否有必要創建導航抽屜?。
創建抽屜布局
如果你要添加一個導航抽屜,需要用DrawerLayout來作為用戶界面的根視圖,DrawerLayout視圖下需放置兩個子視圖,一個是用來顯示顯示屏幕的主體內容(導航抽屜隱藏的時候),一個是用來顯示導航抽屜。
用來顯示屏幕主體內容的視圖一般是FrameLayout(運行的時候,會被一個Fragment填充),用來顯示導航抽屜的視圖一般是一個ListView,如下所示
<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>
復制代碼
上面的布局說明了導航抽屜的布局一些非常重要的特點:
1、顯示主體內容的視圖必須是DrawerLayout下的第一個子視圖,因為抽屜視圖必須在主體內容視圖的上方(意味著DrawerLayout是一個以z軸來布局的控件)
2、顯示主體內容的視圖必須設置為匹配父視圖的高和寬,因為當抽屜視圖隱藏的時候顯示主體內容的視圖代表了整個用戶界面
? ?? ?3、抽屜視圖的layout_gravity屬性值需為“start”,To support right-to-left (RTL) languages,specify the value with "start" insteadof "left" (so the drawer appears on the right when thelayout is RTL)
? ?? ?4、抽屜視圖的寬度不宜匹配父視圖,應當適當的窄一點,這樣就能在抽屜顯示的時候還能看到主體內容視圖的一部分
初始化抽屜列表
抽屜視圖一般包含一個ListView(具體包含的View取決于你的應用),該ListView和平常沒什么兩樣,都需要一個Adapter來填充,也可設置單項選中監聽器
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);
// Set the adapter for the list view
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPlanetTitles));
// Set the list's click listener
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
...
}
}
復制代碼
處理導航項選點擊事件
導航項的點擊事件其實就是包含的ListView項的點擊事件,我們需要根據點擊的項來相應的改變主體內容,記得上面說過顯示主體內容的View運行時一般會是一個Fragment,所以只要把當前的Fragment替換成相應的Fragment就行了
private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
selectItem(position);
}
}
/** Swaps fragments in the main content view */
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);
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
// Highlight the selected item, update the title, and close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
@Override
public void setTitle(CharSequence title) {
mTitle = title;
getActionBar().setTitle(mTitle);
}
復制代碼
監聽導航抽屜打開和關閉事件
可以為DrawerLayout設置?DrawerLayout.DrawerListener監聽器來監聽打開和關閉事件,當導航抽屜打開和關閉時分別會回調onDrawerOpened()?和onDrawerClosed()?方法
但是如果你的Activity包含Action Bar話,你可以選擇?ActionBarDrawerToggle?來替代?DrawerListener?,ActionBarDrawerToggle?實現了DrawerListener接口,所以抽屜的打開和關閉事件照樣能監聽的到,并且使用ActionBarDrawerToggle能促進Action Bar Icon和導航抽屜之間的交互(通過點擊icon來打開和關閉導航抽屜),當導航抽屜打開或關閉時Action Bar的狀態也應該做相應的改變(?NavigationDrawer?中有介紹)
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) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
/* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content view
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
}
復制代碼
點擊應用圖標來打開和關閉導航抽屜
前面我們是介紹過通過手勢來打開和關閉導航抽屜,但是如果Activity包含Action Bar的話,當我們點擊應用圖標時也能打開和關閉導航抽屜,而且我們也需要通過圖標來指示導航抽屜當前的狀態,如果我們是使用ActionBarDrawerToggle類的話,可以通過設置構造方法的參數來做到這一點,它的構造方法參數有五個,分別代表:宿主Activity、DrawerLayout、導航抽屜打開時應用圖標、導航抽屜打開時描述文本、導航抽屜關閉時描述文本
還有一點要注意的是,當手機屏幕的配置環境發生變化時(橫豎屏切換),導航抽屜的配置也需改變,當宿主Activity的onRestoreInstanceState方法調用的時候,導航抽屜的狀態也需進行同步,可在onPostCreate方法中進行同步,具體的可以看如下代碼
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) {
getActionBar().setTitle(mTitle);
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View 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);
}
...
}
復制代碼
幾張運行的截圖:
?
轉載于:https://my.oschina.net/1590538xiaokai/blog/324628
總結
以上是生活随笔為你收集整理的Navigation Drawer详解-Google推出的用来取代Sliding Menu的控件(一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Lua面向对象利用metamethod重
- 下一篇: 你必须掌握足够的知识来明确如何拥有自己的