當InstaMaterial遇到Design Support Library

jopen 9年前發布 | 29K 次閱讀 Android開發 移動開發 InstaMaterial

原文:InstaMaterial meets Design Support Library 

幾個月前,我開始寫InstaMaterial 系列文章。目的很簡單-就是為了證明實現Material Design規范中的任何炫酷UI效果其實都很容易。現在變的更容易了 - 谷歌給我們Android Design Support Library ,里面提供了幾乎所有重要的Material Design UI元素。在本文,我希望把InstaMaterial的源碼從自定義view的實現方式轉到用 Design Support Library 的方式。

前言

design support library 是否意味著這里描述的所有代碼都已經過時了呢?并不完全。的確,使用官方的實現方式總是要好些(真的嗎?),尤其是在標準的使用案例中。使用別人提供的實現方式意味著有人幫你考慮代碼的問題。我們不需要考慮浮動操作按鈕(Floating Action Button)在Kitkat, Lollipop 以及 M___之間的兼容性問題。多虧了它我們節省了不少的代碼量,從而有時間去實現更炫的東西(或者讓代碼更健壯)。

 

但是!另一方面講,有一個很重要的問題,這些庫的作者也是和我們一樣的程序員,他們也會犯錯,他們無法預知所有的使用場景。還有一點更重要 - 有時候知道底層原理更好些-知其然還要知其所以然。只為更好的理解“系統”是如何工作的。

認識 desing support library

目前有許多探討design support library的文章:

這就是為什么本文只會蜻蜓點水般的講解從自定義實現到Design Support Library實現的過渡。順便,我們也會看到我們可以節省多少代碼。

NavigationView

當InstaMaterial遇到Design Support Library

Material design準則對于默認的Navigation drawer定義非常清楚。因為有了NavigationView,整個菜單可以直接在res/menu/{filename}.xml中實現。我們只需要在Activity中使用如下代碼而不是自定義view結構:

<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/flContentRoot"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/vNavigation"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#ffffff"
        app:headerLayout="@layout/view_global_menu_header"
        app:itemIconTint="#8b8b8b"
        app:itemTextColor="#666666"
        app:menu="@menu/drawer_menu" />

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

NavigationView有兩個非常重要的屬性: app:headerLayout 和 app:menu。第一個定義了被用作navigation menu頭部的自定義view布局。第二個定義了誰來提供菜單元素。下面展示了我們app中菜單的實現:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:id="@+id/menu_group_1">
        <item
            android:id="@+id/menu_feed"
            android:icon="@drawable/ic_global_menu_feed"
            android:title="My Feed" />
        <item
            android:id="@+id/menu_direct"
            android:icon="@drawable/ic_global_menu_direct"
            android:title="Instagram Direct" />
        <item
            android:id="@+id/menu_news"
            android:icon="@drawable/ic_global_menu_news"
            android:title="News" />
        <item
            android:id="@+id/menu_popular"
            android:icon="@drawable/ic_global_menu_popular"
            android:title="Popular" />
        <item
            android:id="@+id/menu_photos_nearby"
            android:icon="@drawable/ic_global_menu_nearby"
            android:title="Photos Nearby" />
        <item
            android:id="@+id/menu_photo_you_liked"
            android:icon="@drawable/ic_global_menu_likes"
            android:title="Photos You've Liked" />
    </group>
    <group android:id="@+id/menu_group_2">
        <item
            android:id="@+id/menu_settings"
            android:title="Settings" />
        <item
            android:id="@+id/menu_about"
            android:title="About" />
    </group>
</menu>

在我們的app中我們還定義了一個BaseDrawerActivity,每個繼承自它的activity都會自動添加navigation drawer 。這里是BaseDrawerActivity的源碼。

最后,我們看一看this commit。自定義navigation drawer 視圖,menu adapter以及布局,這些事情都變得沒有必要了。

Floating Action Button

當InstaMaterial遇到Design Support Library

浮動操作按鈕可能是Material Design規范中最引人注目的UI元素了。但是直到現在它的實現方式都不是很明確。圓形,陰影(也是圓形的),波紋(ripple)效果,elevation(層次感)。現在所有這些library都已經提供了。我們只需要把FloatingActionButton直接放在.xml布局文件中就可以了:

<android.support.design.widget.FloatingActionButton
    android:id="@+id/btnCreate"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|right"
    android:layout_marginBottom="@dimen/btn_fab_margins"
    android:layout_marginRight="@dimen/btn_fab_margins"
    android:src="@drawable/ic_instagram_white"
    app:borderWidth="0dp"
    app:elevation="6dp"
    app:pressedTranslationZ="12dp" />

就是這么簡單。我們不需要為Lollipop和Lollipop之前的設備準備兩種drawable,不需要尋求圓形陰影的解決辦法等等。我們再也不希望用不常用的方式去自定義它,所有的都為我們做好了。

值得一提的是FloatingActionButton默認實現了兩種尺寸-mini和普通(默認),分別用app:fabSize="mini" 和 app:fabSize="normal"定義。

CoordinatorLayout

這是很多程序員的期望已久的控件-尤其是那些致力于交互式布局的程序員。CoordinatorLayout是一個新的ViewGroup布局,用于幫助其子view之間的協作與交互。實際使用中最常用的用例可能是ScrollView和其他view之間的交互了。這也是我們想以此為開始的東西-我們希望在向下滾動的時候隱藏Toolbar,向上滾動的時候則顯示。

AppBarLayout

AppBarLayout則是另一個幫助我們實現此效果的另一個ViewGroup。它為toolbar賦予了幾個默認的behavior,可以用于和任意的滾動視圖交互。下面是一個演示了如何使用AppBarLayout與CoordinatorLayout聯系起來的布局示例:

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rvFeed"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBarLayout"
        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"
            app:elevation="@dimen/default_elevation"
            app:layout_scrollFlags="scroll|enterAlways"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

            <ImageView
                android:id="@+id/ivLogo"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:scaleType="center"
                android:src="@drawable/img_toolbar_logo" />
        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>

</android.support.design.widget.CoordinatorLayout>

這里有幾個重要的事情:

  • Toolbar中的app:layout_scrollFlags="scroll|enterAlways" 意味著AppBarLayout的這個子view可以響應滾動事件(view隨著滾動事件滾動)同時任意向下的滾動都將讓view變的可見(快速返回模式)。

  • app:layout_behavior="@string/appbar_scrolling_view_behavior"在RecyclerView中有這個屬性意味著這個滾動視圖將會發送滾動事件到AppBarLayout的子view。

結果

當InstaMaterial遇到Design Support Library

簡單,是吧?現在我們來看看使用其余的scrollFlags可以做出啥效果。

Snackbar

當InstaMaterial遇到Design Support Library

Snackbar被認為是一種更成熟的Toast實現。它也被用作可以提供額外操作(比如針對當前操作的“Undo”操作)的短消息提示。此外它還可以和嵌套在CoordinatorLayout中的其他view交互。

其構造和Toast一樣簡單:

public void showLikedSnackbar() {
    Snackbar.make(clContent, "Liked!", Snackbar.LENGTH_SHORT).show();
}

make() 方法的第一個參數是一個view,從該view找到一個parent。意味著Snackbar將向上走一遍這個view樹,尋找一個合適的父親。如果是CoordinatorLayout,Snackbar將可以和FloatingActionButton交互。同時它還變的可以通過劃動刪除。

TabLayout

當InstaMaterial遇到Design Support Library

谷歌總算給了我們一個比較摩登的tabbar實現方法 - 具有橫向滾動,圖標或者文字,簡單的tab indicator自定義,tab的gravity,波紋效果等等。這就是TabLayout,不多不少。

tab_layout.xml 

<android.support.design.widget.TabLayout
    android:id="@+id/tlUserProfileTabs"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:background="?attr/colorAccent"
    app:tabGravity="fill"
    app:tabIndicatorColor="#5be5ad"
    app:tabIndicatorHeight="4dp"
    app:tabMode="fixed" />

TabLayout.java 

private void setupTabs() {
    tlUserProfileTabs.addTab(tlUserProfileTabs.newTab().setIcon(R.drawable.ic_grid_on_white));
    tlUserProfileTabs.addTab(tlUserProfileTabs.newTab().setIcon(R.drawable.ic_list_white));
    tlUserProfileTabs.addTab(tlUserProfileTabs.newTab().setIcon(R.drawable.ic_place_white));
    tlUserProfileTabs.addTab(tlUserProfileTabs.newTab().setIcon(R.drawable.ic_label_white));
}

CollapsingToolbarLayout

在本文的最后我們將看看CollapsingToolbarLayout。自從Toolbar成為比ActionBar更普遍的解決方法的時候,出現了許多和此view相關的UI效果-視差(parallax),動態的標題大小以及位置,可以擴展或者折疊 的內容等等。這就是CollapsingToolbarLayout可以為我們做的事情。

而且一樣的是全 .xml布局配置-完全沒有java代碼。

下面是替換UserProfileAdapter的實現(不重要的代碼隱藏了):

<android.support.design.widget.AppBarLayout
    android:id="@+id/appBarLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:contentScrim="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <LinearLayout
            android:id="@+id/vUserProfileRoot"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            app:layout_collapseMode="parallax">

        </LinearLayout>

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_collapseMode="pin"
            app:layout_scrollFlags="scroll|enterAlways"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.CollapsingToolbarLayout>

    <android.support.design.widget.TabLayout
        android:id="@+id/tlUserProfileTabs"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="?attr/colorAccent"
        app:tabGravity="fill"
        app:tabMode="fixed" />

</android.support.design.widget.AppBarLayout>

activity_user_profile.xml的全部代碼在這里

重點?

  • app:layout_scrollFlags="scroll|exitUntilCollapsed" 意味著在滾動到頂部之前不固定的view會一直折疊起來。固定的view(Pinned views)(具有 app:layout_collapseMode="pin"屬性的Toolbar ) 將持不可觸摸狀態。

  • app:layout_collapseMode="parallax" 意味著我們的view將會以視差方式折疊。CollapsingToolbarLayout中的app:contentScrim="?attr/colorPrimary"意味著折疊的view會被這個顏色所遮擋。

現在看一眼最終的效果:

當InstaMaterial遇到Design Support Library

這就是今天的全部內容。我們只是用新的view或者效果來更新了InstaMaterial,比如Snackbar,FloatingActionButton, TabLayout, CoordinatorLayout, AppBarLayout and CollapsingToolbarLayout。它們全部都是Android Design Support Library提供的。

源碼

全部的項目代碼可以在Github repository找到。

作者

Miroslaw Stanek


 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!