MaterialDesign基本使用

1、ToolBar

ToolBar是為了替代ActionBar的,ActionBar被限定只能位于Activity的頂部,不能實(shí)現(xiàn)MaterialDesign的效果,所以Google不建議使用ActionBar,而ToolBar不僅繼承了ActionBar的所有功能,而且靈活性很高,可以配合其他控件完成MaterialDesign效果。
我們新建的項(xiàng)目默認(rèn)都會顯示ActionBar的,這是根據(jù)項(xiàng)目中設(shè)置的主題現(xiàn)實(shí)的??聪翧ndroidManifest.xml文件中的配置。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test.rowingview">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

可以看到上面使用了android:theme="@style/AppTheme"指定了項(xiàng)目的主題AppTheme,看下是它是如何定義的

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

可以看到這里定義了一個(gè)name為AppTheme,parent為Theme.AppCompat.Light.DarkActionBar的主題,DarkActionBar表示深色主題,那么ActionBar則為深色主題,所以ActionBar上面的元素則為淺色主題。如果我們想使用ToolBar來替代ActionBar就需要更換Theme.AppCompat.Light.DarkActionBarTheme.AppCompat.Light.NoActionBar(淺色主題)或Theme.AppCompat.NoActionBar(深色主題)。下面我們看下如何使用ToolBar

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/tool_bar"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/purple_500" />
</LinearLayout>

可以看到我們使用xmlns:app指定了一個(gè)新命名空間,這是因?yàn)?strong>MaterialDesign中屬性是新系統(tǒng)中新增的,老系統(tǒng)中不存在,那么為了兼容老系統(tǒng),我們不能使用android:attribute這樣的寫法,而是使用app:attribute。
由于我們設(shè)置了項(xiàng)目的主題為淺色主題,那么ToolBar的主題也為淺色主題,那么ToolBar上面的元素則為深色,如果我們想讓ToolBar上的元素為淺色,就需要通過android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"設(shè)置ToolBar的主題為深色。這就會使彈出的菜單項(xiàng)為深色,所以為了美觀通過
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"設(shè)置菜單項(xiàng)為淺色主題,由于app:popupTheme是新增的屬性,所以為了兼容需要使用app:attribute的寫法。
如果我們想讓ToolBar具有和ActionBar相同的功能,就需要調(diào)用setSupportActionBar(tool_bar),我們也可以通過重寫Activity的onCreateOptionsMenu在ToolBar上添加菜單項(xiàng),重寫Activity的onOptionsItemSelected來實(shí)現(xiàn)菜單項(xiàng)的點(diǎn)擊事件,具體代碼如下。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(tool_bar)
        //設(shè)置是否允許展示返回按鈕
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        //設(shè)置自定義返回按鈕的圖片
        supportActionBar?.setHomeAsUpIndicator(R.mipmap.ic_arrow)
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.main_menu, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            android.R.id.home -> {
            }
            R.id.title -> {
            }
            R.id.content -> {
            }
            R.id.scroll_menu -> {
            }
        }
        return true
    }
}

上面我們通過setDisplayHomeAsUpEnabled(true)設(shè)置返回按鈕展示,可以在onOptionsItemSelected中監(jiān)聽返回按鈕的點(diǎn)擊,其id默認(rèn)為android.R.id.home。ToolBar的使用還是非常簡單的。

2、滑動(dòng)菜單DrawLayout

DrawerLayout中允許放兩個(gè)子控件,第一個(gè)子控件表示展示的主屏幕內(nèi)容,第二個(gè)子控件表示滑動(dòng)菜單中的內(nèi)容,使用layout_gravity來表示滑動(dòng)菜單的位置。注意:DrawLayout并不是只允許放兩個(gè)控件,可以放多個(gè),只不過第一個(gè)控件為主屏內(nèi)容,其他子控件可以通過layout_gravity來設(shè)置菜單展示的位置。

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/purple_500"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/draw_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="主界面" />


        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:background="@android:color/white"
            android:text="Hello World!" />

    </androidx.drawerlayout.widget.DrawerLayout>
</LinearLayout>

這樣我們就通過布局文件就實(shí)現(xiàn)了滑動(dòng)菜單,在屏幕左側(cè)向右滑動(dòng)就可以讓滑動(dòng)菜單顯示出來。


image.png

如果我們想實(shí)現(xiàn)滑動(dòng)菜單時(shí)和導(dǎo)航按鈕進(jìn)行聯(lián)動(dòng)該怎么實(shí)現(xiàn)呢?其實(shí)很簡單,修改下MainActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(tool_bar)
        //設(shè)置是否允許展示返回按鈕
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        //設(shè)置自定義返回按鈕的圖片
//        supportActionBar?.setHomeAsUpIndicator(R.mipmap.ic_arrow)
        val drawerToggle = ActionBarDrawerToggle(
            this,
            draw_layout,
            tool_bar,
            R.string.draw_open,
            R.string.draw_close
        )
        drawerToggle.syncState()
        draw_layout.addDrawerListener(drawerToggle)
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.main_menu, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            android.R.id.home -> {
            }
            R.id.title -> {
            }
            R.id.content -> {
            }
            R.id.scroll_menu -> {
            }
        }
        return true
    }
}

代碼很簡單:

  • 首先調(diào)用supportActionBar?.setDisplayHomeAsUpEnabled(true)展示導(dǎo)航按鈕(其id為android.R.id.home);
  • 然后創(chuàng)建ActionBarDrawerToggle對象( DrawerLayout.DrawerListener的子類);
  • 然后draw_layout.addDrawerListene()設(shè)置監(jiān)聽;
  • 最后記得調(diào)用drawerToggle.syncState()進(jìn)行狀態(tài)同步,否則無效。
    這樣就實(shí)現(xiàn)了滑動(dòng)菜單和導(dǎo)航按鈕的聯(lián)動(dòng)。

3、NavigationView

剛才我們直接通過TextView來作為滑動(dòng)菜單的頁面,其實(shí)Google提供了專門的控件NavigationView來實(shí)現(xiàn)滑動(dòng)菜單。NavigationView中有兩個(gè)屬性app:headerLayout和app:menu,app:headerLayout是用來展示菜單的頭布局的,app:menu是用來展示菜單項(xiàng)的。使用起來很簡單,這里我們修改下activity_main的布局。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/purple_500"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/draw_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="主界面" />


        <com.google.android.material.navigation.NavigationView
            android:id="@+id/navigation_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            app:headerLayout="@layout/head_navigation"
            app:menu="@menu/main_menu" />

    </androidx.drawerlayout.widget.DrawerLayout>
</LinearLayout>

效果如下:

image.png

可以通過navigation_view.setNavigationItemSelectedListener()監(jiān)聽菜單中item的點(diǎn)擊事件。

4、CoordinatorLayout

CoordinatorLayout是一個(gè)加強(qiáng)版的FrameLayout,可以監(jiān)聽所有子控件的事件,并自動(dòng)幫我們實(shí)現(xiàn)最合理的響應(yīng)。先看個(gè)效果


image.png

可以看到FloatingActionButton被Snackbar遮住了,如果能讓CoordinatorLayout監(jiān)聽到Snackbar的彈出事件,那么它會自動(dòng)將FloatingActionButton上移。看下使用CoordinatorLayout之后的布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/purple_500"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/draw_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <androidx.coordinatorlayout.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="主界面" />

            <com.google.android.material.floatingactionbutton.FloatingActionButton
                android:id="@+id/float_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom|end"
                android:layout_margin="16dp"
                android:src="@mipmap/ic_arrow" />

        </androidx.coordinatorlayout.widget.CoordinatorLayout>

        <com.google.android.material.navigation.NavigationView
            android:id="@+id/navigation_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            app:headerLayout="@layout/head_navigation"
            app:menu="@menu/main_menu" />

    </androidx.drawerlayout.widget.DrawerLayout>
</LinearLayout>

再次看下實(shí)現(xiàn)的效果:

image.png

可以看到FloatingActionButton不再被Snackbar遮住了,并且FloatingActionButton會根據(jù)SnackBar的彈出和消失上下移動(dòng)位置,SnackBar并不是CoordinatorLayout的子控件,它是如何監(jiān)聽彈出和消失的呢?從Snackbar的用法不難看出:

 Snackbar.make(float_button, text, duration).show()

第一個(gè)參數(shù)我們傳入就是FloatingActionButton,而FloatingActionButton是CoordinatorLayout的子類,因此可以監(jiān)聽到彈出事件。如果我們傳入的不是
FloatingActionButton而是DrawLayout則無法監(jiān)聽到SnackBar的彈出和隱藏。

5、AppBarLayout

先看個(gè)效果

9101961-bdfbefd3c06302ea.gif

從上面效果可以看出,當(dāng)滑動(dòng)控件向上滑動(dòng)時(shí),隱藏ToolBar,向下滑動(dòng)時(shí)展示ToolBar。實(shí)現(xiàn)這個(gè)效果就需要使用AppBarLayout,它是一個(gè)垂直方向的LinearLayout。實(shí)現(xiàn)步驟如下:

  • 1、使用AppBarLayout包裹ToolBar
  • 2、給滑動(dòng)控件指定app:layout_behavior="@string/appbar_scrolling_view_behavior"
    將滑動(dòng)控件的滾動(dòng)事件告訴AppBarLayout
  • 3、在AppBarLayout接收到滾動(dòng)事件時(shí),通過app:layout_scrollFlags="scroll|enterAlways|snap"設(shè)置其子控件如何去響應(yīng)滾動(dòng)事件。
    其中scroll表示當(dāng)滑動(dòng)控件向上滑動(dòng)時(shí),ToolBar會跟著向上滑動(dòng)并隱藏;enterAlways表示滑動(dòng)控件向下滑動(dòng)時(shí),ToolBar會跟著向下滑動(dòng)并顯示;
    snap表示ToolBar還未完全顯示或隱藏時(shí),會根據(jù)當(dāng)前滾動(dòng)的距離,自動(dòng)選擇顯示還是隱藏;
    具體代碼如下:
<androidx.coordinatorlayout.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <com.google.android.material.appbar.AppBarLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <androidx.appcompat.widget.Toolbar
                    android:id="@+id/tool_bar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:background="@color/purple_500"
                    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                    app:layout_scrollFlags="enterAlways|scroll|snap"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
            </com.google.android.material.appbar.AppBarLayout>

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recy_list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_behavior="@string/appbar_scrolling_view_behavior" />

        </androidx.coordinatorlayout.widget.CoordinatorLayout>

6、可折疊式標(biāo)題欄

先來看個(gè)效果:

9833282-31a22c4230401c35.gif

要實(shí)現(xiàn)這個(gè)效果就需要使用可折疊式標(biāo)題欄CollapsingToolbarLayout,它是作用在ToolBar基礎(chǔ)上的布局,使用它可以讓ToolBar實(shí)現(xiàn)的效果更加豐富。它被限定作為AppBarLayout的子布局,而AppBarLayout又必須是CoordinatorLayout的子布局,直接上代碼:

<androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="250dp">

            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/collapsing_toolbar"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:contentScrim="@color/purple_200"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:scaleType="centerCrop"
                    android:src="@mipmap/ic_pager1"
                    app:layout_collapseMode="parallax" />

                <androidx.appcompat.widget.Toolbar
                    android:id="@+id/toolBar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin" />


            </com.google.android.material.appbar.CollapsingToolbarLayout>

        </com.google.android.material.appbar.AppBarLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recy_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/darker_gray"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="20dp"
            android:src="@mipmap/ic_arrow"
            app:layout_anchor="@id/app_bar"
            app:layout_anchorGravity="bottom|end" />
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

可以看到給CollapsingToolbarLayout設(shè)置了屬性app:contentScrim="@color/purple_200"表示CollapsingToolbarLayout在趨于折疊或折疊之后的顏色,其中app:layout_scrollFlags之前我們使用過,只不過之前是設(shè)置在ToolBar上的,現(xiàn)在設(shè)置給了CollapsingToolbarLayout,其中exitUntilCollapsed表示CollapsingToolbarLayout隨著滾動(dòng)折疊之后保留在屏幕上不再移出屏幕。
我們在CollapsingToolbarLayout中定義了一個(gè)ImageView和一個(gè)ToolBar。很簡單,只不過app:layout_collapseMode比較陌生,它是用于指定CollapsingToolbarLayout在折疊過程中,子控件的折疊形式,給ToolBar設(shè)置成了pin表示折疊過程中位置保持始終不變,給ImageView設(shè)置成parallax隨著折疊產(chǎn)生一定的位移。

充分利用系統(tǒng)狀態(tài)欄空間

如果我們想使用系統(tǒng)狀態(tài)欄的空間可以使用如下代碼:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.decorView.systemUiVisibility=View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            window.statusBarColor=ContextCompat.getColor(this,android.R.color.transparent)
        }else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
        }

但是對于CoordinatorLayout、AppBarLayout、CollapsingToolbarLayout這種嵌套結(jié)構(gòu)的布局好像并不奏效,對于這種布局我們只需要將ImageView以及其所有父控件都增加android:fitsSystemWindows="true"才有效。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容