5.5 让内容滚动
在上一节做的登录页面上增加一个按钮“注册”,将ID设为“buttonRegister”,放到“登录”按钮的下面,效果如图5-56所示。然后运行App,旋转一下屏幕,运行效果如图5-57所示。
“注册”按钮看不到了!为什么?显然屏幕的高度不够了,内容在纵向上超出了屏幕,怎么办呢?使用滚动条!然而,Layout是没有滚动功能的,要想提供滚动功能,需要使用控件ScrollView。
ScrollView可以在子控件高度超出自己的范围时在纵向上提供滚动功能。如果想横向滚动,可以使用HorizontalScrollView。各种ScrollView都有自己的要求:只能容纳一个子控件。
图5-56
图5-57
我们让ConstraintLayout成为ScrollView的子控件,然后设置ConstraintLayout的高度由其内容决定,也就是由组成登录界面的各子控件来共同决定。ScrollView必须有办法计算出其子控件的高度才行,否则不知道该怎么滚。所以ConstraintLayout被放在ScrollView中后,其高度不能再设为match_parent,如果子控件的高度永远与它一样高,那么永远不需要滚动。其子控件应体现出内容的高度,这里也就是组成登录功能的控件共同占据的高度,所以RelativeLayout的layout_height值必须为wrap_content。下面我们按照这个原理一步步改造界面。
5.5.1 添加ScrollView作为最外层容器
可以试着拖一个ScrollView到页面中,如图5-58所示。不行,无法将控件拖到页面中作为最外层的控件,此时需要手动编辑源码。把页面切换到源码模式,在最外层的元素“<android.support.constraint. ConstraintLayout>”外面添加标记“<ScrollView>”,在ConstraintLayout的结束标记“</android.support. constraint.ConstraintLayout>”下面添加ScrollView的结束标记“</ScrollView>”,也就是让ScrollView元素包着RelativeLayout元素。然后,还需要把RelativeLayout标记中的一些属性(这些属性必须放在最外层的元素中)移动到ScrollView标记中:
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".MainActivity"
图5-58
还要为ScrollView设置宽和高。它既然是最外层的控件,就应该充满整个父控件(Activity)。现在layout文件的源码变为:
切换到预览模式,会惊奇地发现ConstraintLayout的高度变了,如图5-59所示。虽然ConstraintLayout的高度值还是match_parent,但是被放到在ScrollView中时这个值并不起作用,实际上却变成了wrap_content。
图5-59
再运行App,旋转屏幕,就可以上下滚动了,效果如图5-60所示。
图5-60
5.5.2 禁止旋转
除了使用ScrollView外,还有一个办法可以解决横屏显示不全的问题,那就是不支持横屏!这需要固定Activity的方向,即在Manifest文件中设一下,如图5-61所示。
属性名screenOrientation表示屏幕方向,值portrait(原意是肖像画,是长的)表示竖屏、landscape(原意是风景画,是宽的)表示横屏。如果不设置此属性,就表示横竖屏都支持。
图5-61
5.5.3 为横屏和竖屏分别创建Layout
可以为一个页面创建横屏和竖屏两个资源。Android App会根据屏幕方向自动选择资源,为横屏和竖屏创建看起来很不一样的界面效果。实际上这个功能除了支持横屏和竖屏外,还支持不同的屏幕分辨率。当然最好还是用一个Layout能自适应横屏、竖屏和各种分辨率,但有时是做不到的。
下面将当前Layout作为竖屏资源,演示一下如何为它创建横屏资源。选择菜单命令,如图5-62所示。
图5-62
选择“Create Landscape Variation(创建横屏变体)”命令,会为当前Layout添加一个新的资源文件。新文件默认复制了原文件的内容,可以在此基础上进行修改,比如把ScrollView去掉,因为我们可以在Landscape资源中以另一种方式摆放控件让它们充分利用横屏空间。
当前资源下面包含了两个文件(见图5-63),在文件系统中的组织和命名如图5-64所示。
图5-63
图5-64
5.5.4 让内容居中
现在还有一个不完美的地方:内容不居中。在竖屏时,内容靠在上部,最好的方式是屏幕足够时居中,屏幕不够时滚动。注意,要先把横屏layout文件删掉。
ScrollView代表屏幕(充满父控件),ConstraintLayout代表内容区,只要设置ConstraintLayout在ScrollView纵向上居中就能达到目标。设置方法有两种:一是查找ScrollView中是否存在设置子控件摆放位置的属性,二是查找ConstraintLayout中是否存在设置其在父控件中如何摆放的属性。ConstraintLayout中有个叫layout_gravity的属性,表示其在父控件中的重心,有很多值可以设置,这里设置为center_vertical,如图5-65所示。
图5-65
ConstraintLayout纵向居中了,收工!