Material Design的研究(一)

由沉浸式状态栏引出

援引一句郭霖大神的话来破除大家对沉浸式的误解。

其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先发起的。因为Android官方从来没有给出过沉浸式状态栏这样的命名,只有沉浸式模式(Immersive Mode)这种说法。而有些人在没有完全了解清楚沉浸模式到底是什么东西的情况下,就张冠李戴地认为一些系统提供的状态栏操作就是沉浸式的,并且还起了一个沉浸式状态栏的名字。

所以说真正的沉浸式是什么,还是援引郭霖大神的话:

那么对应到Android操作系统上面,怎样才算是沉浸式体验呢?这个可能在大多数情况下都是用不到的,不过在玩游戏或者看电影的时候就非常重要了。因为游戏或者影视类的应用都希望能让用户完全沉浸在其中,享受它们提供的娱乐内容,但如果这个时候在屏幕的上方还显示一个系统状态栏的话,可能就会让用户分分钟产生跳戏的感觉。

但是我们就是想要我们以前以为的沉浸式的效果,就像Tim和网易云音乐那种效果我们到底要怎么达成呢?我们有两种思路,一个是指定状态栏的颜色,也就是纯色的,还有一种就是通过全屏模式

这张是Tim的截图

这是Tim的图片

这张是Tim的截图

这是网易云音乐的状态栏

介绍一下几个属性:

  1. fitsSystemWindows
    我们的理解是:在Android版本大于5.0的情况下,对于CoordinatorLayout、AppBarLayout、CollapsingToolbarLayout一起使用的时候,如果对其中的一个子控件设置fitsSystemWindows时,需要对它们的父控件都设置该属性;但是对于其它情况,这个属性的含义是为了不让我们的控件占据系统窗口的空间,比如说状态栏和导航栏(这一属性需要设置状态栏或者导航栏透明或者半透明的时候才会有效)。

指定状态栏的颜色来实现沉浸式(这种说法不准确,但是还是暂时这么说)

style.xml里面设置对应的Activitytheme,通过设置android:statusBarColor这一属性来直接设置状态栏的颜色,这种方案适用于==纯色==的toolBar或者ActionBar,具体代码如下:

1
2
3
<style name="MainActivityTheme" parent="AppTheme">
<item name="android:statusBarColor">@color/colorPrimary</item>
</style>

AndroidManifest.xml中设置刚才定义的style,具体的代码如下:

1
2
3
4
5
6
7
8
<activity android:name=".MainActivity"
android:theme="@style/MainActivityTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

通过设置全屏和状态栏透明来实现沉浸式

我们首先在需要设置全屏,保持状态栏悬浮,具体的代码如下:

1
2
3
View view = getWindow().getDecorView();            
int options = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
view.setSystemUiVisibility(options);

接着我们设置状态栏,具体的代码如下:

1
getWindow().setStatusBarColor(Color.TRANSPARENT);

通过设置全屏和设置状态栏为TRANSLUCENT来实现沉浸式

首先也要设置全屏,和之前的一样,接着要设置状态栏透明(在5.0以上为半透明)

1
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

Toolbar——Actionbar的替代者

一个Toolbar的基本效果如下图所示:

我们通常会设置Toolbarnavigationiconsubtitletitlemenulogo,设置这些属相的代码我贴在下面了:

1
2
3
4
5
6
7
8
9
10
11
12
13
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:paddingTop="24dp"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:theme="@style/Base.ThemeOverlay.AppCompat.Dark.ActionBar"
app:navigationIcon="@drawable/ic_menu"
app:logo="@drawable/ic_head"
app:popupTheme="@style/Base.ThemeOverlay.AppCompat"
app:title="@string/app_name"
app:subtitle="yuanlai" />

因为我们指定的styleLight,所以文字会变成深色,这会很难看的,这里我们需要把Actionbartheme设置为深色,这样文字就会变成浅色,但是这样弹出的菜单项会变成深色,所以我们又需要设置弹出菜单的themexmlns:app是因为Material Design库在Android 5.0系统中才出现,在之前的系统中并不存在,所以为了兼容之前的系统,才会有app:这种写法。

同时我们发现ToolBarstatusbar的颜色保持一致,这里我们用到之前设置statusbar的知识,设置为全屏然后接着设置statusbar为透明色,这里特殊之处在于我们为Toolbar设置的高度为wrap_content并设置了一个最小的高度,这样就可以保证statusbar处的颜色和Toolbar的颜色一致。

接下来我们来具体分析这些属性该怎么用:

title、subtitle、logo、navigationicon的设置

这几个属性直接用app:加上对应的属性名即可。

其中menu的填充一定要在代码中执行,具体定义的步骤如下:

  • 先在menu文件下面新建一个menu文件用来承载具体的menu的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/backup"
android:icon="@drawable/ic_backup_white"
android:title="Backup"
app:showAsAction="always"/>

<item
android:id="@+id/delete"
android:icon="@drawable/ic_delete_white"
android:title="Delete"
app:showAsAction="ifRoom"/>

<item
android:id="@+id/settings"
android:icon="@drawable/ic_settings_white"
android:title="Setting"
app:showAsAction="never"/>
</menu>
  • 在代码里面填充刚刚定义的menu文件
1
2
3
4
5
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar,menu);
return true;
}
  • 设置menu的点击事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.backup:
Toast.makeText(this, "You clicked backup", Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, "You clicked delete", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this, "you clicked settings", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return true;
}

而我们之前设置的navigationicon的点击事件设置则更加简单,其具体代码如下:

1
2
3
4
5
6
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

}
});

附:Toolbar可是一个viewgroup

在实际开发中我们会遇见一个两难的情况,我们希望Toolbartitle到中间去,但是Toolbar似乎不给我们留什么修改它的接口,但是Material Design的许多效果要搭配Toolbar使用才行,比如说CollapsingToolbarLayout。所以说我们得换一个思路,即把Toolbar作为一个viewgroup,具体的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:paddingTop="24dp"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:theme="@style/Base.ThemeOverlay.AppCompat.Dark.ActionBar">

<TextView
android:layout_gravity="center"
android:text="@string/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"/>

</android.support.v7.widget.Toolbar>

这一段代码关键是设置了layot_gravitystyle属性,其中style把自定义的Textview显示的和Actionbar.Title保持一致,同时还需要在代码里面控制Actionbartitle不显示,具体的代码如下:

1
getSupportActionBar().setDisplayShowTitleEnabled(false);

附:利用actionLayout来模仿网易云

我在网上看到大神亦枫的博客,看到他利用Toolbar做出了网易云音乐搜索栏的效果,感觉很牛逼。在通常情况下,ToolbarMenu item只有一个icon,但是有时候有些特殊情况,需要我们自定义Menu item,最后完成的效果如下图所示:

我们需要额外定义一个layout文件,然后通过actionLayout属性引入到标签中。layout具体代码如下:

1
2
3
4
5
6
7
8
9
10
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
xmlns:android="http://schemas.android.com/apk/res/android"
android:hint="搜索音乐、歌手、歌词、用户"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>

这里需要注意两点:

  • 那个layout的跟布局必须是以RelativeLayout作为根布局,否则,视图无法填满Toolbar或者是Actionbar
  • actionLayout这一属性必须是以app为命名空间。

将menu item移至中间

如果我们想把menu移到中间来,而不是把它放到右边去,这个时候我们就需要想到用ActionMenuView,其作为Toolbar的一个子控件,把menu item都放到自己里面,我们先来看看它的布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:paddingTop="24dp"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:layout_height="wrap_content"
android:background="@color/colorRed"
android:theme="@style/Base.ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/Base.ThemeOverlay.AppCompat" >
<android.support.v7.widget.ActionMenuView
android:layout_gravity="center"
android:id="@+id/amv_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</android.support.v7.widget.Toolbar>

接着在代码里把menu资源文件加载到通过findViewById()找到的ActionMenuView里面去,具体的代码如下所示:

1
2
3
4
5
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar, amvSearch.getMenu());
return true;
}

接着直接对ActionMenuView设置点击事件,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
amvSearch.setOnMenuItemClickListener(new ActionMenuView.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {

switch (item.getItemId()){

}

return false;
}
});

具体的效果图如下:

本文标题:Material Design的研究(一)

文章作者:袁来

发布时间:2018年05月01日 - 22:05

最后更新:2018年05月02日 - 19:05

原始链接:http://yoursite.com/2018/05/01/Material-Design的研究-一/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

显示 Gitment 评论