2017年03月22日 17:51:34 薛瑄 阅读数 3320
版权声明:本文为博主 薛瑄 原创文章,转载请标明出处。 https://blog.csdn.net/xx326664162/article/details/64906142
这篇文章主要介绍CoordinatorLayout、AppBarLayout、 Toolbar、CollapsingToolbarLayout、NestedScrollView的使用。看上去很多,其实真的很简单。
我们先来看一下,使用这些控件最终实现的效果图,然后根据源码,逐一分析他所使用到的控件,及每个控件配置的属性.
完整代码下载地址。
这里给出代码,主要体现这些控件的嵌套关系,让你有总体的认识。
<span style="color:#000000"><code><android.support.design.widget.CoordinatorLayout
<span style="color:#000088 !important"><strong>...</strong></span>此处省略若干代码>
<android.support.design.widget.AppBarLayout
<span style="color:#000088 !important"><strong>...</strong></span>此处省略若干代码 >
<android.support.design.widget.CollapsingToolbarLayout
<span style="color:#000088 !important"><strong>...</strong></span>此处省略若干代码>
<ImageView
android:layout_width=<span style="color:#009900 !important">"match_parent"</span>
android:layout_height=<span style="color:#009900 !important">"match_parent"</span>
android:fitsSystemWindows=<span style="color:#009900 !important">"true"</span>
android:scaleType=<span style="color:#009900 !important">"centerCrop"</span>
android:src=<span style="color:#009900 !important">"@mipmap/ic_1"</span>
app:layout_collapseMode=<span style="color:#009900 !important">"parallax"</span>
app:layout_collapseParallaxMultiplier=<span style="color:#009900 !important">"0.5"</span>/>
<android.support.v7.widget.Toolbar
android:id=<span style="color:#009900 !important">"@+id/toolbar"</span>
android:layout_width=<span style="color:#009900 !important">"match_parent"</span>
android:layout_height=<span style="color:#009900 !important">"56dp"</span>
app:layout_collapseMode=<span style="color:#009900 !important">"pin"</span>
android:elevation=<span style="color:#009900 !important">"4dp"</span>
/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width=<span style="color:#009900 !important">"match_parent"</span>
android:layout_height=<span style="color:#009900 !important">"match_parent"</span>
app:layout_behavior=<span style="color:#009900 !important">"@string/appbar_scrolling_view_behavior"</span>
>
<span style="color:#000088 !important"><strong>...</strong></span>此处省略若干代码
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout></code></span>
- 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
1、CoordinatorLayout
这个控件到底能做什么呢?从字面上意思是协调子View的,就是我们滑动(或其他操作)一个Layout,另一个Layout自动执行相应已经设定好的操作。看下图就明白了
蓝色的是一个自定义View,可跟随手指移动
黄色的是一个Button。
他们之间的运动关系:它们在竖直方向同步移动,在水平方向相反。
这个效果如果让你不用CoordinatorLayout去实现,应该没有任何问题,但是代码的耦合度应该非常大,你的代码必须要持有2个View的引用,然后在onTouchEvent里面做各种判断。如果我们想要实现的功能是,有更多的View要根据蓝色的View的移动相应作出响应,那么那就得在蓝色View的onTounchEvent里面针对其他的View处理各种逻辑。这耦合度未免太伤感了~
而CoordinatorLayout既然号称能帮我们协调子View的布局,我们接下来看看CoordinatorLayout如何实现~
CoordinatorLayout使用
在使用前,需要了解三个概念:
- Dependency View (上图中的蓝色view)Child依赖的View
- child View (上图中的黄色Button)CoordinatorLayout的子View,操作Dependency View 时,根据Behavior类,对child View自动执行相关操作
- Behavior类,指定Child View的运动规则。自定义Behavior类,需要实现两个方法
简而言之,就是Dependency View发生了变化,那么Child View就要相应发生变化。
发生变化是具体发生什么变化呢?这里就要引入Behavior,Child发生变化的代码都是放在Behavior类里面。
怎么使用Behavior呢,首先,我们定义一个类,继承CoordinatorLayout.Behavior < T>,其中,泛型参数T是我们要执行动作的View类,也就是Child。然后就是去实现Behavior的两个方法:
<span style="color:#000000"><code><span style="color:#880000 !important">/**
* 判断child的布局是否依赖dependency
*/</span>
<span style="color:#9b859d !important">@Override</span>
<span style="color:#000088 !important"><strong>public</strong></span> <span style="color:#000088 !important"><strong>boolean</strong></span> <span style="color:#009900 !important"><strong>layoutDependsOn</strong></span>(CoordinatorLayout parent, T child, View dependency) {
<span style="color:#000088 !important"><strong>boolean</strong></span> rs;
<span style="color:#880000 !important">//根据逻辑判断rs的取值</span>
<span style="color:#880000 !important">//返回false表示child不依赖dependency,ture表示依赖</span>
<span style="color:#000088 !important"><strong>return</strong></span> rs;
}
<span style="color:#880000 !important">/**
* 当dependency发生改变时(位置、宽高等),执行这个函数
* 返回true表示child的位置或者是宽高要发生改变,否则就返回false
*/</span>
<span style="color:#9b859d !important">@Override</span>
<span style="color:#000088 !important"><strong>public</strong></span> <span style="color:#000088 !important"><strong>boolean</strong></span> <span style="color:#009900 !important"><strong>onDependentViewChanged</strong></span>(CoordinatorLayout parent, T child, View dependency) {
<span style="color:#880000 !important">//child要执行的具体动作</span>
<span style="color:#000088 !important"><strong>return</strong></span> <span style="color:#000088 !important"><strong>true</strong></span>;
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
看一下这个示例中的Behavior是怎么实现的
<span style="color:#000000"><code><span style="color:#000088 !important"><strong>public</strong></span> <span style="color:#000088 !important"><strong>class</strong></span> <span style="color:#4f4f4f !important"><strong>MyBehavior</strong></span> <span style="color:#000088 !important"><strong>extends</strong></span> <span style="color:#4f4f4f !important"><strong>CoordinatorLayout</strong></span>.<span style="color:#4f4f4f !important"><strong>Behavior</strong></span><<span style="color:#4f4f4f !important"><strong>Button</strong></span>> {
<span style="color:#000088 !important"><strong>private</strong></span> <span style="color:#000088 !important"><strong>int</strong></span> width;
<span style="color:#000088 !important"><strong>public</strong></span> MyBehavior(Context context, AttributeSet attrs) {
<span style="color:#000088 !important"><strong>super</strong></span>(context, attrs);
DisplayMetrics display = context.getResources().getDisplayMetrics();
width = display.widthPixels;
}
@Override
<span style="color:#000088 !important"><strong>public</strong></span> <span style="color:#000088 !important"><strong>boolean</strong></span> layoutDependsOn(CoordinatorLayout parent, Button child, View dependency) {
<span style="color:#880000 !important">//如果dependency是TempView的实例,说明它就是我们所需要的Dependency</span>
<span style="color:#000088 !important"><strong>return</strong></span> dependency instanceof TempView;
}
<span style="color:#880000 !important">//每次dependency位置发生变化,都会执行onDependentViewChanged方法</span>
@Override
<span style="color:#000088 !important"><strong>public</strong></span> <span style="color:#000088 !important"><strong>boolean</strong></span> onDependentViewChanged(CoordinatorLayout parent, Button btn, View dependency) {
<span style="color:#880000 !important">//根据dependency的位置,设置Button的位置</span>
<span style="color:#000088 !important"><strong>int</strong></span> top = dependency.getTop();
<span style="color:#000088 !important"><strong>int</strong></span> left = dependency.getLeft();
<span style="color:#000088 !important"><strong>int</strong></span> x = width - left - btn.getWidth();
<span style="color:#000088 !important"><strong>int</strong></span> y = top;
setPosition(btn, x, y);
<span style="color:#000088 !important"><strong>return</strong></span> <span style="color:#000088 !important"><strong>true</strong></span>;
}
<span style="color:#000088 !important"><strong>private</strong></span> <span style="color:#000088 !important"><strong>void</strong></span> setPosition(View v, <span style="color:#000088 !important"><strong>int</strong></span> x, <span style="color:#000088 !important"><strong>int</strong></span> y) {
CoordinatorLayout.MarginLayoutParams layoutParams = (CoordinatorLayout.MarginLayoutParams) v.getLayoutParams();
layoutParams.leftMargin = x;
layoutParams.topMargin = y;
v.setLayoutParams(layoutParams);
}
}</code></span>
- 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
OK,现在我们定义好了跟随Dependency一直变化的动作(Behavior),接下来我们就要指定哪个View来执行这些操作。方法很简单,直接在布局文件指定就好:
<span style="color:#000000"><code><span style="color:#006666 !important"><?xml version="1.0" encoding="utf-8"?></span>
<span style="color:#006666 !important"><<span style="color:#4f4f4f !important"><strong>android.support.design.widget.CoordinatorLayout
</strong></span> <span style="color:#4f4f4f !important">xmlns:android</span>=<span style="color:#009900 !important">"http://schemas.android.com/apk/res/android"</span>
<span style="color:#4f4f4f !important">xmlns:app</span>=<span style="color:#009900 !important">"http://schemas.android.com/apk/res-auto"</span>
<span style="color:#4f4f4f !important">android:layout_width</span>=<span style="color:#009900 !important">"match_parent"</span>
<span style="color:#4f4f4f !important">android:layout_height</span>=<span style="color:#009900 !important">"match_parent"</span>></span>
<span style="color:#006666 !important"><<span style="color:#4f4f4f !important"><strong>Button
</strong></span> <span style="color:#4f4f4f !important">android:layout_width</span>=<span style="color:#009900 !important">"wrap_content"</span>
<span style="color:#4f4f4f !important">android:layout_height</span>=<span style="color:#009900 !important">"wrap_content"</span>
<span style="color:#4f4f4f !important">android:background</span>=<span style="color:#009900 !important">"@color/colorPrimary"</span>
<span style="color:#4f4f4f !important">app:layout_behavior</span>=<span style="color:#009900 !important">"cn.xuexuan.newui.CoordinatorBehavior"</span>/></span>
<span style="color:#006666 !important"><<span style="color:#4f4f4f !important"><strong>cn.xuexuan.newui.MoveView
</strong></span> <span style="color:#4f4f4f !important">android:layout_width</span>=<span style="color:#009900 !important">"50dp"</span>
<span style="color:#4f4f4f !important">android:layout_height</span>=<span style="color:#009900 !important">"50dp"</span>
<span style="color:#4f4f4f !important">android:background</span>=<span style="color:#009900 !important">"@color/colorAccent"</span>
/></span>
<span style="color:#006666 !important"></<span style="color:#4f4f4f !important"><strong>android.support.design.widget.CoordinatorLayout</strong></span>></span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
至此,就可以实现上面动图的效果。
在最开始的那幅图中,在滑动时,自动改变AppBarLayout。你可能会想到,如果要实现图一的效果,那这个Behavior,肯定很难写啊。但是不用担心,android已经提供了这样的Behavior。来看一下面的这个控件
2、AppBarLayout
AppBarLayout 是继承LinerLayout实现的一个ViewGroup容器组件,它是为了Material Design设计的AppBar,支持手势滑动操作。默认的AppBarLayout是垂直方向的,它的作用是把AppBarLayout包裹的内容都作为AppBar。
它可以让你定制,当指定的View滚动时,AppBarLayout内部的子View实现何种动作。你想到了CoordinatorLayout,没错,并且AppBarLayout定义好了Behavior,只需要加上下面这句代码就可以使用。
<span style="color:#000000"><code>app:layout_behavior=<span style="color:#009900 !important">"<span style="color:#4f4f4f !important">@string</span>/appbar_scrolling_view_behavior"</span></code></span>
- 1
AppBarLayout,相当于CoordinatorLayout的dependency View。上行代码需要加到CoordinatorLayout的child view中(下面会介绍)。
AppBarLayout子View的动作
内部的子View通过在布局中加app:layout_scrollFlags设置执行的动作,那么app:layout_scrollFlags可以设置哪些动作呢?分别如下:
1、 scroll: 跟随滚动事件一起发生移动。
就是当指定的ScrollView发生滚动时,该View也跟随一起滚动,就好像这个View也是属于这个ScrollView一样。想滚动就必须设置这个。可配合下面几项一起使用
2、 enterAlways: 当ScrollView滑动时,先滑动AppBarLayout,再响应ScrollView的内部滑动事件
3、 enterAlwaysCollapsed:是enterAlways的附加选项,一般跟enterAlways一起使用。往下滑动时,当AppBarLayout的高度达到最小高度时,就暂时不去往下滚动,直到ScrollView滑动到顶部不再滑动时,AppBarLayout再继续往下滑动
4、 exitUntilCollapsed:当AppBarLayout要往上逐渐“消逝”时,会一直往上滑动,直到剩下的的高度达到它的最小高度后,再响应ScrollView的内部滑动事件。
3、NestedScrollView
图一中,滚动操作,AppBarLayout会进行收缩和扩张,这个可滚动的view,就是这个控件。
它并没有继承ScrollView,它继承的是FrameLayout,但是它实现的效果把它可以看成是ScrollView。
作为CoordinatorLayout的child view,并在xml设置AppBarLayout类已经实现的Behavior。
<span style="color:#000000"><code><span style="color:#006666 !important"><<span style="color:#4f4f4f !important"><strong>android.support.v4.widget.NestedScrollView
</strong></span> <span style="color:#4f4f4f !important">android:layout_width</span>=<span style="color:#009900 !important">"match_parent"</span>
<span style="color:#4f4f4f !important">android:layout_height</span>=<span style="color:#009900 !important">"wrap_content"</span>
<span style="color:#4f4f4f !important">app:layout_behavior</span>=<span style="color:#009900 !important">"@string/appbar_scrolling_view_behavior"</span>></span>
<span style="color:#880000 !important"><!--将你的内容放在这里--></span>
<span style="color:#006666 !important"></<span style="color:#4f4f4f !important"><strong>android.support.v4.widget.NestedScrollView</strong></span>></span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
@string/appbar_scrolling_view_behavio 是AppBarLayout中的Behavior类名
你可能会想到,既然Behavior已经在AppBarLayout类中实现了,干嘛还非要使用NestedScrollView,使用ScrollView不可以吗?
经过我的测试,换做ScrollView还真的不行,但是看到这篇文章中,用在了SwipeRefreshLayout、ViewPager、RecycleView上,我猜想,难道只能用在android.support.v4.widget包里的控件上???
讲到这里你可能已经大概有个了解,但是好像还是有点不明白,AppBarLayout中的图片,滑动效果怎么实现,返回箭头怎么固定住的呢,title颜色渐变怎么控制?那就让我们来看看下面这个控件,一切都会明白
4、CollapsingToolbarLayout
CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承FrameLayout,它可以控制包含在CollapsingToolbarLayout中的控件(如:ImageView、Toolbar)在响应layout_behavior事件时作出相应的scrollFlags滚动事件(移除屏幕或固定在屏幕顶端)。
它通常作为AppBarLayout子View使用,所以可以给它设置layout_scrollFlags。
在CollapsingToolbarLayout的子View中可以设置以下属性:
-
layout_collapseMode (折叠模式) - 有两个值:
- pin - 设置为这个模式时,当CollapsingToolbarLayout完全收缩后,Toolbar还可以保留在屏幕上。
- parallax - 设置为这个模式时,在内容滚动时,CollapsingToolbarLayout中的View(比如ImageView)也可以同时滚动,实现视差滚动效果,和layout_collapseParallaxMultiplier搭配使用。
- layout_collapseParallaxMultiplier(视差因子) - 设置视差滚动因子,值为:0~1。
-
contentScrim - 设置当CollapsingToolbarLayout完全折叠(收缩)后的背景颜色
-
expandedTitleMarginStart - 设置扩张时候(还没有收缩时)title向左填充的距离。
改变title的字体颜色:
扩张时候的title颜色:
<span style="color:#000000"><code>mCollapsingToolbarLayout<span style="color:#009900 !important">.setExpandedTitleColor</span>()<span style="color:#880000 !important">;</span></code></span>
- 1
收缩后在Toolbar上显示时的title的颜色:
<span style="color:#000000"><code>mCollapsingToolbarLayout<span style="color:#009900 !important">.setCollapsedTitleTextColor</span>()<span style="color:#880000 !important">;</span></code></span>
- 1
更多详细用法:AndroidASD完全解析06之CollapsingToolbarLayout
5、Toolbar
Android 3.0 Android 推了 ActionBar 这个控件,而到了2013 年 Google 开始大力地推动所谓的 android style,想要逐渐改善过去 android 纷乱的界面设计,希望让终端使用者尽可能在 android 手机有个一致的操作体验。官方在某些程度上认为 ActionBar 限制了 android app 的开发与设计的弹性,在Lollipop推出了ToolBar来取代过去 actionbar 的控件,而现在于 material design 中也对之有一个统一名称:app bar,在未来的 android app 中,就以 toolbar 这个元件来实现。
由于ToolBar是API 21才有的UI控件,为了适配低版本的系统,在AppCompat V7当中也提供了ToolBar,所以我们一般在开发的时候使用的是V7中的ToolBar
介绍一下使用Toolbar的步骤:
1、style
你对ActionBar的使用比较熟悉,你会发现Toolbar使用起来非常简单。ok,既然是替换,当然用Toolbar的时候就得先去把ActionBar给隐藏掉啦~
<span style="color:#000000"><code><span style="color:#880000 !important"><!-- Base application theme. --></span>
<span style="color:#006666 !important"><<span style="color:#4f4f4f !important"><strong>style</strong></span> <span style="color:#4f4f4f !important">name</span>=<span style="color:#009900 !important">"AppTheme.Base"</span> <span style="color:#4f4f4f !important">parent</span>=<span style="color:#009900 !important">"Theme.AppCompat"</span>></span>
<!<span style="color:#000000 !important">--</span> <span style="color:#000000 !important">Customize</span> <span style="color:#000000 !important">your</span> <span style="color:#000000 !important">theme</span> <span style="color:#000000 !important">here</span>. <span style="color:#000000 !important">--</span>>
<<span style="color:#000000 !important">item</span> <span style="color:#000000 !important">name</span>="<span style="color:#000000 !important">windowActionBar</span>"><span style="color:#000000 !important">false</span></<span style="color:#000000 !important">item</span>>
<<span style="color:#000000 !important">item</span> <span style="color:#000000 !important">name</span>="<span style="color:#000000 !important">android</span><span style="color:#000000 !important">:windowNoTitle"</span>><span style="color:#000000 !important">true</span></<span style="color:#000000 !important">item</span>>
<span style="color:#006666 !important"></<span style="color:#4f4f4f !important"><strong>style</strong></span>></span>
<span style="color:#006666 !important"><<span style="color:#4f4f4f !important"><strong>style</strong></span> <span style="color:#4f4f4f !important">name</span>=<span style="color:#009900 !important">"AppTheme"</span> <span style="color:#4f4f4f !important">parent</span>=<span style="color:#009900 !important">"AppTheme.Base"</span>></span>
<span style="color:#006666 !important"></<span style="color:#4f4f4f !important"><strong>style</strong></span>></span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2、xml文件
在 activity_main.xml 里面添加 Toolbar 控件:
<span style="color:#000000"><code><android<span style="color:#009900 !important">.support</span><span style="color:#009900 !important">.v</span>7<span style="color:#009900 !important">.widget</span><span style="color:#009900 !important">.Toolbar</span>
android:id=<span style="color:#009900 !important">"@+id/toolbar"</span>
android:layout_height=<span style="color:#009900 !important">"?attr/actionBarSize"</span>
android:layout_width=<span style="color:#009900 !important">"match_parent"</span> >
</android<span style="color:#009900 !important">.support</span><span style="color:#009900 !important">.v</span>7<span style="color:#009900 !important">.widget</span><span style="color:#009900 !important">.Toolbar</span>></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
请记得用 support v7 里的 toolbar,不然然只有 API Level 21 也就是 Android 5.0 以上的版本才能使用。
3 、程序 (Java)
在 java文件 中加入 Toolbar 的声明:
<span style="color:#000000"><code>Toolbar toolbar = (Toolbar) findViewById(R<span style="color:#009900 !important">.id</span><span style="color:#009900 !important">.toolbar</span>)<span style="color:#880000 !important">;</span>
setSupportActionBar(toolbar)<span style="color:#880000 !important">;</span></code></span>
- 1
- 2
那为啥要用ToolBar替换ActionBar呢,总应该有他的理由吧:ActionBar是固定在顶部,并不能移动,我觉得这是最大的不好,而ToolBar可以随便摆放,就可以带来很多灵活性和效果啦!
因为在这个项目中使用ToolBar特性不多,这里不过多介绍,想了解更多可以参考android:ToolBar详解(手把手教程)
参考:
关于 APP Bar(ToolBar、CoordinatorLayout、AppBarLayout、CollapsingToolbarLayout)