在公司实战开发长久以来,因为在 IT 公司在应用界面设计的时候为了保持统一,我们的产品经常会强制要求 Android 的界面风格要和 iOS 一致,因为人家长得好看,这种要求在工作中被认为是普遍存在的,,这也确实怪不了别人,问题在于 Android 标准的设计风格并不是被用户所接受,大家基本都认为 Android 系统的 UI 太难看,再加上很多公司都在自己设计自认为更加好看的界面,这样就造成了 Android 的界面设计百花齐放,各有风格,长期难以得到统一,终于在 2014 年 Google I/O 大会上 Material Design 应运而生
那么到底什么是 Material Design,我们先来看一张图:
这张图来自 Android 的官方网站,是不是很漂亮,官方是这么介绍这张图的:创造一种视觉语言,将经典设计原则与科技和科学的创新的可能性相结合,我想这就是 Material Design 的使命吧
Material Design 是由谷歌设计师基于传统的优秀的设计原则,结合创意和科学技术多发明的一套全新的视觉语言,包含了视觉、运动、互动效果等特性如果各个公司都无法设计出比 Material Design 更出色的界面风格,那么它们就应该使用 Material Design 来设计界面,这样也就能从一定程度上解决 Android 平台界面风格界面不统一的问题了,不过在 2014 年重磅推出之后,并没有达到很好的普及效果,,因为这只是一个推荐的设计规范,主要是面向 UI 设计人员的,而不是面向开发的,我们开发者可能根本就搞不懂,什么样的界面效果才能叫 Material Design ,就算知道了,具体到实现也是非常费劲,因为很多 Material Design 的风格是很难实现的,并且 Android 几乎没有提供相应的 API 支持,一切都要开发者从开始,Google 很快也意识到了这个问题,于是在 2015 年的 I/O 大会上推出了 Design Support 库,这个库对 Material Design 中代表性的实现效果进行了封装,这样就使得开发者在不是特别了解 Material Design 的情况下也可以将自己的应用程序 Material Design 化
下面我们就从几个方面来具体看一下:
一、使用材料主题
如果要在应用中使用材料主题,请指定一个从 android:Theme.Material继承风格:
新材料主题将提供:
系统小组件拥有全新的设计与触摸反馈动画,可以为自己的应用定制调色工具、触摸反馈动画以及操作行为转换
材料主题定义为:
注意:材料主题仅在 Android 5.0 ( API 级别 21 )及更高版本中提供,v7 支持内容库为一些小组件提供附带 Material Design 风格的主题,同时为配色工具定制提供支持
定制配色工具:
如果要定制主题的基色以符合你 App 的风格,你可以进行材料主题继承时使用主题属性定义你的定制颜色:
材料主题可以让你轻松定制状态栏,因此你可以指定一个符合自己 App 风格特色的状态栏,如果要为状态栏设置定制颜色,你可以在扩展材料主题时使用android:statusBarColor 属性。默认情况下,android:statusBarColor 将继承 android:colorPrimaryDark的值
你也可以自行将状态栏移到后侧,例如,你想在一个照片上以透明的方式显示状态栏,同时利用细微的深色渐变以确保白色状态栏图标仍保持可见,如果要执行此操作,需要将android:statusBarColor 属性设置为@android:color/transparent 并根据需要调整窗口标志,也可以使用 Window.setStatusBarColor()方法进行动画或淡出设置
注意:在多数情况下,状态栏与主工具栏之间应该有一个清楚的分割,可以在这些栏的后侧显示全屏的丰富图像或媒体内容以及使用颜色渐变以确保图表仍保持可见的情况除外
定制状态栏是,可以选择将导航栏和状态栏变透明或修改状态栏,在所有其他情况中,状态栏均应保持黑色
二、创建列表与卡片
在应用中使用 Material Design 风格创建复杂列表与卡片,可以使用 RecyclerView 以及 CardView 小部件
创建列表
RecyclerView 小部件比 ListView 更高级且更加的灵活,RecyclerView 是用于显示庞大数据集的容器,说白了就是用来展示列表的
如果要创建一个自定义布局管理器,请扩展 RecyclerView.LayoutManager 类别
动画
RecyclerView 在默认情况下启用增加删除列表的动画,如果需要自定义这些动画,请扩展RecyclerView.ItemAnimator 类别并使用 RecyclerView.setItemAnimator()方法
示例:
下列代码示例将展示如何将 RecyclerView 添加至布局:
public class MyActivity extends Activity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example)
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
}
...
}
TextView
小部件显示的字符串阵列的数据集:
public class MyAdapter extends RecyclerView.Adapter {
private String[] mDataset;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView mTextView;
public ViewHolder(TextView v) {
super(v);
mTextView = v;
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(String[] myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
// set the view's size, margins, paddings and layout parameters
...
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.mTextView.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return mDataset.length;
}
}
CardView 扩展 FrameLayout 类并让你能够显示卡片内的信息,CardView 小部件可拥有阴影和圆角,如果要使用阴影创建卡片,请使用card_view:cardElevation 属性,CardView 在 Android 5.0 (API 级别 21) 及更高版本中使用真实高度与动态阴影,而在早期的Android 版本中则返回编辑程阴影实现
使用这些属性自定义 CardView 小部件外观:
示例代码如下:
了解更多可以查看 CardView API 官方文档,地址: 点击打开链接
添加依赖项:
RecyclerView 和 CardView 为 v7 支持库的一部分,如果在项目中使用,需要在项目中添加如下依赖:
dependencies {
...
compile 'com.android.support:cardview-v7:21.0.+'
compile 'com.android.support:recyclerview-v7:21.0.+'
}
三、定义阴影与裁剪视图
Material Design 为 UI 元素引入高度,高度将帮助用户了解每个元素的相对重要性,由于 Z 属性所代表的视图高度将决定其阴影的视觉外观:拥有较高 Z 值的视图将投射更大更柔和的阴影,拥有较高 Z 值的视图将挡住拥有较低 Z 值的视图,不过试图的 Z 值并不影响视图的大小
阴影是由提升的视图的父项所绘制,因此将受到标准视图裁剪的影响,而在默认情况下裁剪将由父项执行,此外,在创建其中的小部件在执行某些操作时会暂时升至视图平面之上的动画时,高度也很实用
指定视图的高度:
视图的 Z 值包含两个组件:
高度:静态组件
转换:用于动画的动态组件
Z = elevation+translationZ
不同视图高度的阴影:
在布局中设置视图的高度:android:elevation属性
在代码中设置是土的高度:View.setElevation()方法
设置视图转换:View.setTranslationZ() 方法
为视图高度添加动画:ViewPropertyAnimator.z()与 ViewPropertyAnimator.translationZ()方法
这里注意:Z 值以 dp (密度独立像素) 为单位度量
自定义视图与轮廓:
视图的背景可绘制对象的边界将决定其阴影的默认形状,轮廓代表图形对象的外形并定义触摸反馈的波纹区域,下面举一个背景可绘制对象的视图示例:
背景可绘制对象被定义为一个拥有圆角的矩形:
自定义轮廓:
1.扩展 ViewOutlineProvider 类别
2.替代 getOutline() 方法
3.利用 View.setOutlineProvider() 方法向视图的指定新轮廓提供程序
也可以使用 Outline 类别中的方法创建带有圆角的椭圆形和矩形轮廓,视图的默认轮廓提供程序将从视图背景取得轮廓,如果要防止视图投射阴影,请将其轮廓提供程序设置为 null
裁剪视图
裁剪视图可以轻松改变视图的形状,以便于其他设计元素保持一致,可以使用 View.setClipToOutline() 方法或 android:clipToOutline 属性将视图裁剪至其沦落区域,由 Outline.canClip() 方法所决定,仅有矩形、圆形和圆角矩形轮廓支持裁剪
四、定义定制动画
这里不做详细的讲解,需要用到可以参考官方文档:定义定制动画
今天就记录到这里