Kotlin實現側滑抽屜菜單(DrawerLayout+NavigationView+Toolbar)

轉載請標明出處:http://blog.csdn.net/donkor_/article/details/78819081

前言
最近做了一個純Kotlin開發的Android開源軟件,“DeepNight-in-kotlin,陪你度過每一個深夜”,剛好用到了Material Design設計風格。功能完善好,代碼簡單貼一下,方便日後查看和使用。

本文demo包含以下要點:

  • DrawerLayout+NavigationView+ToolBar的使用

  • Fragment簡單封裝,實現懶加載

下面看下效果圖。

由上面的效果圖可以看出,其中的佈局包括3部分,主體佈局,抽屜菜單未滑出時的顯示佈局 ,抽屜菜單的頭部佈局 ,抽屜菜單的菜單項佈局

基本配置
在Project的 build.gradle 中的dependencies添加:

implementation 'com.android.support:design:26.1.0'

主佈局文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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="match_parent"
    android:id="@+id/drawer_layout">
    <!--主內容-->
    <include layout="@layout/toolbar_layout"/>
    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity = "start"
        app:headerLayout="@layout/head_layout"
        app:itemBackground="?attr/colorPrimary"
        app:menu="@menu/menu">
    </android.support.design.widget.NavigationView>

</android.support.v4.widget.DrawerLayout>

注:可以看出除了DrawerLayout包裹了NavigationView控件,其中menu指的的是抽屜菜單菜項,headerLayout指的是抽屜菜單的頭部佈局

抽屜菜單header佈局drawer_header.xml

<?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:gravity="center"
    android:orientation="vertical"
    >

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/head_view"
        android:layout_marginTop="30dp"/>

    <TextView
        android:id="@+id/tv_user_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Donkor" />
</LinearLayout>

抽屜菜單menu佈局文件menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <group android:id="@+id/ground1">
        <item
            android:id="@+id/nav_item1"
            android:icon="@mipmap/icon_all"
            android:title="item1"
            app:showAsAction="ifRoom" />
    </group>
    <group android:id="@+id/ground2">
        <item
            android:id="@+id/nav_item2"
            android:icon="@mipmap/icon_bosom"
            android:title="item2"
            app:showAsAction="ifRoom" />
        <item
            android:id="@+id/nav_item3"
            android:icon="@mipmap/icon_buttocks"
            android:title="item3"
            app:showAsAction="ifRoom" />
        <item
            android:id="@+id/nav_item_stockings"
            android:icon="@mipmap/icon_stockings"
            android:title="item4"
            app:showAsAction="ifRoom" />
    </group>
</menu>

注:加了group的話,在drawerlayout裏會以group爲單位劃線。

回過頭,我們再來看看DrawerLayout下導入的toolbar_layout佈局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/blue"
        app:contentInsetStart="0dp">

        <TextView
            android:id="@+id/tv_bar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_gravity="center"
            android:text="Title"
            android:textColor="@android:color/white" />

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

    <LinearLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" />
</LinearLayout>

注:可以看到Toolbar控件包裹到TextView,該View用來做ToolBar標題。效果圖中由於我們使用到了ToolBar的左側圖標,使用ToolBar自帶的標題會導致標題不居中,所以不建議使用。底下的LinearLayout用作主體佈局內容

注:綜上Material Design的佈局基本貼完。之後看下Theme自定義style。修改ToolBar左側圖標顏色

<resources>

    <!-- Base application theme. -->
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="android:windowAnimationStyle">@style/AnimationActivity</item>
    </style>
    <!--Activity動畫-->
    <style name="AnimationActivity" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/slide_in_left</item>
        <item name="android:activityOpenExitAnimation">@anim/slide_out_left</item>
        <item name="android:activityCloseEnterAnimation">@anim/slide_in_right</item>
        <item name="android:activityCloseExitAnimation">@anim/slide_out_right</item>
    </style>
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@android:color/white</item>
        <item name="colorPrimaryDark">@android:color/white</item>
        <!-- 溢出菜單圖標顏色-->
        <item name="colorControlNormal">@android:color/white</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowBackground">@android:color/white</item>
    </style>
</resources>

主佈局Kotlin類MainActivity

package com.donkor.demo.materialdesign

import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.view.GravityCompat
import android.support.v7.app.ActionBarDrawerToggle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.toolbar_layout.*

class MainActivity : AppCompatActivity() {

    private var firstFragment: FirstFragment? = null
    private var secondFragment: SecondFragment? = null
    private var threeFragment: ThreeFragment? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        /*設置ActionBar
        *不使用toolbar自帶的標題
        */
        toolbar.title = ""
        setSupportActionBar(toolbar)
        /*顯示Home圖標*/
        supportActionBar!!.setDisplayHomeAsUpEnabled(true)

        /*設置ToolBar標題,使用TestView顯示*/
        tv_bar_title.text = "Item1"


        /*設置Drawerlayout的開關,並且和Home圖標聯動*/
        val mToggle = ActionBarDrawerToggle(this, drawer_layout, toolbar, 0, 0)
        drawer_layout.addDrawerListener(mToggle)
        /*同步drawerlayout的狀態*/
        mToggle.syncState()


        /*設置監聽器*/
        setListener()

        initFragment(savedInstanceState)
    }


    private fun initFragment(savedInstanceState: Bundle?) {
        if (savedInstanceState != null) {
            //異常情況
            val mFragments: List<Fragment> = supportFragmentManager.fragments
            for (item in mFragments) {
                if (item is FirstFragment) {
                    firstFragment = item
                }
                if (item is SecondFragment) {
                    secondFragment = item
                }
                if (item is ThreeFragment) {
                    threeFragment = item
                }
            }
        } else {
            firstFragment = FirstFragment()
            secondFragment = SecondFragment()
            threeFragment = ThreeFragment()
            val fragmentTrans = supportFragmentManager.beginTransaction()
            fragmentTrans.add(R.id.fl_content, firstFragment)
            fragmentTrans.add(R.id.fl_content, secondFragment)
            fragmentTrans.add(R.id.fl_content, threeFragment)
            fragmentTrans.commit()
        }
        supportFragmentManager.beginTransaction().show(firstFragment)
                .hide(secondFragment)
                .hide(threeFragment)
                .commit()
    }

    /*設置監聽器*/
    private fun setListener() {
        nav_view.setNavigationItemSelectedListener { item ->
            when (item.itemId) {
                R.id.nav_item1 -> {
                    tv_bar_title.text = "Item1"
                    supportFragmentManager.beginTransaction().show(firstFragment)
                            .hide(secondFragment)
                            .hide(threeFragment)
                            .commit()
                }
                R.id.nav_item2 -> {
                    tv_bar_title.text = "Item2"
                    supportFragmentManager.beginTransaction().show(secondFragment)
                            .hide(firstFragment)
                            .hide(threeFragment)
                            .commit()
                }
                R.id.nav_item3 -> {
                    tv_bar_title.text = "Item3"
                    supportFragmentManager.beginTransaction().show(threeFragment)
                            .hide(firstFragment)
                            .hide(secondFragment)
                            .commit()
                }
            }
            drawer_layout.closeDrawer(GravityCompat.START)
            true
        }
    }
}

注:MainActivity中的註釋寫的很詳細 ,這裏不再做過多的解釋

BaseFragment基類,實現懶加載

package com.donkor.demo.materialdesign

import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

/**
 * Created by donkor on 2017/12/16.
 */
abstract class BaseFragment : Fragment() {
    var rootView: View? = null
    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        if (rootView == null) {
            rootView = inflater?.inflate(getLayoutResources(), container, false)
        }
        return rootView
    }

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initView()
    }

    /**
     * 判斷該Fragment是否顯示在用戶面前
     */
    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        if (!hidden)
            loadData()

    }

    abstract fun getLayoutResources(): Int
    abstract fun initView()
    /**
     * 懶加載,當前Fragment顯示的時候才進行網絡請求
     * 如果數據不需要每次都刷新,可以先判斷數據是否存在
     * 數據不存在 -> 進行網絡請求    數據存在 -> 什麼都不做
     */
    abstract fun loadData()

}

FirstFragment

class FirstFragment : BaseFragment() {
    override fun loadData() {
        //懶加載,當前Fragment顯示的時候才進行網絡請求
        //如果數據不需要每次都刷新,可以先判斷數據是否存在
        //數據不存在 -> 進行網絡請求    數據存在 -> 什麼都不做
    }

    override fun getLayoutResources(): Int {
        return R.layout.fragment_frist
    }

    override fun initView() {
    }
}

Fragment的佈局fragment_frist.xml

<?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:orientation="vertical"
    android:layout_gravity="center"
    android:gravity="center">

   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="FirstFragment"
       android:textSize="25sp"/>
</LinearLayout>

注:SecondFragment、ThreeFragment的代碼跟佈局和FirstFragment類似,這裏就不貼了。meun用到的icon如有需要則可以下載demo去拿。

DeepNight-in-kotlin項目使用地址:https://github.com/ChenYXin/DeepNight-in-kotlin
Demo_CSDN 下載地址 :http://download.csdn.net/download/donkor_/10161518


About me
Email :[email protected]
Android開發交流QQ羣 : 537891203
Android開發交流羣

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章