實現Instagram的Material Design概念設計(1)

發表於2015-06-08

幾個月前(本文發表於2014年11月10日),Google 釋出了app和web應用的 Material Design 設計準則之後,設計師 Emmanuel Pacamalan 釋出了一則概念視訊,演示了 Instagram 如果做成Material風格會是什麼樣子:

<embed>

這僅僅是停留在原型設計上,估計很多人都會問,能否用相對簡單的辦法實現它呢?答案是肯定的。不僅僅能實現,而且無須要求在最新的 Lollipop 版本,實際上幾年前 Android 4.0 釋出之後我們就可以實現這些效果了。

鑑於此,我決定開始寫一個新的系列文章,那就是如何將《INSTAGRAM with Material Design》視訊中的效果轉變成現實。當然,我們並不是真的要做一個Instagram應用,只是將介面做出來而已,並且儘量減少一些不必要的細節。

開始

本文將要實現的是視訊中前7秒鐘的效果。我覺得對於第一次嘗試來說已經足夠了,同時也考慮到了我們也要準備和配置我們的專案。

我想要提醒諸位的是,裡面的實現方法不僅僅是能實現,也是我個人最喜歡的實現方式。還有,我不是一個美工,因此專案中的所有圖片是直接從網上的公開渠道獲取的。(主要來源是 resources page )。

好了,下面是最終效果的兩組截圖和視訊(分別從 Android 4.0 和 5.0 上獲得的):

視訊地址:http://www.youtube.com/embed/rTucTiIlQDA

視訊地址:http://www.youtube.com/embed/fYhpc1LddHE

 

準備

在我們的專案中,將使用一些熱門的 Android 開發工具和庫。並不是所有這些東西本篇文章都會用到,我只是將它們準備好以備不時之需。

初始化專案

首先我們需要建立一個新的 Android 專案。我使用的是 Android Studio 和 Gradle 構建系統。最低版本要求sdk是15(即 Android 4.0.4 )。

然後我們將新增一些依賴。沒什麼好講的,下面是 build.gradle 以及 app/build.gradle 檔案的程式碼:

build.gradle

簡而言之,我們有如下工具:

  • 一些相容包(CardView, RecyclerView, Palette, AppCompat),我喜歡使用最新的控制元件。當然你完全可以使用 ListView、Actionbar 甚至 View/FrameView 來替代,但是為什麼要這麼折騰?
    • ButterKnife – View註解工具簡化我們的程式碼。(比方說不再需要寫 findViewById() 來引用 View,以及一些更強大的功能,比如 onClick() 等等)。
    • Rebound – 我們目前還沒有用到,但是我以後肯定會用它。這個 Facebook 開發的動畫庫可以讓你的動畫效果看起來更自然。(它提供了一些工具使用彈性動畫,從 Facebook 的 Messager 的 Chat Heads 中你可以看到他們是如何展示的,我確定你希望在你的下一個專案中使用它)
    • TimberHugo – 對這個專案而言並不是必須的,我僅僅是用它們列印log日誌。

圖片資源

本專案中將使用到一些 Material Design 的圖示資源。應用程式圖示來自於 NSTAGRAM with Material Design視訊,這裡 是專案的全套資源。

樣式

我們從定義app的預設樣式開始。同時為 Android 4.0 和 5.0 定義 Material Desing 樣式的最簡單的方式是直接繼承 Theme.AppCompat.NoActionBar 或者 Theme.AppCompat.Light.NoActionBar 主題。為什麼是 NoActionBar?因為新的sdk中為我們提供了實現 Actionbar 功能的新模式。本例中我們將使用 Toolbar 控制元件,Toolbar是比 ActionBar 更好更靈活的解決方案。我們不會深入講解這個問題,但你可以去閱讀 Android開發者部落格 AppCompat v21

根據概念視訊中的效果,我們在 AppTheme 中定義了三個基本色調:

styles.xml

colors.xml

關於這三個顏色的含義,你可以看這裡 Material Theme Color Palette documentation

Layout

佈局

專案目前主要使用了3個主要的佈局元素:

  • Toolbar – 包含導航圖示和應用程式logo的頂部bar
    • RecyclerView – 用於顯示feed
    • Floating Action Button – 一個實現了 Material Design 中 action button pattern的 ImageButton。

在開始實現佈局之前,我們先在 res/values/dimens.xml 檔案中定義一些預設值:

dimens.xml

這些值的大小是基於 Material Design 設計準則中的介紹。

現在我們來實現 MainActivity 中的layout:

activity_main.xml

稍微解釋一下上面的程式碼:

  • 關於 Toolbar 最重要的特徵是它現在是 activity 中 layout 的一部分,而且繼承自 ViewGroup,因此我們可以在裡面放一些UI元素(它們將利用剩餘空間)。本例中,它被用來放置logo圖片。同時,因為 Toolbar是比 Actionbar 更靈活的控制元件,我們可以自定義更多的東西,比如設定背景顏色為colorPrimary(否則 Toolbar 將是透明的)。
  • RecyclerView 雖然在 xml 中用起來非常簡單,但是如果 java 程式碼中沒有設定正確,app是不能啟動的,會報 java.lang.NullPointerException 異常(原因是沒有配置好 LayoutAdapter,它負責排程 RecyclerView 中的每一項)。
  • Elevation(ImageButton中)屬性不相容API 21以前的版本。所以如果我們想做到 Floating Action Button 的效果,需要在 Lollipop 以及之前的裝置上使用不同的背景。

Floating Action Button

為了簡化 FAB 的使用,我們將用對 Lollipop 及之前的裝置使用不同的樣式:

  • FAB for Android v21:

  • FAB for Android pre-21:

我們需要建立兩個不同的xml檔案來設定按鈕的背景: /res/drawable-v21/btn_fab_default.xml(Lollipop之後裝置) 和 /res/drawable/btn_fab_default.xml(Lollipop之前的裝置)

drawable-v21/btn_fab_default.xml

 _drawable/btn_fab_default.xml

上面的程式碼涉及到兩個顏色的定義,在 res/values/colors.xml 中新增:

可以看到在 API 21 之前的裝置上顯示陰影有點複雜。不幸的是,在xml中達到真實的陰影效果沒有漸變方法。其他的辦法是使用圖片的方式,或者通過Java程式碼實現(參見creating fab shadow)。

Toolbar

現在我們來完成 Toolbar。我們已經有了背景和應用的logo,現在還剩下navigation以及menu選單圖示了。

關於navigation,不巧的是,在xml中 app:navigationIcon=”” 是不起作用的,而 android:navigationIcon=”” 又只能在Lollipop上有用,所以只能使用程式碼的方式了:

至於menu圖示,我們使用標準的定義方式就好了:

menu_main.xml

在 Activity 中 inflate 這個menu:

一切本應正常,但是正如我在 twitter 上提到的,Toolbar onClick selectors 有不協調的情況:

為了解決這個問題,需要做更多的工作,首先為 menu item (res/layout/menu_item_view.xml) 建立一個自定義檢視:

menu_item_view.xml

現在我們為 Lollipop 及之前的裝置分別建立 onClick 的selector,在 Lollipop 上有 ripple 效果:

drawable-v21/btn_default_light.xml

現在,專案中的所有的color應該是這樣子了:

colors.xml

最後我們應該將自定義檢視放到menu item中。在 onCreateOptionsMenu() 方法中:

以上就是 Toolbar 的所有東西。並且 onClick 的按下效果也達到了預期的效果:

Feed

最後需要實現的是feed,基於 RecyclerView 實現。我們需要設定兩個東西:layout manager( RecyclerView 需要知道如何管理每一個item)和 adapter(提供這些item)。

首先要做的很簡單,因為這裡其實只是想實現 ListView 的效果,所以直接用 LinearLayoutManager 就行了。其次,我們需要做更多的事情,但是沒有捷徑去實現這些。

我們首先從item的佈局開始(res/layout/item_feed.xml):

item_feed.xml

在上面的程式碼中:

  • CardView – 在我們的每一個list item周圍包裝成圓角和陰影輪廓(這在 Android API 21及以前都可以實現)
    • ImageView 對應於feed元素的設計( SquaredImageView 是一種 ImageView 的實現,它具有整齊的dimensions)

FeedAdapter 也非常簡單:

FeedAdapter.java

沒什麼特別之處需要說明。

通過以下方法將他們放在一起:

下面是整個 MainActivity 類的原始碼:

MainActivity.java

當你在裝置上build並執行應用程式之後,你應該看到如下畫面:

  • Android Lollipop:

  • Android pre-21:

動畫

最後一件也是最重要的事情就是進入時的動畫效果,再瀏覽一遍概念視訊,可以發現在主 Activity 啟動的時候有如下動畫,分成兩步:

  • 顯示 Toolbar 以及其裡面的元素
    • 在 Toolbar 動畫完成之後顯示 feed 和 floating action button。

Toolbar 中元素的動畫表現為在較短的時間內一個接一個地進入。實現這個效果的主要問題在於navigation圖示的動畫,navigation圖示是唯一一個不能使用動畫的,其他的都好辦。

Toolbar animation

首先我們只是需要在activity啟動的時候才播放動畫(在旋轉螢幕的時候不播放),還要知道menu的動畫過程是不能在 onCreate() 中去實現的(我們在 onCreateOptionsMenu() 中實現)。

MainActivity 建立一個布林型別的變數 pendingIntroAnimation,在 onCreate() 方法中初始化:

onCreateOptionsMenu() 中實現:

在我們啟動程式之後,startIntroAnimation() 將只被呼叫一次。

現在該來準備Toolbar中元素的動畫了,也非常簡單。很好的一點就是保持注意力,一般情況下,動畫由一下兩步組成:

  • 準備 – 我們為每一個動畫元素建立初始狀態。如果我們希望展現擴充套件動畫,我們需要確保我們的每一項是隱藏的。
    • 動畫 – 這一步我們的view會進行動畫至最終狀態或位置。

好的,讓我們嘗試為 Toolbar 實現這兩個步驟:

在上面的程式碼中:

  • 首先我們將所有的元素都通過移動到螢幕之外隱藏起來(這一步我們將FAB也隱藏了)。
    • 讓Toolbar元素一個接一個的開始動畫。

當動畫完成,呼叫了 startContentAnimation() 開始 content 的動畫( FAB 和 feed 卡片的動畫)

Content動畫

在這一步中我們將讓 FAB 和 feed 卡片動起來。FAB 的動畫很簡單,跟上面的方法類似,但是 feed 卡片稍微複雜些。

  • startContentAnimation 方法:

FAB animation

  • FeedAdapter,包含 feed item 的動畫:

就是這些了!如果我們build並執行我們的專案,我們就會得到看到文章開頭展示的最終版本的效果。

原始碼

完整的程式碼在 Github repository

作者: Miroslaw Stanek

相關文章