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