原生Android 側滑選單實踐(部分)

故事熊的象限發表於2019-02-23

此為第一個製作側滑選單的實踐 。

此部分僅僅為部分實踐

僅缺menu的字串佈局,以及需要修改的MainActivity.java檔案,也是需要主要修改的地方。

從使用MD設計-進行側滑選單的製作(activity_main.xml部分)仍然可看。

當中為了向前相容以及使用Material Design,參考了約10個連結。

檔案路徑、參考連結為文章末尾,為了更好的閱讀體驗,增加了檔案原始碼展示(部分程式碼有刪改)。

使用MD設計

設定向前相容

進行4.0系統的一些工作

參考連結-向前相容-1

首先準備新增MD設計包,但考慮到Android Icecream(4.0)僅為14,參考連結中得知Appcomat為21,所以先做以下調整:

  1. build.gradle:
android {
    compileSdkVersion 21
    defaultConfig {
        applicationId "product.felixxiong.com.MyPackgeName"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
...
dependencies {
    implementation fileTree(dir: `libs`, include: [`*.jar`])
    implementation `com.android.support:appcompat-v7:21.0.+`  //匯入Appcompat依賴5.0的21並隨時獲取可用新版本
    implementation `com.android.support.v7.widget.SwichCompat`//匯入支援MD的switch控制元件
    implementation `com.android.support:design.21`  //匯入21設計庫:參考連結:
   
複製程式碼

values相關xml檔案

  1. 新建values/themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="AppTheme.Base"/>
    <style name="AppTheme.Base" parent="Theme.AppCompat">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimary</item>
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>
</resources>
複製程式碼
  1. 新建values-v21/themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.Base">
    <item name="android:windowContentTransitions">true</item>
    <item name="android:windowAllowEnterTransitionOverlap">true</item>
    <item name="android:windowAllowReturnTransitionOverlap">true</item>
    <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
    <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
</style>
</resources>
複製程式碼

新增依賴

參考連結:向前相容

apply plugin: `com.android.application`

allprojects {
    repositories {
        google()
        jcenter()
    }
}
...
dependencies {
    implementation fileTree(dir: `libs`, include: [`*.jar`])
    implementation `com.android.support:appcompat-v7:21.0.+`  //匯入Appcompat依賴5.0的21並隨時獲取可用新版本
    implementation `com.android.support.v7.widget.SwichCompat`//匯入支援MD的switch控制元件
    implementation `com.android.support:design.21`  //匯入21設計庫
    implementation `com.android.support.constraint:constraint-layout:1.1.2`
    //implementation `com.google.android.material:material:1.0.0-rc01`
複製程式碼

使用Toolbar替換Action Bar

參考連結-向前相容-1

  1. active_main.xml:
  <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/Theme.AppCompat.NoActionBar" /> 
            <!--參考連結:關於toolbar-4-->
            <!--android:background="?attr/colorPrimaryDark"-->
                android:background="#3F51B5">                     <!--Toolbar可自定義顏色-->
</android.support.v7.widget.Toolbar>
複製程式碼
  1. MainActivity.java:
@Override
    protectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResource()); 
        //getLayoutResource()此處需要獲取佈局檔案R.layout.……
        
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); //主要關於Toolbar的程式碼
        if(toolbar != null) {
            setSupportActionBar(toolbar);
        }
    }
複製程式碼

進行側滑選單的製作

佈局檔案

導航欄佈局

activity_main.xml
  1. 設定material.navigation.NavigationView

參考連結:Material Design

<com.google.android.material.navigation.NavigationView

        android:id="@+id/left_navigation_drawer"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"                <!--layout_gravity指定重力-->
        app:headerLayout="@layout/navigation_header"  <!--設定navigation頭佈局-->
        app:menu="@menu/my_navigation_items">         <!--設定navigation導航佈局-->
    <!--android:dividerHeight="0dp"
        android:background="#111"--/>

    </com.google.android.material.navigation.NavigationView>

</android.support.v4.widget.DrawerLayout>
複製程式碼

設定佈局,在相應目錄下新建檔案:

layout
avigation_header.xml

menumy_navigation_items

        android:dividerHeight="0dp"
複製程式碼

此處程式碼連結為開發者文件,MD可能不需要兩行程式碼。

  1. 新增Framelayout

此處連結為開發者文件。

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/decor_content_frame"> 
        <!--主內容檢視必須為第一個檢視,抽屜式導航必須位於內容頂部-->

        <android.support.v7.widget.Toolbar 
        ... />

    </FrameLayout>
複製程式碼

選單頭部佈局

navigation_header.xml

參考連結:側滑選單-1

<?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:background="?attr/colorPrimary"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingBottom="50dp"
    android:paddingTop="50dp"
    android:theme="@style/ThemeOverlay.AppCompat.Dark">

    <com.google.android.material.internal.VisibilityAwareImageButton 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"/>

    <android.support.v7.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="demo"/>


</LinearLayout>
複製程式碼

選單項佈局

my_navigation_items

此處參考連結:側滑選單-1,因為開發者文件中使用Adpter方法實現填充,需要深入瞭解Adpter,故未加入。

JAVA檔案()

Main Activity.java

參考連結:側滑選單-1

  1. 初始化抽屜導航欄列表
public class MainActivity extends AppCompatActivity {

    @Override
    protectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        }
    
    private Toolbar toolbar;   //此處Toolbar修改為自己習慣的寫法,為變數
    private String[] mTitles;  //建立標題變數
    private DrawerLayout mDrawerLayout;  //建立抽屜檢視變數
    private NavigationView mDrawerNavgation; //建立側滑選單檢視變數
    //private ActionBarDrawerToggle mDrawerToggle;  在後文中出現
    //建立Toobar的子類作為監聽器,需要在生命週期中呼叫togge
    //private CharSequence mDrawerTitle;
    //private CharSequence mTitle;

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

      //mTitles = R.layout.activity_main.getStringArray(R.array.Titles_array); //初始化介面
      //此處Toolbar修改為自己習慣的寫法,例項化Toolbar寫一起
        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
        onCreateOptionsMenu(R.layout.activity_main);
        toolbar.setTitle("My Title");
        setSupportActionBar(toolbar);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

        mDrawerNavgation = (NavigationView) findViewById(R.id.left_navigation_drawer);
        mDrawerNavgation.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_layout, mTitles));  //為列表檢視設定介面卡

        mDrawerNavgation.setOnItemClickListener(new DrawerItemClickListener());  //呼叫接收點選事件,設定點選監聽器
    }
    ...
   }
}
複製程式碼
  1. 處理導航點選事件
private class DrawerItemClickListener implements NavigationView.OnItemClickListener {   //開始處理導航事件:在使用者選擇某一項時實現介面更改內容檢視
        @Override                                                  //這裡開始呼叫onItemClick
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    }

    private void selectItem(int position) {

        Fragment fragment = new Fragment();  //封裝一個新片段並指定要根據位置顯示的
        Bundle args = new Bundle();
        args.putInt(Fragment.ARG_LIST_NUMBER, position);
        fragment.setArguments(args);

        FragmentManager fragmentManager = getFragmentManager(); //通過替換任何現有片段插入片段
        fragmentManager.beginTransaction()                      
         //將不同的FrameLayout插入內容主檢視
                .replace(R.id.decor_content_frame, fragment)
                .commit();

        // Highlight the selected item, update the title, and close the drawer
        mDrawerNavgation.setItemChecked(position, true);
        setTitle(mTitles[position]);
        mDrawerLayout.closeDrawer(mDrawerNavgation);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }
複製程式碼

3.偵聽開啟和關閉事件

public class MainActivity extends AppCompatActivity {
    private ActionBarDrawerToggle mDrawerToggle; 
    //建立Toobar的子類作為監聽器,需要在生命週期中呼叫togge
    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    ...
     @Override
    protectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        }
...
        mTitle = mDrawerTitle = getTitle();
        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) {
            super.onDrawerClosed(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) {
            super.onDrawerOpened(drawerView);
            getActionBar().setTitle(mDrawerTitle);
            invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
        }
    };

        mDrawerLayout.setDrawerListener(mDrawerToggle); //將抽屜切換設定為DrawerListener

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);
    }
    /* 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(mDrawerNavgation);
        menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
}
複製程式碼
  1. 通過應用圖示開啟和關閉
 mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);  
//通過應用圖示開啟或關閉抽屜導航欄
        mDrawerToggle = new ActionBarDrawerToggle(this,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 */
        ) {

            public void onDrawerClosed(View view) { //當抽屜處於完全關閉狀態時呼叫。
                super.onDrawerClosed(view);
                //getActionBar().setTitle(mTitle);  //設定標題
            }

            public void onDrawerOpened(View drawerView) { //當抽屜處於完全狀態時呼叫。
                super.onDrawerOpened(drawerView);
                //getToolBar().setTitle(mDrawerTitle); //設定標題
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle); ////將抽屜切換設定為DrawerListener

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) { 
    //每當我們呼叫invalidateOptionsMenu()時呼叫
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerNavgation); 
        //如果導航抽屜已開啟,請隱藏與內容檢視相關的操作項
        menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
}

    @Override
    protected void onPostCreate(Bundle savedInstanceState) { //在生命週期中呼叫ActionBarDrawerToggle
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState(); ////在onRestoreInstanceState發生後同步切換狀態。
    }

    @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);
    }
複製程式碼

檔案全部程式碼

build.gradle

allprojects {
    repositories {
        google()
        jcenter()
    }
}

android {
    compileSdkVersion 21
    defaultConfig {
        applicationId "product.penghaoxiong.com.androidquickcheck"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile(`proguard-android.txt`), `proguard-rules.pro`
        }
    }
}

dependencies {
    implementation fileTree(dir: `libs`, include: [`*.jar`])
    implementation `com.android.support:appcompat-v7:21.0.+`  //匯入Appcompat依賴5.0的21並隨時獲取可用新版本
    implementation `com.android.support.v7.widget.SwichCompat`//匯入支援MD的switch控制元件
    implementation `com.android.support:design.21`  //匯入21設計庫
    implementation `com.android.support.constraint:constraint-layout:1.1.2`
    //implementation `com.google.android.material:material:1.0.0-rc01`
    testImplementation `junit:junit:4.12`
    androidTestImplementation `com.android.support.test:runner:1.0.2`
    androidTestImplementation `com.android.support.test.espresso:espresso-core:3.0.2`
}
複製程式碼

參考連結

關於向前相容

  1. AppCompat 21實現低版本手機使用Material Design
  2. 在低版本Android上使用Material Design——AppCompat v21
  3. 如何選擇 compileSdkVersion, minSdkVersion 和 targetSdkVersion

關於Toolbar

  1. android:ToolBar詳解(手把手教程)
  2. 利用Toolbar替換ActionBar
  3. ToolBar替代ActionBar

Material Design

  1. Navigation Views

側滑選單

  1. Android 實現側滑選單-design

路徑

  1. build.gradle:appuild.gradle

  2. MainActivity.java:appsrcmainjavaproductfelixxiongcomcheckMainActivityMainActivity.java

  3. active_main.xml:appsrcmain
    eslayoutactive_main.xml

  4. layout:

    layout
    avigation_header.xml

  5. values:appsrcmain
    esvalues

    values/themes.xml

    values-v21/themes.xml

相關文章