文章出處

寫Android的時候,可能有多個界面。在風格統一的軟件中,寫Activity時會有很多重復。例如我所在軟工課程小組的項目:Github鏈接 ,里面的TaskListActivity和TeacherListActivity就在Navigation的處理上有重復。還有一個雙擊退出APP的方法onBackPressed()也重復實現了。之前讓負責界面的同學把這些代碼放到一個BaseActivity里面,讓其他Activity繼承它。他說不好做,他嘗試過,但失敗了。

于是這次我獨自做 英語詞典APP 的時候 ,經過在Google上的一番搜索和實踐探索,寫出一個還可以的BaseActivity。現在做個記錄,以后還會用得到。
BaseActivity項目的Github鏈接

這個BaseActivity包括側滑菜單(Navigation Drawer)和工具欄(Tool Bar)。
先看最終效果:

一、Navigation Drawer

由于Navigation Drawer涉及到BaseActivity的主要布局,所以先說明。

  1. Activity的布局文件
    先看Android官方Navigation Drawer說明:Creating a Navigation Drawer
    根據說明,將 layout/activity_base.xml 設置為以下內容:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!-- 主內容布局 -->
        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
        <!-- 側滑菜單 -->
        <ListView
            android:id="@+id/left_drawer"
            android:layout_width="240dp"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:background="#111"
            android:choiceMode="singleChoice"
            android:divider="@android:color/transparent"
            android:dividerHeight="0dp"/>
    </android.support.v4.widget.DrawerLayout>

    Android Studio不會提示android:layout_gravity這一項,但是整行敲完之后,可以正常運行。

  2. 側滑菜單列表布局
    這里只做簡單的布局,所以側滑菜單項都是TextView。
    創建 layout/list_item_drawer.xml

    <?xml version="1.0" encoding="utf-8"?>
    
    <TextView
        android:id="@+id/tv_na_draw"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:textColor="#fff"/>

    因為等會兒要用ArrayAdapter,所以這里最外層一定要是TextView。

  3. 側滑菜單項的文本
    StringArray
    創建 values/string_array_test.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string-array name="planets_array">
            <item>主界面</item>
            <item>關于</item>
            <item>設置</item>
            <item>退出</item>
        </string-array>
    </resources>
  4. Activity初始化
    Initialize the Drawer List
    這里由于要將Activity做成BaseActivity,所以和官方文檔上的代碼不太一樣。

    public class BaseActivity extends AppCompatActivity {
        protected String[] planetTitles;
        protected DrawerLayout drawerLayout;
        protected ListView drawerList;
        protected FrameLayout frameLayout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
    
        /**
        * 重寫setContentView,以便于在保留側滑菜單的同時,讓子Activity根據需要加載不同的界面布局
        */
        @Override
        public void setContentView(@LayoutRes int layoutResID) {
            drawerLayout = (DrawerLayout) getLayoutInflater().inflate(R.layout.activity_base, null);
            frameLayout = (FrameLayout) drawerLayout.findViewById(R.id.content_frame);
            // 將傳入的layout加載到activity_base的content_frame里面
            getLayoutInflater().inflate(layoutResID, frameLayout, true);
            super.setContentView(drawerLayout);
    
            setUpNavigation();
        }
    
        private void setUpNavigation() {
            planetTitles = getResources().getStringArray(R.array.planets_array);
            drawerList = (ListView) findViewById(R.id.left_drawer);
            drawerList.setAdapter(new ArrayAdapter<>(BaseActivity.this,
                    R.layout.list_item_drawer, planetTitles));
        }
    }
  5. MainActivity
    先創建個Activity查看效果。
    創建MainActivity繼承BaseActivity :

    public class MainActivity extends BaseActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    }

    layout_main用的是默認布局。
    在啟動前要更改 AndroidManifest.xml ,將MainActivity設置成Launcher:

    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
    
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

    啟動后,手指從最左往右劃,打開側滑菜單。

  6. 添加側滑菜單點擊事件
    Handle Navigation Click Events
    先創建ClickListener,這里簡單地設置點擊后顯示所點擊的文本。
    在BaseActivity中添加:

    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    }
    
    private void selectItem(int position) {
        Toast.makeText(BaseActivity.this, planetTitles[position], Toast.LENGTH_SHORT).show();
    }

    在BaseActivity的 setUpNavigation() 中添加:

    drawerList.setOnItemClickListener(new DrawerItemClickListener());

二、ToolBar

  1. ToolBar 布局
    ToolBar的各個成分:

    Setting Up the App Bar
    打開AndroidManifest.xml,將里面的 android:theme="@style/AppTheme" 替換成 android:theme="@style/Theme.AppCompat.Light.NoActionBar",如下:

    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
    ...(三點表示省略,下同)

    創建 layout/toolbar.xml

    <?xml version="1.0" encoding="utf-8"?>
    <merge xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:elevation="4dp"
            android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
    
    </merge>
  2. ToolBar 初始化
    在BaseActivity里添加:

    public class BaseActivity extends AppCompatActivity {
        ...
        private Toolbar toolbar;
    
        ...
        private void setUpToolBar() {
            toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
        }
    }

    在BaseActivity的 setContentView() 里的 setUpNavigation();下面添加setUpToolBar();,如下:

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        ...
        setUpNavigation();
        setUpToolBar();
    }

    如果想要在MainActivity里顯示ToolBar,還需要在 activity_main.xml 里include一個ToolBar的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout ...>
    
        <include layout="@layout/toolbar"/>
    
    </RelativeLayout>

    顯示的效果如下:

  3. 加入側滑菜單打開鍵
    Material Design Icons 下載圖標。搜索menu,下載PNG版本。

    解壓后,將 ic_menu_black_24dp/android 文件夾下面的所有文件夾復制到 res/ 里面。

    在BaseActivity的 setUpToolBar() 中添加:

    toolbar.setNavigationIcon(R.drawable.ic_menu_black_24dp);


    雖然有圖標,但是還沒設置點擊事件,所以點擊的時候沒有任何反應。

  4. 點擊ToolBar的home按鈕打開Navigation Drawer
    在BaseActivity里添加:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                drawerLayout.openDrawer(GravityCompat.START);
                return true;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    這里就省略ActionBarDrawerToggle的部分了,影響不是特別大。實際應用中再去添加。

  5. 添加Option Menu
    values/strings.xml 里添加等會兒會用到的字符串:

    <resources>
        ...
        <string name="edit">編輯</string>
        <string name="search">搜索</string>
        <string name="change_history">變更記錄</string>
    </resources>

    Material Design Icons 下載相關圖標。
    創建 res/menu/menu_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <menu android:id="@+id/expanded_menu"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item
            android:id="@+id/menu_edit"
            android:icon="@drawable/ic_mode_edit_black_24dp"
            android:title="@string/edit"
            app:showAsAction="ifRoom"/>
    
        <item
            android:id="@+id/menu_search"
            android:icon="@drawable/ic_search_black_24dp"
            android:title="@string/search"
            app:showAsAction="ifRoom"/>
    
        <item
            android:id="@+id/menu_change_history"
            android:icon="@drawable/ic_change_history_black_24dp"
            android:title="@string/change_history"
            app:showAsAction="never"/>
    
    </menu>

    其中ifRoom表示如果ToolBar空間足夠,則將其圖標顯示在ToolBar上面。never表示永不顯示在ToolBar上面,只有當點擊option menu按鈕的時候,才會出現。
    在BaseActivity中添加:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        super.onCreateOptionsMenu(menu);
        return true;
    }

    啟動APP:

    點擊menu按鈕后:

  6. Option Menu的點擊事件
    在BaseActivity里的 onOptionsItemSelected() 增加case即可。

  7. 隱藏ActionBar的Option Menu
    有時候不想在某個Activity中顯示Option Menu,于是修改BaseActivity:

    public class BaseActivity extends AppCompatActivity {
        ...
        private boolean showOptionMenu = true;
    
        ...
        protected void hideOptionMenu() {
            showOptionMenu = false;
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            if (showOptionMenu) {
                getMenuInflater().inflate(R.menu.menu_main, menu);
            }
            super.onCreateOptionsMenu(menu);
            return true;
        }
    
    }

三、參考鏈接

  1. ToolBar
    https://developer.android.com/training/appbar/setting-up.html
    https://developer.android.com/training/appbar/actions.html
    http://stackoverflow.com/questions/32367041/calling-toolbar-on-each-activity
    http://stackoverflow.com/questions/30824324/clicking-hamburger-icon-on-toolbar-does-not-open-navigation-drawer
    http://stackoverflow.com/questions/19724567/how-to-add-menu-indicator-next-to-action-bars-app-icon
    http://stackoverflow.com/questions/26582075/cannot-catch-toolbar-home-button-click-event

  2. Navigation Drawer
    https://developer.android.com/training/implementing-navigation/nav-drawer.html
    http://stackoverflow.com/questions/33009469/baseactivity-for-navigation
    http://stackoverflow.com/questions/22652556/creating-base-activity-with-navigation-drawer-in-android

  3. ArrayAdapter
    http://stackoverflow.com/questions/9280965/arrayadapter-requires-the-resource-id-to-be-a-textview-xml-problems
    http://stackoverflow.com/questions/29591546/unable-to-use-layout-gravity-for-listview-inside-drawerlayout

  4. String Array
    https://developer.android.com/guide/topics/resources/string-resource.html#StringArray

  5. Material icons
    https://design.google.com/icons/


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()