Material Design学习(三)

Material Design(三)

上篇介绍了Material Design中的各种动画效果,结合第一篇就可以写出很棒的UI界面了,这次再学习下Material Design中其它控件.

照常先贴学习链接:

https://github.com/traex/ExpandableLayout
http://githubonepiece.github.io/2015/11/26/Material-Design-Palette/
http://www.fx114.net/qa-26-168872.aspx
http://blog.csdn.net/jdsjlzx/article/details/41441083/
https://github.com/Flipboard/bottomsheet

ExpandableLayout

这个组件还是很常用的,但是Android自带的那个ExpandableListView使用起来不是很好,而且其适配器得继承其自带的适配器,使得代码十分不好写。今天在Github上看到ExpandableLayout真的是比Android自带的ExpandableListView好用不是一点点。这个组件的效果大家都见过,比如QQ的好友展开等等就是使用了该控件。废话不多说,直接开始使用吧。

要使用ExpandableLayout十分简单,在build.gradle中添加:

1
2
3
dependencies {
compile 'com.github.traex.expandablelayout:library:1.2.2'
}

就可以调用了。接下来在xml文件中就可以添加ExpandableLayout,ExpandableLayoutItem,ExpandableLayoutListView这三个控件了。

xml文件中使用ExpandableLayout需要添加head layoutcontent layout(在下面代码中去理解).

1
2
3
4
5
6
7
<com.andexert.expandablelayout.library.ExpandableLayout
android:id="@+id/expandableLayout"
xmlns:expandable="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
expandable:headerLayout="@layout/view_header"
expandable:contentLayout="@layout/view_content"/>

自己在写两个xml文件即可,测试效果就是点击view_headerview_content显示出来。效果自己也可以很好的实现,即写两个控件其中一个不可见,点击其中一个设置另一个控件可见。

同样的ExpandableLayoutListView也可以添加到xml文件。

1
2
3
4
5
<com.andexert.expandablelayout.library.ExpandableLayoutListView
android:id="@+id/expandableLayout"
xmlns:expandable="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

而填充ListView则可以使用ExpandableLayoutItem

1
2
3
4
5
6
7
<com.andexert.expandablelayout.library.ExpandableLayoutItem
android:id="@+id/expandableLayout"
xmlns:expandable="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
expandable:headerLayout="@layout/view_header"
expandable:contentLayout="@layout/view_content"/>

是不是特别的简单。在MainAcitivity.java中也不需要你做太多的事情,只需要你简单适配一下ListView就行,而ListView的适配就和正常ListView的适配相差无几。剩下的具体使用可以去Github上去看。这里只是做个简介!

Palette

在Material Design设计中很重要的一部分内容是应用中的图片颜色和文字颜色和主题相匹配。而在Android Lollipop发布的时候,Palette类则用来实现上面说的效果。这个类的作用就是提取某张图片中的主要颜色,比如你有一张大海的图片,那么这个类可以提取出的这张照片的主要颜色可能是蓝色。接下来看看怎么使用这个类。

首先你要使用这个类的话,你得依赖于:

1
compile 'com.android.support:palette-v7:23.0.0'

Palette有四种生成方式,其中前两种已经被google抛弃,但这里学习下不至于以后碰到了看不懂。

已抛弃得用法.

两种同步的方式:

1
2
Palette p = generate(Bitmap bitmap);
Palette p = generate(Bitmap bitmap ,int size)//设置调色板得大小为size

两种异步得方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 简单快速的实现方法,内部使用AsyncTask
// 但是可能不是最优的方法(因为有线程的切换)
// 默认调色板大小(16).
Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
// palette为生成的调色板
}
});
// 设置调色板大小(24)
Palette.generateAsync(bitmap, 24, new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
// palette为生成的调色板
}
});

提倡的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Palette.Builder builder = Palette.from(bitmap);
builder.generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {

}
});

//或者很多时候也可以直接写成

Palette.from(bitmap).generate(new PaletteAsyncListener() {
public void onGenerated(Palette p) {
// do something

}
});

调色板的大小值越大,生成得调色的时间越长,数值越小,得到的颜色信息也越少,调色板的大小最好根据图像类型来决定。(默认是16.)

生成了Palette对象后就可以尝试获取六种不同的色板了,具体如下:

1
2
3
4
5
6
1. Palette.Swatch s1 = Palette.getVibrantSwatch(); //充满活力的色板
2. Palette.Swatch s2 = Palette.getDarkVibrantSwatch(); //充满活力的暗色类型色板
3. Palette.Swatch s3 = Palette.getLightVibrantSwatch(); //充满活力的亮色类型色板
4. Palette.Swatch s4 = Palette.getMutedSwatch(); //黯淡的色板
5. Palette.Swatch s5 = Palette.getDarkMutedSwatch(); //黯淡的暗色类型色板(翻译过来没有原汁原味的赶脚啊!)
6. Palette.Swatch s6 = Palette.getLightMutedSwatch(); //黯淡的亮色类型色板

可以根据需求自由选择色板类型,有了色板就可以根据色板来获取具体颜色信息,在Swatch色板中提供了五种颜色信息,分别如下:

1
2
3
4
5
1. getPopulation(): the number of pixels represented by this swatch
2. getRgb(): the RGB value of this color.
3. getHsl(): the HSL value of this color.
4. getBodyTextColor(): the RGB value of a text color which can be displayed on top of this color.
5. getTitleTextColor(): the RGB value of a text color which can be displayed on top of this color.

示例代码如下:

1
2
3
4
5
Palette.Swatch swatch = palette.getVibrantSwatch();
TextView titleView = ...;
if (swatch != null) {
titleView.setBackgroundColor(swatch.getRgb());
titleView.setTextColor(swatch.getTitleTextColor()); //设置文本颜色

请注意必须对swatch进行是否为null的判断,因为如果面板无法找到相匹配的标准色,那么然后将返回null,不进行判断将会出现空指针异常。也可以是用另一种方式

1
2
3
4
5
6
tv1.setBackgroundColor(palette.getVibrantColor(0x999933));
tv2.setBackgroundColor(palette.getDarkVibrantColor(0x999933));
tv3.setBackgroundColor(palette.getLightVibrantColor(0x999933));
tv4.setBackgroundColor(palette.getMutedColor(0x999933));
tv5.setBackgroundColor(palette.getDarkMutedColor(0x999933));
tv6.setBackgroundColor(palette.getLightMutedColor(0x999933));

设置默认的颜色0x999933即使为空也可以填充默认的颜色。

这里也是个简单的说明,效果大概如下:
Palette效果

这个代码很简单,大家按照上面的代码试试就能得到了,具体Palette在Material Design的App中的应用大家可以看看这个项目,链接:
Android Material Design之Toolbar与Palette实践,博主源码也给了,大家可以试试看。

Bottom Sheet

哇,这个看起来就不是一般的帅了。知乎的分享大家都用过吧,那个从底下弹出来然后一堆的可以分享应用(如微信,qq)给你选择。你上滑整个界面也会往上划,看上去是不是很帅。效果很棒代码应该很难写吧? No No No,代码真的一点都不复杂,因为总有大神会帮你搞出个Library出来。今天学习的是Flipboard做的bottomsheet,链接已经贴在上面了。使用的话Github上有个sample你可以自己下下来看看效果然后实践下即可,这里就给大家抛砖引玉下吧。
image description
那么开始吧,如果你要使用bottom sheet的话,请记得在你的build.gradle中添加

1
2
3
4
dependencies{
compile 'com.flipboard:bottomsheet-core:1.5.0'
compile 'com.flipboard:bottomsheet-commons:1.5.0' //optional
}

这里有个optional是什么个意思,解释下:如果你只需要bottom sheet显示一个页面的话,你可以不依赖第二个。否则请添加上。

布局文件上呢也有轻微的变化,比如你曾经是这么写布局文件的。

1
2
3
4
5
6
7
8
9
10
11
12
<LinearLayout
android:id="@+id/root"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">


<View
android:id="@+id/view1"
android:layout_width="match_parent"
android:layout_height="match_parent"/>


</LinearLayout>

如果你要在这个布局文件中使用bottom sheet的话,请将你的布局文件该成下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<com.flipboard.bottomsheet.BottomSheetLayout
android:id="@+id/bottomsheet"
android:layout_width="match_parent"
android:layout_height="match_parent">


<LinearLayout
android:id="@+id/root"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">


<View
android:id="@+id/view1"
android:layout_width="match_parent"
android:layout_height="match_parent"/>


</LinearLayout>

</com.flipboard.bottomsheet.BottomSheetLayout>

首先是最简单的:只显示一个界面那你只需要在你的.java文件中加下面2句话

1
2
3
4

BottomSheetLayout bottomSheet = (BottomSheetLayout) findViewById(R.id.bottomsheet);

bottomSheet.showWithSheetView(LayoutInflater.from(context).inflate(R.layout.my_sheet_layout, bottomSheet, false));

这里的R.layout.my_sheet_layout即是你要显示的页面。

第二个种就是知乎分享按钮弹出来的界面:即你可以在上面的View中进行点击后执行相应的操作。
知乎的分享界面
布局文件同样如上,只是你不需要再写一个需要显示的布局文件。相关的代码如下:

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
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, "dasjdasjdsadasd");
intent.setType("text/plain");
IntentPickerSheetView intentPickerSheet = new IntentPickerSheetView(MainActivity.this, intent,
"I love you", new IntentPickerSheetView.OnIntentPickedListener() {
@Override
public void onIntentPicked(IntentPickerSheetView.ActivityInfo activityInfo) {
bottomsheet.dismissSheet();
startActivity(activityInfo.getConcreteIntent(intent));
}
});
List<IntentPickerSheetView.ActivityInfo> activityInfo = new ArrayList<>();
Drawable customDrawable = ResourcesCompat.getDrawable(getResources(), R.mipmap.ic_launcher, null);
IntentPickerSheetView.ActivityInfo customInfo = new IntentPickerSheetView.ActivityInfo(customDrawable, "Custom mix-in", MainActivity.this, MainActivity.class);
activityInfo.add(customInfo);
Drawable customDrawable2 = ResourcesCompat.getDrawable(getResources(), R.mipmap.ic_launcher, null);
IntentPickerSheetView.ActivityInfo customInfo2 = new IntentPickerSheetView.ActivityInfo(customDrawable2, "Custom mix-in123123", MainActivity.this, Main2Activity.class);
activityInfo.add(customInfo2);
intentPickerSheet.setMixins(activityInfo);

bottomsheet.showWithSheetView(intentPickerSheet);
}
});

这里稍微做点说明,具体的还是大家测试才知道。我也是试了然后看了作者的函数以及调用参数后自己写的。如果大家要实现知乎的那个分享效果的话,只需要把Intent.ACTION_SEND这里换成分享的Intent就好了。具体的我这里就不就不写了,也不是本文的重点。下面还有一堆的代码是我们用户自己添加到bottomsheet界面上的,添加了一个icon,title和点击该视图所执行的操作
intentPickerSheet.setMixins(List ActivityInfo)
你可以根据上面的方式添加多个你想要的ActivityInfo,之后你把它添加到ActivityInfo的集合中去即可。

最后如果你想要自己定制的Bottom sheet的话,你就需要使用这个库中MenuSheetView了,这个也很好写。具体代码如下:

首先你得创建一个menu文件夹(如果有就不必创建了),在menu文件夹下新建一个activity_menu.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
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:title="@string/document"
android:icon="@mipmap/ic_launcher"
/>

<item
android:title="@string/spreadsheet"
android:icon="@mipmap/ic_launcher"
/>

<item
android:title="@string/folder"
android:icon="@mipmap/ic_launcher"
/>


<item
android:id="@+id/menu_subheader"
android:title=""
>

<menu>
<item
android:id="@+id/navigation_sub_item_1"
android:icon="@mipmap/ic_launcher"
android:title="@string/upload_photos"/>

<item
android:id="@+id/navigation_sub_item_2"
android:icon="@mipmap/ic_launcher"
android:title="@string/use_camera"/>

</menu>
</item>
<item
android:id="@+id/reopen"
android:title="@string/reopen"
android:icon="@mipmap/ic_launcher"
/>


</menu>

接着在MainActivity.java中为menu中的item添加点击事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
MenuSheetView menuSheetView =
new MenuSheetView(MenuActivity.this, MenuSheetView.MenuType.LIST, "Create...", new MenuSheetView.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(MenuActivity.this, item.getTitle(), Toast.LENGTH_SHORT).show();
if (bottomSheetLayout.isSheetShowing()) {
bottomSheetLayout.dismissSheet();
}
return true;
}
});
menuSheetView.inflateMenu(R.menu.activity_menu);
bottomSheetLayout.showWithSheetView(menuSheetView);

当然MenuSheetView.MenuType除了LIST还有GRID,一个是列表一个是表格,上面的GIF已经把效果显示出来了。

在它的sample中还有两种其他的效果,一种是ImagePicker就是把相册中的图片放到了bottomsheet中。另一个是在bottomsheet中显示一个Fragment,竟然都能显示Fragment了那估计想干么就能干么了。但在实际的App中常见的用途是前面介绍的两种,后面两种等需要使用的时候在继续学习。