Material Design 学习(一)

使用 Material 主题

Material 主题有:

  • @android:style/Theme.Material (深色版本)
  • @android:style/Theme.Material.Light (浅色版本)
  • @android:style/Theme.Material.Light.DarkActionBar

与之对应的 AppCompat 主题有:

  • Theme.AppCompat
  • Theme.AppCompat.Light
  • Theme.AppCompat.Light.DarkActionBar

效果如图所示:
MaterialDark.png
MaterialLight.png

定制主题配色

如果要定制主题的配色,只需要进行如下设置即可:

1
2
3
4
5
6
7
8
9
10
11
12
<resources>
<!-- inherit from the material theme -->
<style name="AppTheme" parent="android:Theme.Material">
<!-- Main theme colors -->
<!-- your app branding color for the app bar -->
<item name="android:colorPrimary">@color/primary</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="android:colorPrimaryDark">@color/primary_dark</item>
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">@color/accent</item>
</style>
</resources>

  • colorPrimary 表示应用栏颜色
  • colorPrimaryDark 表示状态栏颜色
  • colorAccent 表示CheckBox选中或EditText编辑时的颜色

与之对应的图:
ThemeColors.png

定制状态栏

通过使用android:statusBarColor属性来为状态栏设置颜色,默认情况下,android:statusBarColor继承colorPrimaryDark的值。

创建列表与卡片

RecyclerViewListView相比更加灵活,性能也更好;CardView能以卡片形式进行内容的展示。

创建列表

ListView相同的,也必须为RecyclerView指定一个适配器,该适配器需继承 RecyclerView.Adapter,除此之外,还需要指定一个布局管理器。

RecyclerView.png

RecyclerView提供的内置布局管理器有:

  • LinearLayoutManager 以垂直或水平滚动列表方式显示项目。
  • GridLayoutManager 在网格中显示项目。
  • StaggeredGridLayoutManager 在分散对齐网格中显示项目。

如果要创建一个自定义布局管理器,直接继承RecyclerView.LayoutManager即可。

RecyclerView拥有默认的增加和删除动画,如果要自定义这些动画,只需继承RecyclerView.ItemAnimator并重写RecyclerView.setItemAnimator()方法即可。

添加RecyclerView到布局中:

1
2
3
4
5
6
<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

RecyclerView指定布局管理器和适配器:

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
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);
}
...
}

RecyclerView适配器的简单实现:

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
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
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,通过card_view:cardElevation属性为CardView设置阴影效果;在布局中通过card_view:cardCornerRadius属性或在代码中通过CardView.setRadius()方法为CardView设置圆角半径;通过card_view:cardBackgroundColor属性为CardView设置背景颜色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
... >
<!-- A CardView that contains a TextView -->
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_gravity="center"
android:layout_width="200dp"
android:layout_height="200dp"
card_view:cardCornerRadius="4dp">
<TextView
android:id="@+id/info_text"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v7.widget.CardView>
</LinearLayout>

定义阴影与裁剪视图

Material Design 为 View 引入了高度属性,高度属性决定了投射的阴影及其外观。

指定视图高度

View 的高度属性 Z 值包含两个组件:

  • 高度:静态组件。
  • 转换:用于动画的动态组件。

Z = elevation + translationZ (单位为dp)

在布局中通过android:elevation属性或在代码中通过View.setElevation()方法设置 View 的高度;在代码中通过View.setTranslationZ()方法设置 View 的转换

自定义视图阴影与轮廓

1
2
3
4
5
<TextView
android:id="@+id/myview"
...
android:elevation="2dp"
android:background="@drawable/myrect" />
1
2
3
4
5
6
<!-- res/drawable/myrect.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#42000000" />
<corners android:radius="5dp" />
</shape>

使用 Drawables

定义定制动画

维护兼容性

参考文章

面向开发者的 Material Design