###關於Material Design的基本概念
Material Design(簡稱MD):從Android5.0開始引入的,是一種全新的虛擬的設計語言(翻譯為“材料設計”),其實是谷歌提倡的一種設計風格、理念、原則。是擬物設計和扁平化設計一種結合體驗。還吸取了最新一些科技理念。這種設計風格是跨平臺:我們在網頁、IOS等地方也會經常看見。
例如:為了增加APP的層次感,可以通過設計View的Z軸座標大小來完成。我們要相容的時候,可以自己通過layerlist來實現。
####不同人員對於Material Design的認識
- 對於美工:遵循MD的介面設計、圖示合集。
- 對於產品經理:遵循MD介面設計、頁面的跳轉及動畫效果、互動設計。
- 對於開發人員:參與原型設計、輔助美工原型設計的素材準備。開發實現MD的設計----介面、動畫、轉場動畫等等。
其中,擼程式碼才是我們的重點。關於更多的介紹,可以去谷歌官網MD官網,當然國內也有翻譯好的文件,例如極客學院的文件:極客學院文件
###Material Design的使用及開發
谷歌開放以及收集了一些最新的開源的專案(很多是自己開發的),彙集到最新的support相容支援包以及最新的5.X API裡面。
- android-support-v4:最低相容到Android 1.6系統,裡面有類似ViewPager等控制元件。
- android-support-v7:appcompat、CardView、gridlayout、mediarouter、palette、preference、recyclerView(最低相容到3.0)
- v14 preference:設定頁面,可以通過配置檔案達到介面設計的效果。(用得比較少)
其中,v7包最低相容到Android 2.1的系統(不同的庫可能會高一些),這個工程可以讓開發人員統一開發標準,在任何的系統版本下保證相容性。(比如:Theme,value,佈局,新的控制元件,新的動畫特效實現)
######Tips1:現在開發幾乎都是相容到4.0,所以一般不會出現什麼相容性問題。 ######Tips2:相容包報錯問題:SDK升級:API升級、相容包的升級、工具升級。因為新的相容包可能引入了新的類、資源等等。
###Material Design初探--樣式的使用
首先我們需要使用v7包,為什麼要用appcompat專案呢?因為裡面是谷歌精心準備的---解決android碎片化開發蛋疼的問題,讓我們app編譯出來在各種高低版本之間、不同的廠商生產的ROM之間顯示出來的效果UI控制元件等有一較一致的體驗。
######Tips:SDK更新的歷史上幾個特別重要的版本:14(4.0)、19(4.4)、21(5.0),而appcompat裡面就對這幾個不同的版本做了相容,如果我們使用appcompat包,系統會自動根據最近的版本來使用。
現在用Android Studio建立專案的時候預設都是使用了v7包,因此我們可以使用v7包裡面的主題,並且配置相關的顏色,例如:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!--主色調,一般是指標題欄的顏色-->
<item name="colorPrimary">#f00</item>
<!--狀態列的顏色-->
<item name="colorPrimaryDark">#0f0</item>
<item name="android:statusBarColor">#0f0</item>
<!--頁面中所有UI控制元件的基本色調-->
<item name="colorAccent">#00f</item>
<!--以下幾個我們一般不會去配置-->
<!--背景顏色,但是我們一般不會配置,為了防止過度繪製-->
<item name="windowBackground">#fff</item>
<!--底部導航條的背景顏色-->
<item name="android:navigationBarColor">#f00</item>
<!--字型的基調顏色,實際發現沒有生效-->
<item name="textColorPrimary">#000</item>
</style>
複製程式碼
其中,各種顏色的對應關係如下圖所示:
######Tips1:某些屬性最低的API比較高,因此需要在不同的values資料夾中配置。 ######Tips2:上面只是為了方便寫Demo,直接把顏色寫死,實際專案中我們需要自己建立colors檔案。
####MaterialDesign相容性控制元件的使用
尤其是在appcompat-V7裡面有很多為相容而生的控制元件,這樣就可以做到高低版本和不同的ROM之間體驗一致!還可以配合appcompat的主題使用達到體驗一致性。例如:
-
android.support.v7.app.AlertDialog
-
進度條樣式設定 style="@style/Widget.AppCompat.ProgressBar.Horizontal"
-
SwipeRefreshLayout下拉重新整理
-
PopupWindow、ListPopupWindow、PopupMenu、Button、EditText等等
-
android.support.v7.widget.LinearLayoutCompat 給包裹在裡面的所有子控制元件新增間隔線(例如“關於頁面”的條目)
<android.support.v7.widget.LinearLayoutCompat android:layout_width="match_parent" android:layout_height="match_parent" app:divider="@drawable/abc_list_divider_mtrl_alpha" app:dividerPadding="10dp" app:showDividers="beginning|middle" android:orientation="vertical" > 複製程式碼
其中,showDividers屬性是設定在哪一個條目的位置顯示。比如只設定end,那麼只會在最後一個條目的下面新增分隔線。當然,你也可以設定padding,這裡就不贅述了。這裡有個坑就是,只能同時設定左右Padding。
######Tips:如果你的專案是使用了Material Design的話,推薦使用這些相容性控制元件,否則的話就不用這麼麻煩了。
####擴充套件--LinearLayoutCompat原始碼分析
看原始碼需要有目的去看,因此我們可以先猜想:
LinearLayoutCompat是如何做到給裡面的所有的child之間新增分割線的?
首先我們知道View的繪製會經過三個方法:onMearsue(測量自身和裡面的所有子控制元件),onLayout(擺放裡面所有的子控制元件),onDraw(繪製)
猜想:
- mearsuredWidth,mearsuredHeight會變大(加上分割線)
- 擺放子控制元件位置會有一定的體現(childView: left/top/right/bottom)
- onDraw繪製的時候也會有體現(childView: left/top/right/bottom)
先看onMearsue:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mOrientation == VERTICAL) {
measureVertical(widthMeasureSpec, heightMeasureSpec);
} else {
measureHorizontal(widthMeasureSpec, heightMeasureSpec);
}
}
複製程式碼
onMeasure分為了水平和豎直的情況,我們這次以豎直情況為例分析。我們猜想可以知道,在測量的時候,肯定加了分隔線的高度(只看核心程式碼):
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
//如果有分隔線,那麼測量的時候就加上分割線的Drawable的高度
if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {
mTotalLength += mDividerHeight;
}
}
}
複製程式碼
下面繼續來看onLayout:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (mOrientation == VERTICAL) {
layoutVertical(l, t, r, b);
} else {
layoutHorizontal(l, t, r, b);
}
}
複製程式碼
同理,我們只看layoutVertical:
void layoutVertical(int left, int top, int right, int bottom) {
for (int i = 0; i < count; i++) {
if (hasDividerBeforeChildAt(i)) {
childTop += mDividerHeight;
}
}
}
複製程式碼
也能看到,相關的程式碼。最後看繪製:
@Override
protected void onDraw(Canvas canvas) {
if (mDivider == null) {
return;
}
if (mOrientation == VERTICAL) {
drawDividersVertical(canvas);
} else {
drawDividersHorizontal(canvas);
}
}
複製程式碼
相信看到這裡就明白了。我們最後分析一些分割線是如何繪製上去的:
void drawVerticalDivider(Canvas canvas, int left) {
mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
mDivider.draw(canvas);
}
複製程式碼
mDivider其實是一個Drawable物件,畫之前需要設定一個繪製範圍,然後進行繪製即可。
更多的關於LinearLayoutCompat的使用,可以參考:
http://blog.csdn.net/zhangphil/article/details/48899585
如果覺得我的文字對你有所幫助的話,歡迎關注我的公眾號:
我的群歡迎大家進來探討各種技術與非技術的話題,有興趣的朋友們加我私人微信huannan88,我拉你進群交(♂)流(♀)。