Material Design学习(二)

Material Design学习(二)

上一篇介绍了一个Material Design的各种控件的使用,并且将其组成了一个完整的Demo,根据代码一步一步来我想收获应该是不少的。今天就学习下Material Design的其他方面的用法--动画

在Android L中新增了如下几种动画:

  • Touch feedback(触摸反馈)
  • Reveal effect(揭露效果)
  • Activity transitions (Activity转换效果)
  • Curved motion
  • View state changes(视图状态改变)
  • Animate Vector Drawables(可绘制矢量动画)

触摸反馈:

在Andorid L5.0中加入触摸反馈动画。
其中最明显的,最具代表的就是波纹动画,必入点击按钮会从点击的位置产生类似于波纹扩散的效果。

Ripple(波纹效果)

当你使用了Material主题,波纹动画会自动应用在所有控件上,我们可以设置其属性来调整我们需要的效果。

首先创建一个Andorid studio的project,这里注意了你必须设置你的Minimum SDK至少在API21:Android5.0(Lollipop)以上,因为这样你才可以使用Material主题,项目创建好了之后。在AndroidMainifest.xml作修改。

1
2
3
4
5
6
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Material">

将主题切换成Material主题即可。
之后修改activity_main.xml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.cui.materialthemedemo.MainActivity">


<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="使用了MaterialDesign主题,默认" />


<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:text="使用了MaterialDesign主题,设置了背景边界"/>


<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"

android:text="使用了MaterialDesign主题,设置了背景边界但可以超出边界"/>


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />

</LinearLayout>

修改好了后,尝试运行,有的人可能会报错。说你必须使用Theme.AppCompat theme的主题。这就还需要修改一个地方即将Activity继承自AppCompatAcitvity改为继承自Avtivity改完之后就能正常运行了,效果如下:

使用Material主题的Ripple效果

这种方法的好处想必大家也看出来了,代码量少,使用简单,操作方便。但它的缺点也十分的明显直接导致很少人这么使用,因为它必须得在API21以上的Android手机上才可以实现。还没有向后兼容的特点,故大多数人不会这么使用。

既然你不可以向后兼容,那就创建一个View可以实现这种效果不就好了嘛,所以有了另一种实现Ripple的方法

RippleEffect

要实现Ripple十分简单,你只需要在你的项目的build.gradle(Module:app)(另一个project,不再是上面那个了)中加入:

1
2
3
dependencies {     
compile 'com.github.traex.rippleeffect:library:1.3'
}

就可以了。修改你的activity_main.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.example.cui.rippledemo.MainActivity">


<android.support.v7.widget.Toolbar
android:id="@+id/actionbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_dark">


<RelativeLayout
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize">


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="RippeleDemo"
android:layout_marginLeft="25dp"
android:textColor="@android:color/white"
android:textSize="18sp"/>


<com.andexert.library.RippleView
android:id="@+id/more"
android:layout_width="?android:actionBarSize"
android:layout_height="?android:actionBarSize"
android:layout_toLeftOf="@+id/more2"
android:layout_margin="5dp"
app:rv_centered="true">


<ImageView
android:layout_width="?android:actionBarSize"
android:layout_height="?android:actionBarSize"
android:src="@android:drawable/ic_menu_edit"
android:layout_gravity="center"
android:padding="10dp"
android:background="@android:color/holo_blue_dark"/>

</com.andexert.library.RippleView>

<com.andexert.library.RippleView
android:id="@+id/more2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_margin="5dp"
app:rv_type="doubleRipple">


<ImageView
android:layout_width="?android:actionBarSize"
android:layout_height="?android:actionBarSize"
android:src="@drawable/ic_profil_plus"
android:layout_gravity="center"
android:padding="10dp"
android:background="@android:color/holo_blue_dark"/>

</com.andexert.library.RippleView>
</RelativeLayout>
</android.support.v7.widget.Toolbar>


<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="不在RippleView中哦"/>


<com.andexert.library.RippleView
android:id="@+id/rect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/actionbar"
android:layout_marginTop="20dp"
android:layout_marginLeft="30dp"
android:background="@drawable/selector_row"
app:rv_type="rectangle"
android:padding="20dp"
app:rv_zoom="true">


<TextView
android:id="@+id/rect_child"
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:textColor="@android:color/white"
android:textSize="18sp"
android:gravity="center"
android:text="Hello World"
android:background="@android:color/holo_green_light"/>


</com.andexert.library.RippleView>


<android.support.v7.widget.RecyclerView
android:layout_below="@id/rect"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />

</RelativeLayout>

RecyclerView里面可以加载RippleView的(ListView也是可以的),之后我就不贴关于RecyclerView适配的一些代码了。(大家如果要学习可以Git下别人的源码,上不去Github就在后面我po的CSDN的链接上下载吧)

MainAcitivity.java修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.andexert.library.RippleView;
import com.example.cui.rippledemo.adpater.RrippleRecyclerAdapter;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

private ArrayList<String> sourcesArrayList = new ArrayList<>();


private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final RippleView rippleView = (RippleView) findViewById(R.id.rect);

final TextView textView = (TextView) findViewById(R.id.rect_child);


final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar);

setSupportActionBar(toolbar);

rippleView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "onClick: Rect has clicked");
}
});

rippleView.setOnRippleCompleteListener(new RippleView.OnRippleCompleteListener() {
@Override
public void onComplete(RippleView rippleView) {
Log.d(TAG, "onComplete: RippleView has been Clicked");
}
});

textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "rect Chlid has been clicked" );
}
});


sourcesArrayList.add("Samsung");
sourcesArrayList.add("Android");
sourcesArrayList.add("Google");
sourcesArrayList.add("Asus");
sourcesArrayList.add("Apple");
sourcesArrayList.add("Samsung");
sourcesArrayList.add("Android");
sourcesArrayList.add("Google");
sourcesArrayList.add("Asus");
sourcesArrayList.add("Apple");
sourcesArrayList.add("Samsung");
sourcesArrayList.add("Android");
sourcesArrayList.add("Google");
sourcesArrayList.add("Asus");
sourcesArrayList.add("Apple");

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
RrippleRecyclerAdapter rippleRecyclerAdapter = new RrippleRecyclerAdapter(sourcesArrayList);
recyclerView.setAdapter(rippleRecyclerAdapter);
}


}

最终实现效果如下:

RipplEffect的使用

RippleDemo CSDN源码下载

Activity Transition

这个看上去效果赞极了,首先偷张图。
原图地址:https://github.com/lgvalle/Material-Animations

网上Android 5.0关于这个的介绍不是很详细,都是简单的将官方文档做翻译,不过有了官方文档可以自己测试倒是。

先贴主要的学习链接:

http://www.androiddesignpatterns.com/2014/12/activity-fragment-transitions-in-android-lollipop-part1.html

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0116/2320.html

https://github.com/lgvalle/Material-Animations

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0116/2310.html

方法一:使用Material Design主题
http://blog.csdn.net/a396901990/article/details/40187203这篇文章已经说的蛮清楚了,步骤说的不是很详细,这里我稍作补充,再来是有好奇心的我在测试的时候发现了一些问题。

首先Android studio创建一个新的Android project
接着再res/values下的styles.xml里作修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<style name="myTheme" parent="android:Theme.Material">  
<!-- 允许使用transitions -->
<item name="android:windowContentTransitions">true</item>

<!-- 指定进入和退出transitions -->
<item name="android:windowEnterTransition">@transition/explode</item>
<item name="android:windowExitTransition">@transition/explode</item>

<!-- 指定shared element transitions -->
<item name="android:windowSharedElementEnterTransition">
@transition/change_image_transform</item>
<item name="android:windowSharedElementExitTransition">
@transition/change_image_transform</item>
</style>

接着你就需要修改AndroidManifest.xml修改成
android:theme="@style/myTheme"
然后你需要新建一个Directory名为transition(在res文件夹下),然后在里面创建相应的文件。比如explode.xml.修改如下:

1
2
3
4

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<explode/>
</transitionSet>

你要写别的效果你可以再创建,修改里面得属性改成你需要的属性即可。

然后你需要创建一个新的Activity,创建好了就需要写两个Activity跳转的代码了。在MainActivity.java中设置按钮的点击事件跳转至另一个Activity。这里可以设置它的ExitTransition,在setContentView之前添加如下代码就行。

1
2
3
4
5
// 允许使用transitions  
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

// 设置一个exit transition
getWindow().setExitTransition(new Explode());

这里效果不是很好看出来,在你添加的另一个Activity中,同样在setContentView之前添加:

1
2
3
4
5
// 允许使用transitions  
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

// 设置一个exit transition
getWindow().setEnterTransition(new Explode());

然后你跳转时需要使用:

1
2
Intent intent1 = new Intent(MainActivity.this, ExplodeActivity.class);
startActivity(intent1, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

这样就可以很清楚的看到你跳转到另一个Activity时就会有Explode\Fade\Slide的效果(修改setEnterTransition里面的参数即可)。

这里我发现了一些问题,在style.xml中我们设置了windowEnterTransition而在代码中我们也setEnterTransition两个会不会起冲突?不会,你最后给Acitivity设置了什么Transition它就是什么。所以style.xml里应该算是设置默认setEnterTransition是什么Transition了。这也意味着可以通过xml和代码两种方式设置setEntransition。而且我发现只要你使用了主题android:Theme.Material就算你不在style.xml和代码里写Content Transition的相关设置代码,你只需要在跳转的时候使用:

1
startActivity(intent1, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

你就可以看到Activity Transition的效果了,默认是Fade效果。

下面介绍下Share Element Transition,上面的链接中有对这个做介绍的,大家看看我这里就不写了。

MainActivity.java的布局文件activity_main.xml中加入:

1
2
3
4
5
6
7
8
<Button
android:id="@+id/shareElememt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="shareElement测试按钮"
android:transitionName="shareView"
android:layout_weight="1"
/>

注意这里的一个属性android:transitionName="shareView"
在另一个你要共享元素传递到的那个Activity的布局文件中加入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="shareElement测试按钮"
android:transitionName="shareView"
android:layout_weight="1"
/>


<Space
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_weight="1"/>


<Space
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_weight="1"/>

<Space
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_weight="1"/>

可以看到我们这里的Button同样添加了上面的属性。正如链接里说的:
共享元素变换并不是真正实现了两个activity或者Fragment之间元素的共享,实际上我们看到的几乎所有变换效果中(不管是B进入还是B返回A),共享元素都是在B中绘制出来的。Framework没有真正试图将A中的某个元素传递给B,而是采用了不同的方法来达到相同的视觉效果。A传递给B的是共享元素的状态信息。B利用这些信息来初始化共享View元素,让它们的位置、大小、外观与在A中的时候完全一致。当变换开始的时候,B中除了共享元素之外,所有的其他元素都是不可见的。随着动画的进行,framework 逐渐将B的activity窗口显示出来,当动画完成,B的窗口才完全可见。

然后在MainActivity.java中设置Button的点击事件。

1
2
3
Intent intent4 = new Intent(MainActivity.this, ShareElememtActivity.class);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, v, "shareView" );
startActivity(intent4, options.toBundle());

同样在跳转的那个Activity中设置Button的点击事件。

1
2
3
4
5
6
7
8
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent4 = new Intent(ShareElememtActivity.this, MainActivity.class);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(ShareElememtActivity.this, v, "shareView" );
startActivity(intent4, options.toBundle());
}
});

最后效果如下:

image description

根据我的介绍应该可以一步一步拼凑出来,需要源码的同学可以去:
CSDN Transition Deom下载