(《Android群英传》读书笔记)
Android5.X开始使用新的设计风格Material Design来统一整个Android系统的界面设计风格,主要是以下三个方面的设计:
1、材料的形态模拟(真实地空间感);
2、更加真实地动画(视觉连贯性);
3、大色块的使用(时尚感和视觉冲击力)。
Material Design
官方英文文档:
http://www.google.com/design/spec/material-design/
中文版网站:
http://wiki.jikexueyuan.com/project/material-design/
中文版 GitHub 仓库:
https://github.com/1sters/material_design_zh_2
一、Material Design主题:
默认的三种主题:
<style name="AppTheme" parent="@android:style/Theme.Material">
<style name="AppTheme" parent="@android:style/Theme.Material.Light">
@android:style/Theme.Material.Light.DarkActionBar
当然还可以自定义Style的方式来创建自己的Color Palette颜色主题,从而实现不同的颜色风格。
<style name="AppTheme" parent="android:Theme.Material">
<item name="android:colorPrimary">#BEBEBE</item>
<item name="android:colorPrimaryDark">#FF5AEBFF</item>
<item name="android:navigationBarColor">#FFFF4130</item>
</style>
二、Palette (调色板,颜料)
使用Palette 来提取颜色,从而让主题能够动态的适应当前页面的色调,做到整个App颜色基调和谐统一。
(……待做……)
三、视图与阴影
1、阴影效果
在View的X、Y基础上增加一个新的属性Y,对应垂直方向上的高度变化。其Z值有两部分组成,elevation和translationZ。elevation是静态成员,translationZ可在代码中使用来实现动画效果。
Z = elevation + translationZ
在XML布局中使用如下代码设置View的视图高度:
android:elevation="10dp"
效果图如上一幅图所示。
在程序中,使用如下代码来动态的改变视图高度:
mTextView = (TextView) findViewById(R.id.tv_text);
mTextView.setTranslationZ(20);
也可以使用属性动画来为视图高度改变时增加一个动画效果。
if (flag) {
mTextView.animate().translationZ(100);
flag = false;
} else {
mTextView.animate().translationZ(0);
flag = true;
}
四、Tinting(着色)
它的使用很简单,只要在XML中配置好tint喝tintMode就好了。Tint通过修改图像的Alpha遮罩来修改图像的颜色。
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:elevation="20dp"
android:src="@drawable/ic_launcher" />
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:elevation="20dp"
android:src="@drawable/ic_launcher"
android:tint="@android:color/holo_blue_bright" />
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:elevation="20dp"
android:src="@drawable/ic_launcher"
android:tint="@android:color/holo_blue_bright"
android:tintMode="add"/>
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:elevation="20dp"
android:src="@drawable/ic_launcher"
android:tint="@android:color/holo_blue_bright"
android:tintMode="multiply" />
五、Clipping(裁剪)
它可以改变视图的外形。首先使用ViewOutlineProvider来修改outline,然后在通过setOutlineProvider将outline作用给视图。
<TextView
android:id="@+id/tv_rect"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:layout_margin="20dp"
android:elevation="1dp" />
<TextView
android:id="@+id/tv_circle"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:layout_margin="20dp"
android:elevation="1dp" />
View v1 = findViewById(R.id.tv_rect);
View v2 = findViewById(R.id.tv_circle);
// 获取outline
ViewOutlineProvider provider1 = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
// 修改outline为特定形状
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 30);
}
};
ViewOutlineProvider provider2 = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setOval(0, 0, view.getWidth(), view.getHeight());
}
};
// 重新设置形状
v1.setOutlineProvider(provider1);
v2.setOutlineProvider(provider2);
六、RecyclerView(列表)
它是ListView的升级版,它把ViewHolder的实现封装起来,用户只要实现自己的ViewHolder就好了,该组件会自动回收复用每一个item。
首先需要引入recyclerview的包。
(另写博客)
七、CardView(卡片)
它是一种容器类布局,可以设定卡片的大小与视图高度,还有圆角的角度。
首先引入cardview的依赖,同时在使用CardView的时候需要引入新的命名空间——xmlns:card_view=http://schemas.android.com/apk/res-auto
(另写博客)
八、Activity过渡动画
5.X有三种Transition类型:
进入和退出:1.explode(分解)——从屏幕中间进或出
2.slide(滑动)——从屏幕边缘进或出
3.fade(淡出)——改变视图的透明度添加或移除视图
共享元素:1.changeBounds——改变目标视图的布局边界
2.changeClipBounds——裁剪目标视图边界
3.changeTransform——改变目标视图的缩放比例和旋转角度
4.changeImageTransform——改变目标视图的大小和缩放比例
<TextView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:layout_margin="10dp"
android:background="@drawable/ic_launcher"
android:elevation="20dp" />
<Button
android:id="@+id/btn_explode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="以explode方式启动ActivityB" />
<Button
android:id="@+id/btn_slide"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="以slide方式启动ActivityB" />
<Button
android:id="@+id/btn_fade"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="以fade方式启动ActivityB" />
<Button
android:id="@+id/btn_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:transitionName="share"
android:onClick="onClick"
android:text="以共享元素启动ActivityB" />
ActivityA中:
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_explode:
i = new Intent(ActivityA.this, ActivityB.class);
i.putExtra("flag", 0);
startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
break;
case R.id.btn_slide:
i = new Intent(ActivityA.this, ActivityB.class);
i.putExtra("flag", 1);
startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
break;
case R.id.btn_fade:
i = new Intent(ActivityA.this, ActivityB.class);
i.putExtra("flag", 2);
startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
break;
case R.id.btn_share:
i = new Intent(ActivityA.this, ActivityB.class);
i.putExtra("flag", 3);
startActivity(i, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
break;
default:
break;
}
}
ActivityB中:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
int flag = getIntent().getExtras().getInt("flag");
// 设置不同的动画效果
switch (flag) {
case 0:
getWindow().setEnterTransition(new Explode());
break;
case 1:
getWindow().setEnterTransition(new Slide());
break;
case 2:
getWindow().setEnterTransition(new Fade());
getWindow().setExitTransition(new Fade());
break;
case 3:
break;
}
setContentView(R.layout.activity_b);
}
九、Material Design动画效果
1、Ripple(点击后的波纹效果)
有界波纹(波纹被限制在控件的边界中):
android:background=”?android:attr/selectableItemBackground”
无界波纹(波纹不会限制在控件边界中,会呈圆形发散出去):
android:background="?android:attr/selectableItemBackgroundBorderless"
2、Circular Reveal(圆形展示)
一个View以圆形形式展开、揭示出来。
圆形:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="@android:color/holo_blue_bright" />
</shape>
矩形:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@android:color/darker_gray" />
</shape>
布局:
<ImageView
android:id="@+id/iv_oval"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/oval" />
<ImageView
android:id="@+id/iv_rect"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/rect" />
Activity:
public class CircularReveal extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.avtivity_circular);
final View oval = this.findViewById(R.id.iv_oval);
oval.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Animator animator =
ViewAnimationUtils.createCircularReveal(
oval,
oval.getWidth()/2,
oval.getHeight()/2,
0,
oval.getWidth());
animator.setInterpolator(new AccelerateInterpolator());
animator.setDuration(2000);
animator.start();
}
});
final View rect = this.findViewById(R.id.iv_rect);
rect.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Animator animator =
ViewAnimationUtils.createCircularReveal(
rect,
0,
0,
0,
(float)Math.hypot(rect.getWidth(), rect.getHeight()));
animator.setInterpolator(new AccelerateInterpolator());
animator.setDuration(2000);
animator.start();
}
});
}
}
3、View state changes Animation
改变视图状态来设置一个视图的状态切换动画。
(1)、StateListAnimator
它作为视图改变时的动画效果,通常会使用Selector来进行设置。在5.0以前,通常是修改背景来达到反馈的效果,5.0之后,可以使用动画来作为视图改变的效果。
在XML中定义一个StateListAnimator:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="true">
<set>
<objectAnimator
android:propertyName="rotationX"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="360"
android:valueType="floatType"/>
</set>
</item>
<item
android:state_pressed="false">
<set>
<objectAnimator
android:propertyName="rotationX"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="0"
android:valueType="floatType"/>
</set>
</item>
布局文件中:
<Button
android:layout_width="200dp"
android:layout_height="200dp"
android:stateListAnimator="@drawable/state_list_animator" />
在代码中也可以使用如下代码:
调用AnimationInflater.loadStateListAnimator(),通过View.setStateListAnimator()方法将动画加载到视图上。
运行后点击按钮,发现按钮会旋转360°,离开按钮,按钮又会倒转360°。
(2)、animated-seletor
它是一个状态改变的动画效果。
首先需要一组图:
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/state_on"
android:state_checked="true">
<bitmap android:src="@drawable/ic_done_anim_030" />
</item>
<item android:id="@+id/state_off">
<bitmap android:src="@drawable/ic_plus_anim_030" />
</item>
<transition
android:fromId="@+id/state_on"
android:toId="@+id/state_off">
<animation-list>
<item android:duration="50">
<bitmap android:src="@drawable/ic_plus_anim_000" />
</item>
<item android:duration="50">
<bitmap android:src="@drawable/ic_plus_anim_001" />
</item>
……
<item android:duration="50">
<bitmap android:src="@drawable/ic_plus_anim_030" />
</item>
</animation-list>
</transition>
<transition
android:fromId="@+id/state_off"
android:toId="@+id/state_on" >
<animation-list>
<item android:duration="50">
<bitmap android:src="@drawable/ic_done_anim_000" />
</item>
<item android:duration="50">
<bitmap android:src="@drawable/ic_done_anim_001" />
</item>
……
<item android:duration="50">
<bitmap android:src="@drawable/ic_done_anim_030" />
</item>
</animation-list>
</transition>
</animated-selector>
布局文件中:
<ImageView
android:id="@+id/iv_img"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:layout_marginTop="30dp"
android:background="@drawable/fab_anim"
android:onClick="anim" />
Activity中:
public class AnimatedSelector extends Activity {
private boolean mIsCheck;
private static final int[] STATE_CHECKED = new int[] { android.R.attr.state_checked };
private static final int[] STATE_UNCHECKED = new int[] {};
private ImageView mImageView;
private Drawable mDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animated_selector);
mImageView = (ImageView) findViewById(R.id.iv_img);
mDrawable = getResources().getDrawable(R.drawable.fab_anim, null);
mImageView.setImageDrawable(mDrawable);
}
public void anim(View view) {
if (mIsCheck) {
mImageView.setImageState(STATE_UNCHECKED, true);
mIsCheck = false;
} else {
mImageView.setImageState(STATE_CHECKED, true);
mIsCheck = true;
}
}
}
运行结果如图:
十、Toolbar
Toolbar与Actionbar的区别主要为Toolbar更加自由、可控。
(另写博客)