一个Activity掌握Design新控件 (转)
原文地址:http://blog.csdn.net/lavor_zl/article/details/51295364
谷歌在推出Android5.0的同时推出了全新的设计Material Design,谷歌为了给我们提供更加规范的MD设计风格的控件,在2015年IO大会上推出了Design支持包,Design常用的新控件有下面8种。
1. TextInputLayout(文本输入布局)
TextInputLayout的作用是将EditText包裹起来,使得EditText的android:hint
属性的值以浮动标签的形式显示出来,同时可以通过setErrorEnabled(boolean)
和setError(CharSequence)
来显示错误信息。
在xml文件中定义TextInputLayout:
<code class="hljs avrasm has-numbering"> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.TextInputLayout</span> android:id=<span class="hljs-string">"@+id/text_input_layout"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span>> <EditText android:hint=<span class="hljs-string">"作者"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span> /> </android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.TextInputLayout</span>></code>
在java文件中设置错误信息:
<code class="hljs avrasm has-numbering"> this<span class="hljs-preprocessor">.textinputlayout</span><span class="hljs-preprocessor">.setErrorEnabled</span>(true)<span class="hljs-comment">;</span> this<span class="hljs-preprocessor">.textinputlayout</span><span class="hljs-preprocessor">.setError</span>(<span class="hljs-string">"作者不能包含标点符号"</span>)<span class="hljs-comment">;</span></code>
2. TabLayout(选项卡布局)
Tablayout提供横向布局显示选项卡,它取代了ActionBar添加选项卡的方式。它经常与ViewPager配合使用。
在xml文件中定义TabLayout:
<code class="hljs avrasm has-numbering"> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.TabLayout</span> android:id=<span class="hljs-string">"@+id/tab_layout"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span>> </android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.TabLayout</span>> </code>
在java文件中添加选项卡:
<code class="hljs avrasm has-numbering"> tablayout<span class="hljs-preprocessor">.addTab</span>(tablayout<span class="hljs-preprocessor">.newTab</span>()<span class="hljs-preprocessor">.setText</span>(<span class="hljs-string">"Tab1"</span>))<span class="hljs-comment">;</span> tablayout<span class="hljs-preprocessor">.addTab</span>(tablayout<span class="hljs-preprocessor">.newTab</span>()<span class="hljs-preprocessor">.setText</span>(<span class="hljs-string">"Tab2"</span>))<span class="hljs-comment">;</span> tablayout<span class="hljs-preprocessor">.addTab</span>(tablayout<span class="hljs-preprocessor">.newTab</span>()<span class="hljs-preprocessor">.setText</span>(<span class="hljs-string">"Tab3"</span>))<span class="hljs-comment">;</span></code>
Tablayout与ViewPager配合使用:
- tablayout.setupWithViewPager();
这种方法下面选项卡的标题由ViewPager决定
- viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(tablayout));
这种方法下面选项卡的标题由Tablayout决定
3. Snackbar
Snackbar提供比Toast轻量级的反馈操作,谷歌推荐使用Snackbar替代Toast。Snackbar显示或者消失的时候有一个回调方法。
<code class="hljs java has-numbering"> <span class="hljs-comment">//tablayout是Snackbar努力找到持有自己的视图</span> Snackbar snackbar=Snackbar.make(tablayout,<span class="hljs-string">"我是Snackbar"</span>,Snackbar.LENGTH_LONG); <span class="hljs-comment">//为snackbar设置回调方法</span> snackbar.setCallback(<span class="hljs-keyword">new</span> Snackbar.Callback() { <span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onDismissed</span>(Snackbar snackbar, <span class="hljs-keyword">int</span> event) { <span class="hljs-keyword">super</span>.onDismissed(snackbar, event); Log.i(<span class="hljs-string">"Snackbar"</span>,<span class="hljs-string">"Snackbar消失了"</span>); } <span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onShown</span>(Snackbar snackbar) { <span class="hljs-keyword">super</span>.onShown(snackbar); Log.i(<span class="hljs-string">"Snackbar"</span>,<span class="hljs-string">"Snackbar出现了"</span>); } }); <span class="hljs-comment">//显示snackbar</span> snackbar.show(); </code>
4. FloatingActionButton(浮动按钮)
FloatingActionButton在用户界面中通常是一个漂浮的小圆圈,它有自身独特的动态效果,比如变形、弹出、位移等等。
FloatingActionButton默认的背景颜色是主题的colorAccent
,还可以通过app:backgroundTint
来修改,也可以通过android:backgroundTint
属性修改,但是android:backgroundTint
属性只能在API21及以上使用。
FloatingActionButton的定义很简单:
<code class="hljs avrasm has-numbering"> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.FloatingActionButton</span> android:id=<span class="hljs-string">"@+id/fab_add_task"</span> android:layout_width=<span class="hljs-string">"wrap_content"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span> android:src=<span class="hljs-string">"@drawable/ic_add_circle_pink_400_18dp"</span> app:backgroundTint=<span class="hljs-string">"@color/blue"</span> app:fabSize=<span class="hljs-string">"normal"</span> /> </code>
5. NavigationView(导航视图)
NavigationView顾名思义是导航视图,一般与DrawerLayout(抽屉布局)联合使用。它为应用程序提供标准的导航菜单,菜单内容可以通过一个xml菜单文件来填充。
在xml文件中定义NavigationView
<code class="hljs avrasm has-numbering"> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.NavigationView</span> android:id=<span class="hljs-string">"@+id/navigation_menu"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"match_parent"</span> android:layout_gravity=<span class="hljs-string">"start"</span> android:fitsSystemWindows=<span class="hljs-string">"true"</span> app:headerLayout=<span class="hljs-string">"@layout/drawer_navigation_header"</span> app:menu=<span class="hljs-string">"@menu/drawer_navigation_menu"</span> /> </code>
app:headerLayout
:表示NavigationView的头部布局app:menu
:表示NavigationView的导航菜单
头部布局很简单就是一个普通的布局文件,我们来看看导航菜单的定义吧。
<code class="hljs xml has-numbering"><span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span><span class="hljs-tag"><<span class="hljs-title">menu</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span>></span><span class="hljs-tag"><<span class="hljs-title">group</span> <span class="hljs-attribute">android:checkableBehavior</span>=<span class="hljs-value">"single"</span>></span><span class="hljs-tag"><<span class="hljs-title">item </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/drawer_home"</span><span class="hljs-attribute">android:icon</span>=<span class="hljs-value">"@drawable/ic_home_black_24dp"</span><span class="hljs-attribute">android:title</span>=<span class="hljs-value">"@string/home"</span> /></span><span class="hljs-tag"><<span class="hljs-title">item </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/section"</span><span class="hljs-attribute">android:icon</span>=<span class="hljs-value">"@drawable/ic_more_horiz_black_24dp"</span><span class="hljs-attribute">android:title</span>=<span class="hljs-value">"分组1"</span>></span><span class="hljs-tag"><<span class="hljs-title">menu</span>></span><span class="hljs-tag"><<span class="hljs-title">item </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/drawer_favourite"</span><span class="hljs-attribute">android:icon</span>=<span class="hljs-value">"@drawable/ic_favorite_black_24dp"</span><span class="hljs-attribute">android:title</span>=<span class="hljs-value">"@string/favourite"</span> /></span><span class="hljs-tag"><<span class="hljs-title">item </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/drawer_downloaded"</span><span class="hljs-attribute">android:icon</span>=<span class="hljs-value">"@drawable/ic_file_download_black_24dp"</span><span class="hljs-attribute">android:title</span>=<span class="hljs-value">"@string/downloaded"</span> /></span><span class="hljs-tag"></<span class="hljs-title">menu</span>></span><span class="hljs-tag"></<span class="hljs-title">item</span>></span><span class="hljs-tag"><<span class="hljs-title">item </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/section2"</span><span class="hljs-attribute">android:title</span>=<span class="hljs-value">"分组2"</span>></span><span class="hljs-tag"><<span class="hljs-title">menu</span>></span><span class="hljs-tag"><<span class="hljs-title">item </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/drawer_more"</span><span class="hljs-attribute">android:icon</span>=<span class="hljs-value">"@drawable/ic_more_horiz_black_24dp"</span><span class="hljs-attribute">android:title</span>=<span class="hljs-value">"@string/more"</span> /></span><span class="hljs-tag"><<span class="hljs-title">item </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/drawer_settings"</span><span class="hljs-attribute">android:icon</span>=<span class="hljs-value">"@drawable/ic_settings_black_24dp"</span><span class="hljs-attribute">android:title</span>=<span class="hljs-value">"@string/settings"</span> /></span><span class="hljs-tag"></<span class="hljs-title">menu</span>></span><span class="hljs-tag"></<span class="hljs-title">item</span>></span><span class="hljs-tag"></<span class="hljs-title">group</span>></span><span class="hljs-tag"></<span class="hljs-title">menu</span>></span> </code>
我们来分析一下该xml文件:
group
:表示组
android:checkableBehavior
:可以接受下面3种值
- single
组中只有一个菜单项可以checked
- all
组中所有菜单项可checked
- none
组中所有菜单项都不可checked
item
:表示项,下面可以有子菜单, item
与item
会默认有分割线分开。
6. AppBarLayout(应用程序栏布局)
AppBarLayout是一个垂直的线性布局,实现了Material Design概念的应用程序栏,支持滚动手势。
它的子视图提供所需的滚动行为:
- 在java文件中通过setScrollflags(int)
设置
- 在xml布局文件中通过““
AppBarLayout经常作为CoordinatorLayout的直接子视图使用。
AppBarLayout的作用是把AppBarLayout包裹的内容都作为应用程序栏。
我们在xml文件中定义一个AppBarLayout,AppBarLayout下面有一个Toolbar和一个TabLayout
<code class="hljs avrasm has-numbering"> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.AppBarLayout</span> android:id=<span class="hljs-string">"@+id/app_bar_layout"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span>> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.v</span>7<span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.Toolbar</span> android:id=<span class="hljs-string">"@+id/toolbar"</span> app:layout_scrollFlags=<span class="hljs-string">"scroll|enterAlways"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span> android:background=<span class="hljs-string">"?attr/colorPrimary"</span> android:fitsSystemWindows=<span class="hljs-string">"true"</span> app:popupTheme=<span class="hljs-string">"@style/ThemeOverlay.AppCompat.Light"</span> app:theme=<span class="hljs-string">"@style/ThemeOverlay.AppCompat.Dark.ActionBar"</span>> </android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.v</span>7<span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.Toolbar</span>> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.TabLayout</span> android:id=<span class="hljs-string">"@+id/tab_layout"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span>> </android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.TabLayout</span>> </android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.AppBarLayout</span>> </code>
我们向上滑动AppBarLayout看看有什么效果
此时我们发现Toolbar被隐藏了,我们再在向下滑动AppBarLayout,发现Toolbar又出来了。
这就相当于是一个可以折叠的工具栏。
这是因为Toolbar设置了app:layout_scrollFlags="scroll|enterAlways"
。
app:layout_scrollFlags
属性里面必须至少启用scroll
这个flag,这样这个view才会滚动出屏幕,否则它将一直固定在顶部。可以使用的其他flag有:
- enterAlways: 一旦向下滚动,不管是否继续滚动,该view都会变为可见。
- enterAlwaysCollapsed: 这个属性是作为enterAlways
属性的附加属性使用的,这个flag定义的是何时进入,,当你定义了一个minHeight
,并且定义了enterAlways
属性,那么view将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。
- exitUntilCollapsed: 这个flag时定义何时退出,当你定义了一个minHeight
,这个view将在滚动到达这个最小高度的时候开始慢慢消失。
app:layout_scrollFlags
这个属性其实一般就只有下面4种使用情况,我们来一一讲解。
1. app:layout_scrollFlags="scroll"
- 该view显示时,只有在滚动视图顶部向上滚动时,该view才会慢慢消失。
- 该view消失后,只有在滚动视图顶部向下滚动时,该view才会慢慢出现。
2. app:layout_scrollFlags="scroll|enterAlways"
- 该view显示时,只要滚动视图向上滚动,该view就会慢慢消失。
- 该view消失后,只要滚动视图向下滚动,该view就会慢慢出现。
3. app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
,同时该view设置了minHeight
- 该view显示时,只要滚动视图向上滚动,该view就会慢慢消失。
- 该view消失后,只要滚动视图向下滚动,该view就会慢慢出现:
- 当滚动视图不在顶部时,该view只会慢慢出现
minHeight
高度的内容 - 当滚动视图在顶部时,该view会慢慢出现全部的内容
- 当滚动视图不在顶部时,该view只会慢慢出现
4. app:layout_scrollFlags="scroll|exitUntilCollapsed"
,同时该view设置了minHeight
- 该view显示时,只有在滚动视图顶部向上滚动时,该view才会慢慢消失,但不会完全消失,会保留着
minHeight
高度的内容依然可见。 - 该view消失后,只有在滚动视图顶部向下滚动时,该view才会慢慢出现。
注意:只有AppBarLayout第一个设置app:layout_scrollFlags
属性的直接子视图可以折叠
7. CoordinatorLayout(协作布局)
CoordinatorLayout是一个超级强大的FrameLayout。
CoordinatorLayout有两个主要用途:
- 作为顶级应用程序的装饰或着色布局
- 作为特定交互的容器,与一个或多个孩子视图交互
CoordinatorLayout作为一个父视图,它的孩子可以通过特定的行为与CoordinatorLayout别的孩子交互。
当视图类作为CoordinatorLayout的孩子时,可以定义特定的行为。
- 在xml文件中使用app:layout_behavior
。
- 在view类使用@DefaultBehavior
修饰符来添加注解。
在CoordinatorLayout的孩子视图FloatingActionButton中设置
app:layout_behavior="com.lavor.designnewcontrols.ScrollBehavior"
com.lavor.designnewcontrols.ScrollBehavior
的代码如下:
<code class="hljs scala has-numbering">public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScrollBehavior</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">CoordinatorLayout</span>.<span class="hljs-title">Behavior</span><<span class="hljs-title">View</span>> {</span><span class="hljs-javadoc">/** * 因为是在XML中使用app:layout_behavior定义静态的这种行为, * 必须实现一个构造函数使布局的效果能够正常工作。 * 否则 Could not inflate Behavior subclass error messages. */</span> public ScrollBehavior(Context context, AttributeSet attrs) { <span class="hljs-keyword">super</span>(); } <span class="hljs-javadoc">/** * 开始滚动时 */</span><span class="hljs-annotation">@Override</span> public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { <span class="hljs-comment">//如果child可见,设置其不可见</span><span class="hljs-keyword">if</span>(child.getVisibility()==View.VISIBLE){ ((FloatingActionButton)child).hide(); } <span class="hljs-comment">//如果child不可见,设置其可见</span><span class="hljs-keyword">else</span>{ ((FloatingActionButton)child).show(); } <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); } } </code>
CoordinatorLayout的子视图可以设置app:layout_anchor
属性,该属性的值对应着CoordinatorLayout中其它子视图(不能是该视图本身或其子视图)的android:id
属性。这可以将浮动视图放在任意地方。
<code class="hljs avrasm has-numbering"> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.FloatingActionButton</span> android:id=<span class="hljs-string">"@+id/fab_add_task"</span> android:layout_width=<span class="hljs-string">"wrap_content"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span> android:src=<span class="hljs-string">"@drawable/ic_add_circle_pink_400_18dp"</span> app:fabSize=<span class="hljs-string">"normal"</span> app:layout_anchor=<span class="hljs-string">"@id/toolbar"</span> app:layout_anchorGravity=<span class="hljs-string">"bottom|right|end"</span> /> </code>
我们将FloatingActionButton(浮动按钮)放置到Toolbar的右下方结束位置。
注意:使用CoordinatorLayout时,AppBarLayout下面有一个RecyclerView时,RecyclerView会与AppBarLayout重叠,因为CoordinatorLayout是帧布局。
要解决这个问题可以设置RecyclerView的app:layout_behavior="@string/appbar_scrolling_view_behavior"
,其实此时该属性的值就是android.support.design.widget.AppBarLayout$ScrollingViewBehavior
8. CollapsingToolbarLayout(折叠工具栏布局)
CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承至FrameLayout,它通常是作为AppBarLayout直接子视图使用。它提供的折叠工具栏更高级,还可以制造视觉差。
对于CollapsingToolbarLayout,我们通常是这样使用的,将其定义为AppBarLayout的第一个直接子视图,并且其自身定义如下:它里面有一个ImageView和一个Toolbar,形成折叠工具栏。
<code class="hljs avrasm has-numbering"> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.CollapsingToolbarLayout</span> app:layout_scrollFlags=<span class="hljs-string">"scroll|exitUntilCollapsed"</span> app:contentScrim=<span class="hljs-string">"?attr/colorPrimary"</span> app:expandedTitleMarginStart=<span class="hljs-string">"48dp"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span>> <ImageView android:src=<span class="hljs-string">"@drawable/bg"</span> android:scaleType=<span class="hljs-string">"centerCrop"</span> app:layout_collapseMode=<span class="hljs-string">"parallax"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"wrap_content"</span> /> <android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.v</span>7<span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.Toolbar</span> android:id=<span class="hljs-string">"@+id/toolbar"</span> android:layout_width=<span class="hljs-string">"match_parent"</span> android:layout_height=<span class="hljs-string">"60dp"</span> app:layout_collapseMode=<span class="hljs-string">"pin"</span> android:background=<span class="hljs-string">"?attr/colorPrimary"</span> android:fitsSystemWindows=<span class="hljs-string">"true"</span>> </android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.v</span>7<span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.Toolbar</span>> </android<span class="hljs-preprocessor">.support</span><span class="hljs-preprocessor">.design</span><span class="hljs-preprocessor">.widget</span><span class="hljs-preprocessor">.CollapsingToolbarLayout</span>></code>
- 首先,CollapsingToolbarLayout要设置
app:layout_scrollFlags
,这个属性在介绍AppBarLayout的时候已经讲过了,app:contentScrim
表示滚动达到一定阈值后Toolbar的背景颜色,app:expandedTitleMarginStart
设置扩张时候(还没有收缩时)title向左填充的距离。 - 其次, ImageView的
app:layout_collapseMode
属性的值为parallax
,设置为这个模式时,在内容滚动时,CollapsingToolbarLayout中的View(比如ImageView)也可以同时滚动,实现视差滚动效果,通常和app:layout_collapseParallaxMultiplier
属性(设置视差因子)搭配使用,其值为0~1。 - 最后,Toolbar的
app:layout_collapseMode
属性的值为pin
,设置为这个模式时,当CollapsingToolbarLayout完全收缩后,Toolbar还可以保留在屏幕上。
程序源代码下载:一个Activity掌握Design新控件
关于Design新控件国外有一篇不错的教程:https://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout
该教程源代码的github地址:https://github.com/chrisbanes/cheesesquare