随着Android Studio2.3正式版本的发布,约束布局(ConstraintLayout)也进入了1.0.1正式版,是时候进入安卓开发布局的新阶段了。
约束布局的概念第一次接触是在iOS开发的学习当中,苹果官方将约束布局叫做AutoLayout,但最终的实现其实就是约束布局。严格来讲,称为约束布局更为合适。
苹果官方在iOS5版本中引入了Storyboard方式实现使用拖拽方式完成布局,Storyboard中文可以翻译为故事板。这个名称取的非常有意思,而且还带有一些文艺色彩,开发一款APP其实恰好就是你给使用者讲的一个有意思的故事。虽然Storyboard已经推出了很久,却一直没有完全被大家所接受。普遍的一个论点认为:Storyboard在多人开发协作的时候将导致维护起来非常麻烦,因为Storyboard的xml可读性非常差,通过拖拉产生的改变导致xml的变化不计其数,这在多人开发的过程中无疑是灾难性的。但其实官方没有明确说明的是,Storyboard是可以同时使用多个的。比如,每一个功能模块使用一个Storyboard,每一个人负责一个模块,这就有效地避免了多人共同维护一个Storyboard的问题。尽管如此,由于前期的一些误解,导致中国iOS开发圈依然有大量的程序员使用代码进行约束布局。我想,这大约是苹果官方不愿意看到的吧!
言归正传,回到安卓的约束布局。
为了保证约束布局更便于理解,安卓官方引入了很多新的概念。但很多人一看到概念就会头晕脑胀。因此,本篇我们不讲任何理论和概念,具体的概念和理论留到最后一个章节讲解。
理解ConstraintLayout
约束布局的意思其实很简单,就是通过一系列的限制,让某个控件的位置实现唯一确定,这就是约束布局的核心思想。这样做的一个好处就是,避免了控件的无限制嵌套,减少过度绘制问题。看下面一个形象的例子:
假设这是一个垂直放置的矩形面板,这只可爱的小猫距离垂直边缘距离20m,距离水平边缘30m,这样在一个平面内,小猫的位置就唯一确定了。无论面板如何变化,他在面板里面的位置都是唯一确定的。距离垂直边缘距离20m和距离水平边缘30m这两个条件其实就是两个约束,学过基础数学的同学都知道在二维空间通过一个二维坐标(x,y)可以确定唯一的点,就是这个道理。
这个数学知识也告诉我们:要想唯一确定某个物体的位置,在水平和垂直方向必须至少各有一个约束条件。
约束布局的基础理论体系就建立在上面这个简单的数学知识之上,下面来实际操作一下,看一看安卓的约束布局是否设计的够简单,能否与iOS的自动布局相媲美。
实现一个简单的登录页面
添加依赖
dependencies {
...
compile 'com.android.support.constraint:constraint-layout:1.0.1'
...
}
Note:推荐使用Android Studio 2.3,创建安卓工程会默认添加这个依赖,并且在创建约束布局的时候会给予友好的提示。
Let's get started
要实现这样一个布局,首先确定一个控件的绝对位置,其他控件可以以这个控件作为基点,来实现绝对定位。这里我们选择[用户名]这个TextView ,添加如下约束:
<TextView
android:layout_width="50dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="20dp"
android:layout_marginLeft="10dp"
android:textSize="16dp"
android:textColor="@color/yaHei"
android:text="@string/username"
android:gravity="right"
android:id="@+id/text_username"/>
这里的意思,其实可以通过英文意思去理解一下,其实是给TextView添加了两个约束:
- TextView的顶部与父布局的顶部对齐
- TextView的左边和父布局的左边对齐
这两个约束分别作用在x和y方向,已经可以实现TextView位置的唯一确定。最后,通过添加margin就实现如上图的效果,接下来来确定用户名输入框,依然很简单,看下面一段xml:
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBaseline_toBaselineOf="@id/text_username"
app:layout_constraintLeft_toRightOf="@id/text_username"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:textSize="16dp"
android:textColor="@color/yaHei"
android:hint="@string/input_username_please"/>
这里对EditText添加了三个约束:
- EditText保持和上面的TextView基线对齐
- EditText的左侧和TextView的右侧对齐
- EditText的右侧和父布局对齐
这三个约束也保证了EditText位置的唯一确定,实现了如上图所示的效果。其他两个控件使用类似的方式实现了位置的唯一确定,这里就不赘述了,大家可以去我的Github进行Clone阅读。
小结
这篇文章只是简单地让大家了解了一下安卓最新推荐使用的ConstraintLayout的基本用法,没有涉及到任何相关的概念,因为我害怕一堆的概念一定会吓跑一批不敢去尝试新鲜事物的同学。因此,我希望大家在不了解概念的前提下看看约束布局使用起来是否非常简单,是否值得一试。
扩展
这不就是相对布局吗?
一定会有很多人产生这样的感觉。的确,相对布局可以实现其中的部分功能,可在很多场景中,相对布局是无法实现的。比如:基线对齐,两个控件的宽度按照一定的比例约束,单个控件的宽高也可以按照比例显示等等这些场景都是相对布局无法做到的。ConstraintLayout试图打造一个万能布局,换而言之,原来所学的五种布局(LinearLayout,FrameLayout,RelativeLayout,TableLayout,GridLayout)都可以舍弃了,可以完全使用这一个布局来实现所有的复杂布局,这是安卓官方的设计初衷。
这种布局有什么好处?
一定会有人有这样的疑问,有人甚至会想,如果布局较为复杂,满屏的约束会不会让人感到混乱。首先,上面的描述中我已经说了约束布局的第一个好处,就是:我们终于可以不用再记那么多布局了,仅仅使用这一个布局方式就可以实现所有复杂的布局。这一点iOS程序员体现的非常明显,最初的iOS开发是直接写死多少像素的,使用逐帧的方式布局。所以,你可以看到iOS程序员常常对一个像素非常敏感,原因就在于此。后面由于iOS设备越来越多,单一的逐帧布局已经无法满足需要,这种场景下约束布局应运而生。而到现在为止,这种布局iOS同学已经用了好几年,他们从来不需要去了解其他的布局方式,这就是约束布局的伟大之处。
第二个更屌的地方就是:也许拖拉一下我们就完成了布局。上面有提到,iOS官方推荐使用Storyboard实现自动布局,这种方式就是拖拉的典型代表。iOS同学已经享用了这种便利好几年,安卓同学终于拨开云雾见青天了。这个部分的讲解我们放到最后,和概念一起讲,前期我们一直使用xml实现布局。
约束布局可以嵌套吗?
应该有部分同学会有这样的疑问,答案是:当然可以。约束布局是继承自ViewGroup,实现了根据约束条件完成布局的逻辑(其实这并不简单)。所以,嵌套是一定可以的,如果你有需要嵌套约束布局才能完成的UI,大胆去做吧。
约束布局的性能如何?
其实,约束布局的诞生,从某种层面来说就是为了解决安卓布局不断嵌套的问题,减少过度绘制,避免过度绘制的开销。如果设计优良,在使用复杂布局时,毫无疑问,约束布局的性能是要高于其他布局方式的。所以,未来开发过程中,我推荐大家使用约束布局。
最佳的学习资料
https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html
https://github.com/googlesamples/android-ConstraintLayoutExamples
这篇文章的Git代码地址:https://github.com/yuanhoujun/ConstraintLayoutSamples ,欢迎大家下载学习,后期的关于约束布局的讲解代码依然会放到这个仓库里面。