本文翻译自著名博客 Android Developers,原作者是 Ian Lake,点击此处可查看 原文 。
Android 5.0 Lollipop 是迄今为止最重大的一次发布,很大程度上是因为 material design —— 这是一门新的设计语言,它刷新了整个 Android 的用户体验。但是对于开发者来说,要设计出完全符合 material design 哲学的应用,是一个很大的挑战。Android Design Support Library 对此提供了很好的支持,里面汇集了很多重要的 material design 控件,支持所有 Android 2.1 及后续版本。里面你可以看到 navigation drawer view、floating labels、floating action button、snackbar、tabs,以及一套将它们紧密结合在一起的动作与滚动框架。
Navigation View(导航视图)
无论从应用标识、内容导航,还是设计一致性来讲,navigation drawer 都是首当其冲的焦点。现在,NavigationView 让导航栏变得更简单,它提供了 navigation drawer 需要的框架,以及通过资源文件来自定义更多菜单项的能力。
你只需要将 NavigationView 作为 DrawerLayout 的内容视图来使用即可,例如:
这里你会注意到两个属性:app:heanderLaytout
用来控制 header 部分的布局;app:menu
指定了菜单资源。NavigationView 自动处理了状态栏的变化,保证可以在 API 21+ 的设备上正确运行。
最简单的 drawer 菜单就是一个允许选择的菜单项集合,例如:
选中的菜单会高亮显示,以提醒用户当前选择的是哪个菜单项。
你也可以在菜单中使用 subheader 来实现独立的分组:
调用 setNavigationItemSelectedListener()
后,在菜单项被选中的时候,你会通过OnNavigationItemSelectedListener
得到回调。在处理回调时,你会知道是哪个菜单项被点击,此时你可以处理选择事件,修改选中状态,加载新的内容,以及通过代码来关闭 drawer,或者其他任何你想执行的操作。
文字输入时的悬浮标签
尽管 EditText 已经为 material design 做了一些改善,但是还不够,譬如它在我们输入第一个字符的时候,就会自动隐藏掉提示标签。现在你该使用 TextInputLayout 了,它会在用户开始输入之后,自动将提示标签悬浮到 EditText 上方,这样用户就永远都能知道输入内容的上下文。
另外,你也可以通过调用 setError()
方法,在 EditText 下方显示一个出错提示消息。多么贴心的设计,有没有?
Floating Action Button(浮动操作按钮)
Floating action button 是一个圆形按钮,代表当前页面最重要的交互动作。Design Library 里面的 FloatingActionButton 给了你一个简单一致的实现,它会默认使用你主题中 colorAccent
属性定义的色调。
在标准尺寸之外,它也支持 mini 尺寸。FloatActionButton 继承自 ImageView,所以你也可以使用android:src
或者其他方法(如 setImageDrawable()
)来控制它的外观。
Snackbar
如果要提供一个轻量、快速的操作反馈方式,那就非 Snackbar 莫属了。Snackbar 在屏幕最下方展示,包含文字和一个可选的操作,它会在一定时间后自动消失,用户也可以通过滑动手势来提前消除它。
Snackbar 可以支持滑动手势,也可以响应点击动作,远比 Toast 强大,但是你会发现它的 API 非常眼熟:
Snackbar
.make(parentLayout, R.string.snackbar_text, Snackbar.LENGTH_LONG)
.setAction(R.string.snackbar_action, myOnClickListener)
.show(); // Don’t forget to show!
你会注意到 make
的第一个参数,Snackbar 会试图寻找合适的父视图,来确保它能显示在底部的正确位置。
Tabs(选项卡)
在应用内,通过 tab 在不同视图间切换,这不是 material design 中的新概念。Tabs 一般用来作顶层导航,或者组织、展示应用内不同分组的内容。如下图所示:
Design Library 的 TabLayout 控件实现了固定 tab(所有 tab 平分秋色,宽度固定)和滚动 tab(宽度根据标题长度自适应,可以水平滑动)两种形式,你可以用代码来添加 tab:
TabLayout tabLayout = ...;
tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
如果你使用 ViewPager 来水平分页,可直接在 PagerAdapter.getPageTitle()
中来创建 tab,最后通过 setupWithViewPager()
方法将它们绑定在一起。这能确保内容变化时 tab 和 ViewPager 会自动同步起来。
CoordinatorLayout、动画和滚屏
打造一个符合 material design 风格的应用,独特的视觉效果只是一方面,动作和手势也是非常重要的一部分。 Material design 里面包含了大量的手势,譬如点击的波纹效果和其他一些有用的转场动画。Design Library 介绍了 CoordinatorLayout 的布局方式,它提供了一个附加层,用来控制子视图间的点击事件,Design Library 里面很多控件都使用了这种布局。
CoordinatorLayout 和浮动操作按钮
FloatingActionButton 就是一个绝好的例子。当你将 FloatingActionButton 作为子元素加入 CoordinatorLayout,然后将 CoordinatorLayout 作为参数传给 Snackbar.make()
的时候,Snackbar 没有显示到 FloatingActionButton 上面。FloatingActionButton 利用了 CoordinatorLayout 提供的额外回调接口,在 Snackbar 展现的时候自动上移,消失的时候自动复位,所有这一切都不需要写任何代码。
CoordinatorLayout 还提供了一个 layout_anchor
的属性,连同 layout_anchorGravity
一起,可以用来放置与其他视图关联在一起的悬浮视图(如 FloatingActionButton)。
CoordinatorLayout 和 App Bar
CoordinatorLayout 的另一个主要使用场景,则与 appbar(以前的 actionBar)和滚屏相关。你可能已经在布局里面使用过 Toolbar,它允许你简单修改外观、整合图标以和其余部分一致。Design Library 将所有这些东西放到了下一级:使用 AppBarLayout,让你的 Toolbar 和其他视图(如 TabLayout 提供的 tab 视图),可以响应 ScrollingViewBehavior 标记的同级视图的滚动事件。此时你可以这样来创建一个布局:
现在,随着用户滚动 RecyclerView, AppBarLayout 也会响应这些事件(通过使用子节点的 scroll flag 来控制它们如何滚入和滚出屏幕)。Flags 包括:
- scroll: 这个标志会被设置到所有希望滚出屏幕的视图上,如果不设置这一标志,则视图会被一直保留在屏幕顶部。
- enterAlways: 这个标志会确保任何下滑滚屏都会触发视图的展现,等于开启了一种「快速返回」模式。
- enterAlwaysCollapsed: 如果设置了 minHeight 和这个标志,你的视图通常会折叠显示,只有当滚动视图已经到达了它的顶点以后才会打开到完整高度。
- exitUntilCollapsed: 这个标志会导致视图在退出之前,一直被锁定。
注意一点:所有设置了 scroll 标志的视图必须在未设该标志的视图之前进行声明,这样可以确保所有的滚动视图都从顶部退出,而固定元素都不受影响。
可伸缩的 Toolbars
直接将 Toolbar 加到 AppBarLayout 中,你就可以设置 enterAlwaysCollapsed
/exitUntilCollapsed
等滚动标志,但是不同元素如何响应折叠动作,你没法更深入地控制。要达到这一点,你需要使用 CollapsingToolbarLayout:
通过使用 app:layout_collapseMode="pin"
来确保 Toolbar 会一直被保留在屏幕顶端。更进一步,当你组合使用 CollapsingToolbarLayout 和 Toolbar,在视图完全展现的时候,标题会自动放大,当视图折叠的时候,标题则会过渡到默认字号。注意这时候你需要调用 CollapsingToolbarLayout 的 setTitle(),而不是 Toolbar 的相应方法。
除了将视图固定在屏幕之外,你还可以设置 app:layout_collapseMode="parallax"
(额外也需要增加 app:layout_collapseParallaxMultiplier="0.7"
这样的属性来设置视差乘数)来达到视差滚动的效果。这种用法搭配 app:contentScrim="?attr/colorPrimary"
属性效果非常好,例如下面这样:
CoordinatorLayout 和自定义视图
还有一件重要的事情就是,CoordinatorLayout 并不是天生就理解 FloatingActionButton 或者 AppBarLayout 如何工作,它只是提供了一些 Coordinator.Behavior 的附加 API,允许子控件来更好地控制点击事件和手势。
视图也可以使用 CoordinatorLayout.DefaultBehavior(YourView.Behavior.class)
来定义一个默认的行为,或者在 layout 文件中设置app:layout_behavior="com.example.app.YourView$Behavior"
来达到同样的效果。
Design Library 框架允许任何视图与 CoordinatorLayout 组合使用。
现已发布
Design Library 现在已经公开发布了,请确认在 SDK manager 中升级 Android Support Repository。对于 Gradle 项目来讲,你可以直接加入对 Design Library 的依赖:
compile 'com.android.support:design:22.2.0'
注意 :Design Library 依赖于 Support v4 和 AppCompat Support 库,它们会自动被加进编译依赖里来。并且,这些新的 widget 在 Android Studio Layout 编辑器中也是可用的(在 CustomView 中找到他们)。
对于构建一个具有一流外观和交互的现代应用,Design Library、AppCompat 和所有 Android Support Library 都是非常重要的工具,大家快来动手试试吧。
Android Design Support Library 中控件的使用简单介绍(一)
介绍
在这个 Lib 中主要包含了 8 个新的 material design 组件!最低支持 Android 2.1 。 这些组件在我看来就是对 Github中最近比较火的 android 组件进行了封装!!
下载
要使用这个库,当然得先下载啦!( 没有FQ的同学肯定已经哭晕在厕所了!! )这里我给童鞋们,提供一个简单的方法:
就是使用 红杏 提供的公益代理!具体使用方法如下图:
之后就是使用 Android SDK Manager 更新下载了!!
使用
第一步--引用
引用这个库:在 build.gradle
文件中加上这段代码: compile 'com.android.support:design:22.2.0
第二步--具体控件的使用
TextInputLayout
以前当我们使用 EditText 这个组件的 hint 属性的时候,当用户输入第一个字母之后,这个 hint 中的文本就会消失!有点影响用户体验!但是现在不一样了!现在只要把 EditText 包含在 TextInputLayout 中,这个 hint 中的文本就会变成 floating lable 浮动在 EditText 上方!同时,也支持在 EditText 下方显示错误信息好了,我么先来看一下 TextInputLayout 这个控件的公共方法吧!
想必大家也能看明白 (我在有的函数解释下)
现在我们先在布局文件中布局:
很简单就是一个嵌套!我们接下来 onCreate(Bundle savedInstanceState)
方法中的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textinput = (TextInputLayout) findViewById(R.id.textinput);
et_content = textinput.getEditText();
textinput.setHint("请输入用户名");
textinput.setError("密码输入错啦!");
textinput.setErrorEnabled(true);
}
代码很简单 不细说!大家直接看效果图:
FloatingActionButton
由于这个控件相对简单!我就直接在上面的那个布局中增加这个按钮,并把它显示在右边!
<android.support.design.widget.FloatingActionButton
android:id="@+id/button"
android:layout_width="48dp"
android:layout_gravity="right"
android:layout_height="48dp"
android:orientation="vertical" />
接着我们在看代码区域:
button.setRippleColor(Color.GRAY);
button.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.ic_menu_add));
不解释了简单!
Snackbar
和 Toast 类似。但是它有简单的可选择的单个的Action。 同时还有个特性就是用户可以在它消失时间未到的时候,移掉它!现在来介绍下 Snackbar 的一些函数
dismiss()
用来消失 Snackbar 的getDuration()
得到显示时长的make(View view, int resId, int duration)
创建 Snackbar 的make(View view, CharSequence text, int duration)
和上面一样setAction(int resId, View.OnClickListener listener)
对 Snackbar 设置单击时间,这里的单击时间不是作用于整个 Snackbar 的,还是作用于你所设置的这个字段的,也就是这个 resId
setAction(CharSequence text, View.OnClickListener listener)
和上面一样setActionTextColor(ColorStateList colors)
设置动作字的颜色,就是对上面的setAction 中文字颜色的设置setActionTextColor(int color)
和上面一样setDuration(int duration)
设置 Snackbar 显示时常setText(int resId)
更新 Snackbar 中的文本setText(CharSequence message)
和上面一样show()
显示 Snackbar
函数已经介绍完了!现在,我会FloatingActionButton增加一个单击事件用来显示 Snackbar 。直接看代码:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar
.make(content, "你好啊", Snackbar.LENGTH_LONG)
.setAction("delete", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "delete", Toast.LENGTH_SHORT).show();
}
})
.show();
}
});
直接看效果吧!
Tabs
选项卡,一般和 TabLayout 一起使用哦。现在我们来看一下 TabLayout 的一些函数。
addTab(TabLayout.Tab tab, int position, boolean setSelected)
增加选项卡到 layout 中addTab(TabLayout.Tab tab, boolean setSelected)
同上addTab(TabLayout.Tab tab)
同上getTabAt(int index)
得到选项卡getTabCount()
得到选项卡的总个数getTabGravity()
得到 tab 的 GravitygetTabMode()
得到 tab 的模式getTabTextColors()
得到 tab 中文本的颜色newTab()
新建个 tabremoveAllTabs()
移除所有的 tabremoveTab(TabLayout.Tab tab)
移除指定的 tabremoveTabAt(int position)
移除指定位置的 tabsetOnTabSelectedListener(TabLayout.OnTabSelectedListener onTabSelectedListener)
为每个 tab 增加选择监听器setScrollPosition(int position, float positionOffset, boolean updateSelectedText)
设置滚动位置setTabGravity(int gravity)
设置 GravitysetTabMode(int mode)
设置 ModesetTabTextColors(ColorStateList textColor)
设置 tab 中文本的颜色setTabTextColors(int normalColor, int selectedColor)
设置 tab 中文本的颜色 默认 选中setTabsFromPagerAdapter(PagerAdapter adapter)
设置 PagerAdaptersetupWithViewPager(ViewPager viewPager)
和 ViewPager 联动
函数介绍完了,现在来看代码吧!布局代码:
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:background="#1FBCD2"
android:layout_height="48dp" />
再来看一下 onCreate(Bundle savedInstanceState)
中的方法吧
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab);
tabLayout= (TabLayout) findViewById(R.id.tablayout);
tabLayout.setTabTextColors(Color.WHITE, Color.GRAY);
tabLayout.addTab(tabLayout.newTab().setText("第一个"), true);
tabLayout.addTab(tabLayout.newTab().setText("第二个"),false);
tabLayout.addTab(tabLayout.newTab().setText("第三个"),false);
}
来看一下效果吧
现在 我们来把 TabLayout 和 ViewPager 连起来用先看布局文件 我们在上面的基础上加了个ViewPager
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:background="#1FBCD2"
android:layout_height="48dp" />
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
再来看一下 onCreate(Bundle savedInstanceState)
中的方法吧
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab);
tvs = new ArrayList<TextView>();
for (int i = 0; i < items.length; i++) {
TextView tv = new TextView(this);
tv.setText(items[i]);
LinearLayout.LayoutParams lp =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
tv.setTextColor(Color.BLACK);
tv.setBackgroundColor(Color.WHITE);
tv.setGravity(Gravity.CENTER);
tv.setLayoutParams(lp);
tv.setTextSize(22);
tvs.add(tv);
}
tabLayout = (TabLayout) findViewById(R.id.tablayout);
tabLayout.setTabTextColors(Color.WHITE, Color.GRAY);
vp = (ViewPager) findViewById(R.id.vp);
adapter = new Adapter();
vp.setAdapter(adapter);
tabLayout.setupWithViewPager(vp);
tabLayout.setTabsFromPagerAdapter(adapter);
}
看效果图:
Navigation View
大家都记得 DrawerLayout 这个控件吧!它是 android 用来体态 SlideMenu 的一个组件!在这个控件中我们通常需要一个 menu(也是个布局文件)和一个主体布局文件。现在这个 Navigation View 就是用来写 menu的!这个控件我就不一一写函数了!我们还是直接使用吧!直接看布局文件
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="哈哈"
android:gravity="center"
android:textSize="30sp"
android:textColor="@android:color/background_dark"/>
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/header"
app:menu="@menu/my_navigation_items" />
</android.support.v4.widget.DrawerLayout>
我们直接看 NavigationView ,会发现我使用了两个新的属性 app:headerLayout
和 app:menu
这是因为这个组件把menu分为两部分,一个是头部还有一个是 menu。现在我们只需要写个新的头部和一个 menu就行啦!!这个组件我就不上图了!主要是我认为没啥意思这个组件!
剩下的组件
现在还剩下 CoordinatorLayout
, CollapsingToolbarLayout
和AppBarLayout
这三个组件!由于我对这个三个组件还没有仔细研究,在这篇博文中就不说了!下篇博文再讲!!