天天看點

Material Design Learning in Udacity

Tangible Surfaces

Surfaces that we can touch and react to our input.

Affordances

一個對象,隻是看着它,就能夠用直覺去感覺并且明白應該去如何操作,這樣的特性被稱為

Affordances

.

一如生活中的紙張和蘋果,你可以折疊/撕碎,你可以遠抛和嚼上一口.

在程式中實作這樣的特性不是這麼容易的事情,但我們仍然可以采取

Affordances

tangibility

的一些原則來讓我們的應用變得更直覺(

intuitive

).

Surface introduction

在MD(材料設計,Material Design)中,我們将UI想象成是由一張張的紙張重疊而成的平面,螢幕上的一切都在這個平面上.

這些平面具有小部分的實體特性,用以展示事物間的相關性和差異性.

這利用了我們快速識别物體的本能.

Just the smallest set of real world cues are enough to express a lot of meaning

各個平面之間層層疊加,并且在低層次的平面上投下陰影.

一般來說,距離我們越近的物體,越容易引起我們視覺上的注意.

我們利用陰影來表達一個平面相對于另一個平面的高度.

Using Surfaces

經驗來說,如果是同一内容的條目,放置在同一個平面進行浏覽和對比是相當重要的(即不要讓ListView裡面的每個Item都是一個CardView這樣隔離開來);

相反,如果展示的是不同類型的條目,将它們放置在各自的平面上是更為合适的.

引導注意力

Directing Attention

是非常強有力的一項技術,但也需要恰當去使用.

就像上面說的,盡管對于不同類型的條目應該使其在各自的平面上,但是界面上出現太多分離平面的時候,會導緻人注意力的渙散.

又是經驗之談,盡量不要在螢幕上一次展現超過5個以上的平面

Implements Surfaces

平面從本質上來講是一個投射陰影的容器.

在XML檔案中,設定高度的屬性是

android:elevation="4dp"
           

系統會根據此自動繪制陰影.

高度值越大,陰影越深,也越加分散.

Question: What’s the standard elevation for an app bar?

Objects in material design possess similar qualities to objects in the physical world.

Find answer in Material Design

Elevation(dp) Component
24 Dialog
24 Picker
16 Nav drawer
16 Right drawer
16 Modal bottom sheet
12 Floating action button(FAB-pressed)
9 Sub menu(+1dp for each sub menu)
8 Botton navgation bar
8 Menu
8 Card(when picked up)
8 Raised button(pressed state)
6 Floating action button(FAB-resting elevation)
6 Snackbar
4 App bar
3 Refresh indicator
3 Quick entry/Search bar(scrolled state)
2 Card(resting elevation)
2 Raised button(resting elevation)
2 Quick entry/Search bar(resting elevation)
1 Swtich

What’s the FB?

一個色彩鮮豔,同時浮于所有其他内容的上方.強烈提示使用者可通過其進行一些操作.

一般的直徑是40/56dp,靜止高度為6dp,按下時的高度為12dp.

正因為FAB是一個對于吸引使用者注意力具有強烈效果的控件,是以一定要注意避免過度使用它.一般而言在一個頁面中隻需要一個FAB即可.

并非每個螢幕都必須要一個FAB,如果你不能确定在目前的螢幕上的哪個操作是更應該設定給FAB的,那更好的選擇可能是你并不需要一個FAB(手動滑稽).

Add a FAB to your project

首先為項目添加依賴:

dependencies {
    compile fileTree{dir: 'lib', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
    compile 'com.android.support:design:22.2.0'
}
           

(版本号應該使用最新的)

在XML中,一個FAB可以是這樣的(注意其中的幾個關鍵屬性)

<android.support.design.widget.FloatingActionButton
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"

    app:fabSize="normal"
    app:elevation="6dp"
    app:pressedTranslationZ="12dp"
    app:layout_gravity="end"

    android:layout_margin="16dp"
 />
           

如果直接運作,可能會報錯.

因為FAB需要AppCompat的支援來擷取樣式資訊,是以需要把你的Theme改成類似

Theme.AppCompat.Light

這樣的類型以擷取支援.

Surface Feedback

在MD中,對于觸摸的視覺回報主要有兩種形式:

  1. 波紋效果.

    從指尖點選的位置開始,一直延伸到所在平面的邊緣結束.而對于那些沒有邊界的元素,波紋将延伸地足夠遠以使使用者感覺到元素的大小.

    又是我們也稱其為

    ink ripple

    ,因為它是平面上泛開的數字墨水,就像一滴墨水滴在紙上然後散開一樣.

    這種始于使用者指尖的發散性動畫效果,是MD設計風格裡面很重要的一部分.

    這種波紋效果,不僅使使用者感受到自己控制着UI,同時也提供了更好的體驗.

  2. 擡升效果.

    一如FAB的高度設定,在平時是6dp,而當你點選的時候,會擡升到12dp.就好像你的觸摸吸引了該平面一樣.這也給使用者提供了不一般的體驗.

Add the Ripple/Elevation to FAB

在support:design支援庫中已經有一個實作好了的FAB,具有波紋效果和高度效果.

但是自己實作一個相同效果的FAB,對于加深了解來說是很重要的.

FAB的核心部件是一個ImageView,也可以通過使用ImageButton來簡化操作.

src

屬性的圖像,選擇矢量圖

<vector>

更有利于适配不同的螢幕

http://schemas.android.com/apk/res/android"
    android:height="24dp"
    android:width="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path android:fillColor="#fff" android:pathData="M19,13H13V13H11V13H5V11H11V5H13V11H19V13Z" />
</vector>
           

background

屬性設定

<shape>

可以讓方形的圖示變為圓形:

<?xml version="1.9" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="?attr/colorAccent" />
</shape>
           

然後我們來添加波紋效果,這需要将我們剛設定的形狀标簽,用波紋屬性來包裹:

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:colorControlHighlight">
    <item>
        <shape android:shape="oval">
            <solid android:color="?android:colorAccent" />
        </shape>
    </item>
</ripple>
           

下面則是要添加觸摸時的擡升效果(a state list animator),

android:steateListAnimation="@anim/fab_raise"

:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="true" android:state_pressed="true">
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="8dp"
            android:valueType="floatType"
            />
    </item>
    <item>
        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="0dp"
            android:valueType="floatType"
            />
    </item>
</selector>
           

Transform Paper

紙張和墨水的隐喻方式盡管有效,但切記不要被現實中的屬性所束縛住.

你能在程式裡實作的效果,比你想象的要更多.

盡可能帶給使用者,一種沉浸式的應用使用體驗.

Create Transform Of Paper

最為簡單常見的一個效果就是

Circular Review

就是當點選RecycleView中的一個條目時,會動效并顯示别的内容.

具體代碼見此SimplePaperTransformations

Response For Scrolling

A seam to step transition

縫到階的過渡:

兩相鄰平面先是形成一條縫,

當較低位置的平面從另一個下面滑過時,就形成了一個階梯

CoordinatorLayout
    |---AppBarLayout(android:layout_height="168dp")
    |       |---CollapsingToolbarLayout(app:layout_scrollFlags="scroll|exitUntilCollapsed")
    |               |---Toolbar(android:layout_height="56dp")
    |---RecycleView(app:layout_behavior=...)
           

具體代碼見此ScrollEventsDemo

Bold Graphic Design

An homage to great typography and print layout.

Gestalt Principle

周圍世界的資訊十分豐富,是以相對應的人腦已經形成了一種快速認知的本能.

其中依靠抽象/聯想/對比等等,不一而足.

通過認知心理學(Cognitive Psychology)的研究,發現一種稱為格式塔的原理.

  1. 過往經驗法則(Law of Past Experience)

    早起的應用就是這樣,将現實事物用電子的形式展現,諸如秒表,記事本,等等.

    像是記事本應用上面的橫向,稱其為”拟物化細節”,這讓使用者感到更加熟悉和親切.

    但是随着移動裝置的增加,這類細節的重要性不斷下降,人們更希望使用那些偏離現實世界的應用.

  2. 接近法則(Law of Proximity)
  3. 相似法則(Law of Similarity)

元素之間的空間距離暗示了人們它們之間的相關性的高低.

Grid and Keylines

圖示,間距,内外邊框,都是8的倍數

而文字相關的,都是4的倍數

這些都是網格的作用

關鍵線則是用來讓相似控件有基準線可以對齊.

Color

It can be used to direct attention or imply hierarchy and structure.

大膽并且有針對性地使用顔色,不僅僅是為了美觀,

更是為了讓你的應用更易于使用.

Using Color

挑選一款顔色作為主色(Primary Color)來代表你的應用是極具有價值的.

它可以表現你的品牌定位和個性.

然後是一款強調色(Accent Color),更加鮮亮和飽和的顔色能引導使用者将注意力集中到特定的控件上,比如FAB.

材料設計為顔色指定了色度數值.深的數值大,淺的小.推薦500作為主色,同時加上A的顔色則是推薦作為強調色.

Using Palette

先建立一個colors.xml,裡面采取MD所列的名稱來命名顔色.

然後在styles.xml裡面指定主色/底色/強調色

xml中,帶有”?”的屬性,像是

android:background="?colorPrimary"

這樣的,是因為其引用的是一個本地屬性,也可以改寫成

android:background="?attr/colorPrimary"

這樣的格式.

Roboto

SP

scale-independent pixels

縮放獨立像素

16sp = 16dp @ 100% scale

16sp = 20dp @ 125% scale

使用sp可以友善那些視力上有困難的使用者,放大字型也不會模糊.

Font

Material Design Learning in Udacity
Material Design Learning in Udacity
Material Design Learning in Udacity

Choosing Fonts

在Roboto及其變體之外挑選字型,也絕非易事.

選擇的字型僅僅是易于閱讀同時和周圍形成良好對比還遠遠不夠,

字型的選擇會影響使用者對你的看法,以及他們做出的反應.

書寫體/圓體使應用看起來更随意,而方方正正的字型則給人一種井然有序的感覺,等等

需要注意的是:

  1. 不要在一緻的子產品中使用類似的字型造成困擾;
  2. 在不同裝置/分辨率上測試你選擇字型的适應性;
  3. 確定字型的選擇符合你應用的情感基調

Add Custom Font

在assets目錄下添加你的字型檔案.

如果是在片段中使用自定義字型,因為片段生命周期的緣故,需要在

onAttach()

裡面執行個體化字型:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    courgette = Typeface.createFromAsset(getActivity().getAssets(), "Courgette-Regular.ttf");
}
           

之是以這樣做的原因是,在執行個體化後到附着于Activity上之間有一小段間隔,如果在這個間隔之内就調用了諸如

tv.setTypeface(courgette);

的方法,就會出現異常.

Using Image

圖像,不僅帶給人視覺的體驗,更能觸及人的情緒,甚至是回想起味道.

使用的圖像将會強烈影響你的品牌效應.

使用的圖像往往分為三類:

  1. 照片(Photography)
  2. 插圖(Illustration)
  3. 圖示(Iconography)

針對内容時,照片是很好的選擇.

但尤其需要注意的是,提供充足分辨率的圖像,同時在不同裝置上測試它們,因為布局往往是不同的.

如果内容是抽象的,難以展示的,選擇插圖是一個好辦法.

插圖需要避免過度修飾,表述要清晰,同時盡量在一系列插圖之間保持一緻性,使其能夠互相關聯.

圖示的使用,是為了便于尋找.

Make Image More Pleasant

Using

ScaleType

to fix your image.

Circular Avatars

RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(), bitmap);
drawable.setCircular(true);
           

使用這個來建立圓形頭像圖檔.

Aspect Ratio Image View

public class ThreeTwoImageView extends ImageView {
    ...
    ...
    ...(Three Construction)
    @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        int threeTwoHeight = MeasureSpec.getSize(widthSpec) * 2 / 3;
        int threeTwoHeightSpec = MeasureSpec.makeMeasureSpec(threeTwoHeight, MeasureSpec.EXACTLY);
        super.onMeasure(widthSpec, threeTwoHeightSpec);
    }
}
           

這樣的iv視圖将會固定為3:2的寬高比.

Background Protect

Scrim Gradient

為了解決當背景圖檔顔色和在其上的文字顔色相近導緻看不見字的情況,

我們可以采取一層蒙版的方式.

<shape android:shape="rectangle">
    <gradient
        android:angle="-90"
        android:startColor="#000"
        android:centerColor="#000"
        android:endColor="#4d000000"
        android:type="linear" />
</shape>
           

然後我們使用一個

FrameLayout

,将這個蓋在我們的

ImageView

上面:

<FramgLayout ...>
    <ImageView ... />
    <View
        android:background:="@drawable/scrim"
        ... />
    <TextView
        android:layout_gravity="bottom"
        ... />
</FrameLayout>
           

這樣就可以改善視圖效果.

Meaningful Motion

Motion that guides and encourages the user.

Animations in Android

The Early Days Of Animations

AnimationSet animationSet = new AnimationSet(context, null);
    animationSet.addAnimation(new AlphaAnimation(1f, 0f));
    animationSet.addAnimation(new TranslateAnimation(0, 0, 0, -mButton.getHeight()));
    animationSet.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
    animationSet.setAnimationListener(new Animation.AnimationListener() {
        @Override public void onAnimationEnd(Animation animation) {
        mButton.setVisibility(View.GONE);
        startActivity(new Intent(MainActivity.this, SubActivity.class));
        overridePendingTransition(R.anim.activity_open_enter, R.anim.activity_open_exit);
        }
        ...
    });
    mButton.startAnimation;
           

或者可以在XML中定義動畫,通過如下方式引入:

Animation animationSet = AnimationUtils.loadAnimation(context, R.anim.slideoutbutton);
           

下面是

res/anim

slideoutbutton.xml`的檔案内容:

<set ...>
    <translate
        android:fromYDelta="0%"
        android:toYDelta="-100%" />
    <alpha
        android:fromAlpha="1"
        android:toAlpha="0" />
</set>
           

Android 4: ViewPropertyAnimator

mButton.animate()
       .alpha(0f)
       .translationY(-mButton.getHeight())
       .setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime))
       .withEndAction(new Runnable() {
           @Override
           public void run() {
               ...
           }
        });
           

Android 4: ObjectAnimator

ObjectAnimator.ofObject(
    mButton,
    "textColor",
    new ArgbEvaluator(),
    Color.BLACK,
    Color.RED)
    .setDuration(1000)
    .start();
           

這對文字的顔色做出了動畫設計.

Introduce of TransitionManager

Slide slide = new Slide();
slide.setSlideEdge(Gravity.TOP);
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
TransitionManager.beginDelayedTransition(root, slide);
imageView.setVisibility(View.INVISIBLE);
           

這一段的API并不是很懂…

Some New Animation(API 4.4)

像是在一個頁面下,兩個場景的過渡,其實是使用了兩套XML

然後使用

TransitionManager

來進行切換:

TransitionManager.go(
    Scene.getSceneForLayout(
        (ViewGroup) findViewById(R.id.root),
        R.layout.activity_main_scene_info,
        MainActivity.this)
    );
           

如果沒有特别指定的話,系統會自動為你生成合适的效果.

如果想要自定義的話,在XML中描述動畫效果,然後傳遞給TransitionManager:

TransitionManager.go(
    Scene.getSceneForLayout(
        (ViewGroup) findViewById(R.id.root),
        R.layout.activity_main_scene_info,
        MainActivity.this)
    ),
    TransitionInflater.from(this)
        .inflateTransition(R.transition.defaultToInfo));
           

Animation In Lollipop

Activity的退出和顯示,可以做成兩個動畫來顯示:

Exit Transition

res/transition/grid_exit.xml
<explode xmlns... />

res/values/styles.xml
<style name="AppTheme.Home">
    <item name="android:widnowExitTransition">
        @transition/grid_exit</item>
</style>
           

以上是Exit_Activity的動效,然後在代碼中使用它:

GridActivity.java
Bundle bundle = ActivityOptions.
    makeSceneTransitionAnimation(this).toBundle();
context.startActivity(intent, bundle);
           

然後:

res/values/styles.xml
<style name="AppTheme" ...>
    <item
        name="android:windowContentTransitions">
        true</item>
</style>
(如果使用的是MD的Theme或者是AppCompat,這項是已經自動設定了的)
           

Enter Transition

DetailActivity.java
Slide slide = new Slide(Gravity.BOTTOM);
slide.addTarget(R.id.description);
slide.setInterpolator(
    AnimationUtils.loadInterpolator(this,
        android.R.interpolator.linear_out_slow_in));
slide.setDuration(slideDuration);
getWindow().setEnterTransition(slide);
           

API Check

code:
if (Build.VERSION.SDK_INT >=
    Build.VERSION_CODES.LOLLIPOP) {
    Slide slide = new Slide(Gravity.BOTTOM);
    ...
    getWindow().setEnterTransition(slide);
}

xml:
res/transition-v21/grid_exit.xml
...

res/values-v21/styles.xml
...
           

Re-enter

res/values/styles.xml
<style name="AppTheme" ...>
    <item
        name="android:windowContentTransitions">
        true</item>
    <item name="android:windowReenterTransition">
        @android:transition/slide_top</item>
</style>
           

Shared Element Transitions

當UI改變的時候,動效能幫助更好的說明這種改變,同時吸引使用者的注意力.

共享元素即是指在兩個界面中存在的相同的元素,

這樣在兩個頁面之間切換的時候,應該為其提供一種平滑的過渡效果.

共享元素過渡使用相同的通道來進行推動,那就是過渡架構

Transition Framework

.

Now to build this, it helps to understand a little bit about how the system works under the hood.

When we say we’re doing a shared element transition between two activities, we aren’t actually sharing any views in their hierarchy. Each activity has an independent view tree. What we’re doing, is passing information about the shared view.

Such as, its position and its size between the two. When the second activity launches, it sets a transparent background and hides all of its own view so that you can, so to speak, see through to the previous activity behind it. It then locates the shared view within its own hierarchy and alters its attributes to match those passed in from the launching activity and makes that single view visible.

It then runs animations to transition the shared view from this state to its natural position in the layout. As the transition progresses, the window background and the rest of the non-shared amids slowly fade in until they’re totally opaque.

想要在兩個視圖中定義設定共享内容,我們需要在XML中定義

transitionName

屬性:

layout/grid_item.xml
<ImageView
    ...
    android:transitionName=
        "@string/transition_photo" />

layout/activity_detail.xml
<ImageView
    ...
    android:transitionName=
        "@string/transition_photo" />
           

推薦是采用String資源檔案的方式來保證其一緻性.

然後,在Activity中,我們需要設定并指定共享元素:

GridActivity.java
Bundle bundle = ActivityOptions
    .makeSceneTransitionAnimation(
        this,
        sharedView,
        sharedView.getTransitionName()
        )
    .toBundle();
startActivity(intent, bundle);
           

為什麼這裡使用String而非id的方式來指明共享内容?

因為共享元素的過渡不僅僅是存在于單一應用之間,通過

publish

共享内容的名稱,可以在不同的應用間進行共享元素的過渡效果.

共享元素的過渡的動效是如何這樣生動地展現的?

Default Transition

Move.xml
<transitionSet>
    <changeBounds/>
    <changeTransform/>
    <changeClipBounds/>
    <changeImageTransform/>
</transitionSet>
           

如果想要實作自定義的動效:

Custom Shared Element Transition

<style name="AppTheme.Home">
    <item name="android:windowSharedElementEnterTransition>
        @transition/your_transition</item>
</style>
//-----------------
getWindow()
    .setSharedElementEnterTransition(yourTransition);
           

Instructive Motion

就像标簽頁之間切換的時候,給頁面增加一點不明顯的滑動動畫,這就是一種指導動畫,它以自己的動效暗示使用者可以通過滑動來操作頁面.

Material Design Learning in Udacity
Material Design Learning in Udacity
MainActivity.java
@Override
public void onEnterAnimationComplete() {
    super.onEnterAnimationComplete();
    final int startScrollPos = 
        getResources().getDimensionPixelSize(
            R.dimen.init_scroll_up_distance);
    Animator animator = ObjectAnimator.ofInt(
        mScrollView,
        "scrollY",
        startScrollPos)
        .setDuration(300);
    animator.start();
}
           

可惜的是,這隻在Android 5.0之後開始可用.

不過在早期版本,也可以進行僞造,設定啟動延時即可.

Design to Enhance the Experience

With great power comes great responsibility.

經驗來看,動畫一般是300ms

當然,也可以通過移動的距離,來制定動畫的時長

PS:經驗來看,大部分設計人員制定的動效時長其實都超過了使用者期望的時長…(好吐槽啊)

通過插值器來實作動效的加速度效果,同時在MD風格的設計當中,

加速和減速是不對稱的

往往采用的是”快出,慢進”的效果(Fast-out/Slow-in)

user-initiated change

Really really important in MD

 Coordinated Motion

現實世界中,很少有事物是完全線性運動的,是以曲線動效會比線性動效更加生動,但要小心這個效果會分散注意力.

尺寸變化有時會被誤認為是高度變化,比較好的方式是以不同的速率将寬高的變化做成動畫,這樣展現出來就不容易産生誤會了.

Gladden Detail

The detail are not the detail.

They make the design.

–Eames

無論何時,元素的狀态發生了改變,都應該為其制作動畫效果

不僅僅是大的區塊需要,為小細節制作動畫效果,能使過渡更加流暢和美觀.

After all, animating literally means bringing to life.

為了制作出這些富有樂趣的效果,我們需要看看

VectorDrawable

AnimatedVectorDrawable

這兩個類.

下面是一個

VectorDrawable

的例子:

<vector xmlns=...
    android:width="120dp"
    android:height="120dp"
    android:viewportWidth="24dp"
    android:viewportHeight="24dp">

    <path
        android:name="cross"
        android:pathData="M6.4,6.4 L17.6,17.6 M6.4,17.6 L17.6,6.4"
        android:strokeWidth="2dp"
        android:strokeLineCap="square"
        android:strokeColor="#999" />
</vector>
           

pathData

的資料實際上繪制了一個X的圖像

AnimatedVectorDrawable

允許你将一些屬性制成動畫,下面是能制成動畫的清單:

  1. Translate
  2. Scale
  3. Rotate
  4. Opacity
  5. Color
  6. Path
  7. Trim start/end
  8. Clip-path

前五項具有相當标準的動畫繪制屬性.

Path

,可以變換(morph),進而達到動畫的效果,比如将上面繪制的X變為✔.

同樣可以将這個與别的效果合并,比如旋轉,這樣會更加美觀一點.

形狀的變化有一個限制條件,就是各個形狀需要有相同數量的繪制指令,這樣才能在兩者之間進行插值.

當繪制一條路徑的時候,

Trim start/end

可以讓你通過裁減頭或者尾來繪制它的一部分(裁減效果)

Clip-path

,也即镂空效果,可以在你繪制的圖形中留出镂空的部分,進而制成動效.

### Implement AnimatedVectorDrawable

The tick to cross animation

第一步先建立兩個xml,用

<vector>

繪制的鈎和叉

res/drawanle/ic_tick.xml
<vector xmlns...
    android:width="120dp"
    android:height="120dp"
    android:viewportWidth="24"
    android:viewportHeight="24">

    <group
        android:name="groupTickCross"
        android:pivotX="12"
        adnroid:pivotY="12" >

            <path
                android:name="tick"
                android:pathData="M4.8,13.4 ..."
                android:strokeWidth="2"
                android:strokeLineCap="square"
                android:strokeColor="#999" />

    </group>

</vector>

res/drawanle/ic_cross.xml
<vector xmlns...
    android:width="120dp"
    android:height="120dp"
    android:viewportWidth="24"
    android:viewportHeight="24">

    <group
        android:name="groupTickCross"
        android:pivotX="12"
        adnroid:pivotY="12" >

            <path
                android:name="cross"
                android:pathData="M6.4,6.4 ..."
                android:strokeWidth="2"
                android:strokeLineCap="square"
                android:strokeColor="#999" />

    </group>

</vector>
           

一個十分有用的技巧是,建立一個資源檔案來儲存你動畫的所有屬性:

Material Design Learning in Udacity

這樣就可以從很多不同的地方直接引用到我們所需要的資料.

第二步是為每一個變化的步驟建立動畫效果.

res/animator/cross_to_tick.xml
<ObjectAnimator
    xmlns...
    android:propertyName="pathData"
    android:valueFrom="@string/path_cross"
    android:valueTo="@string/path_tick"
    android:duration="@integer/duration"
    android:interpolator="@android:interpolator/fast_out_slow_in"
    android:valueType="pathType" />
           

然後,建立一個可繪制的動畫矢量來将圖像與動畫連接配接起來

res/drawable/avd_cross_to_tick.xml
<animated-vector
    xmlns...
    android:drawable="@drawable/ic_cross">

    <target
        android:name="@string/cross"
        android:animation="@animator/cross_to_tick" />

    <target
        android:name="@string/groupTickCross"
        android:animation="@animator/rotate_cross_to_tick" />

</animated-vector>
           

最後,在ImageView中顯示繪制圖,并在适當的時候啟用動畫

SomeActivity.java
AnimatedVectorDrawable crossToTick = getDrawable(
    R.drawable.avd_cross_to_tick);
imageView.setImageDrawable(crossToTick);
crossToTick.start();
           

Adaptive Design

UIs that look great no matter how large or small the screen is.

Five Principles

  1. Balanced use of space
  2. Reading comfort
  3. Image quality
  4. Maintaining context
  5. Aesthetic

Break Point and Content

臨界點,就是在超過這個DPI值的時候,你的UI做出适應性改變.

MD設計規範裡有提供一些臨界點的範例,

但是,在适用于自己的應用時,要注意:

内容優先于範例的臨界點

對于内容的适應的第一優先的

是以,基于内容來決定臨界點,遠比基于裝置決定臨界點要來的更具有前瞻性.

Fix in Break Point

  1. Reveal, 在大螢幕上顯示那些你曾隐藏的内容(例如NavigationView)
  2. Divide, 将點選ListItem顯示的詳情頁和List一起顯示
  3. Reflow, 調整在不同螢幕上内容的顯示方式(如單列變成三列)
  4. Expand, 将内容顯示的平面拓展一些,并引入外邊框來防止螢幕看起來太寬

Implement Adapter Design

最簡單的方法莫過于建立一個布局,并放置在比如

res/layout-w6000dp

這樣的的資源目錄下.

但是這樣的方法,必然存在大量重複的代碼,在布局檔案多了以後,代碼的維護問題就會很嚴重.

解決方式之一是采用

<include>

:

Material Design Learning in Udacity

同時,對布局中的整數資源,可以同樣采用

w600dp

限定符:

Material Design Learning in Udacity

對于采用的不同布局,可以在Adapter中根據整數資源的不同來進行判斷:

Material Design Learning in Udacity

同時,不僅僅有整數資源,還有布爾類型的資源:

Material Design Learning in Udacity

對于一些距離上的值的改變,同樣運用這樣的技術,可以最大程度上改善代碼的重複率:

Material Design Learning in Udacity

下面就是一個例子,防止在較大螢幕上導緻的按鈕拉伸過長:

注意的是僅僅

match_parent

不會在資源檔案中起作用,因為特殊值-1是沒有機關的,是以需要添加

<item>

到你的尺寸檔案中,這樣就可以引用了

Material Design Learning in Udacity

同樣的,對于基準線,也是一樣的道理:

Material Design Learning in Udacity

Theme Change

Material Design Learning in Udacity

Ending Wrods

課程内容基本到這裡就結束了,

最後有一個課程結業作業.

不看不知道,一看才發現,竟然還推薦你學完另兩門課,知識才夠完成這個作業.

不禁感覺頭大(:зゝ∠)…

那就先這樣吧~