到这里基本上你已经掌握了 Android 所有的常用控件,不知道有没有这样的疑惑:如果控件太多,在有的小尺寸手机上将屏幕占满了怎么办?是不是有一种通用的解决方法?没错,本节的主角——ScrollView 就是来帮你解决这个问题的,它让你的控件能够在屏幕显示不足的情况下,支持滚动展示。
1. ScrollView 的特性
ScrollView 是一种可以有效解决由于 View 过多显示不全的布局,它可以让控件在横向或者纵向上支持滚动显示。它其实是一个 FrameLayout,内部可以包含一个或多个 View / ViewGroup,当然它的滚动效果也只会作用于子 View / ViewGroup 当中。
另外需要注意的是因为它是一个 FrameLayout,所以我们需要注意它的布局排列方式(对于 FrameLayout 的布局方式可以参考第 11 节的内容),大多数场景下我们需要结合其他的布局一起使用,其实最简单的使用方式就是直接在写好的布局外面套一个 ScrollView 就可以支持滚动了。
ScrollView 默认是纵向的滚动,如果需要横向滚动可以使用HorizontalScrollView,只是方向不同,用法是完全一样的。
注:对于需要支持滚动的场景而言,ScrollView 是一个非常完美的解决方案,但是我们后面会学到两大滚动列表控件——ListView / GridView,因为这两个控件天生就带有滚动效果,所以通常我们不会将 ScrollView 和这两个控件一起使用。
2. ScrollView 的基本用法
通常无论是控件还是布局我们会先介绍属性,但是 ScrollView 本质是一个 FrameLayout,作用也只是增加一个滚动效果,并没有什么很特别的属性,这里主要介绍一下几个控制滚动的 API:
fullScroll():
将列表滚动到顶部或者底部:ScrollView.FOCUS_DOWN 表示滚动到底部;ScrollView.FOCUS_UP 表示滚动到顶部。
scrollTo():
将列表滚动到指定位置,参数为 x/y,分别表示横纵坐标的坐标值。这里要注意如果是纵向的 ScrollView,那么横坐标(x)是无效的;相反横向的 ScrollView,纵向(y)是无效的。
3. ScrollView 使用示例
ScrollView 的适用场景也很明显,我们人为创造一个 View 过多的场景即可。
3.1 布局文件的编写
首先布局文件主要包括 3 个部分:
Button——用于点击回到顶部;
Button——用于点击跳转底部;
ScrollView——包含过多的子 View,支持滚动。
然后我们将两个用于跳转的 Button 放入一个 LinearLayout 中,和 ScrollView 同层,这样两个 Button 就不会响应 ScrollView 的滑动,然后在 ScrollView 中添加一个 LinearLayout 用来管理需要滑动的 n 个 View,布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="30dp"> <LinearLayout android:id="@+id/button_group" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="80dp" android:text="ScrollView" android:textSize="25dp" android:textStyle="bold" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="20dp" android:text="Welcome to Android" /> <!-- 在Java代码中动态添加若干个Button,超出屏幕范围即可滑动 --> </LinearLayout> </ScrollView> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <Button android:id="@+id/bt_to_top" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:text="滚动到顶部" /> <Button android:id="@+id/bt_to_bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:text="跳转到底部" /> </LinearLayout> </FrameLayout>
3.2 Java 文件编写
以上代码主要实现了两个 Button 及一个 ScrollView,可以看到 ScrollView 中只有一个 LinearLayout,而 LinearLayout 中只有两个 Button,所以我们需要在 Java 代码中动态添加 Button,这里也可以让大家熟悉一下如何动态创建并添加 Button。接下来在 Java 代码中主要做两件事:
为两个 Button 设置点击事件,分别实现回到顶部及跳转到底部;
往 ScrollView 中添加 View,并绑定点击事件。
代码如下:
package com.emercy.myapplication; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.Toast; public class MainActivity extends Activity implements View.OnClickListener { public static final int BUTTON_COUNT = 10; private ScrollView mScrollView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.bt_to_top).setOnClickListener(this); findViewById(R.id.bt_to_bottom).setOnClickListener(this); mScrollView = findViewById(R.id.scrollView); LinearLayout layout = findViewById(R.id.button_group); for (int i = 0; i < BUTTON_COUNT; i++) { Button button = new Button(this); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); params.topMargin = 100; layout.addView(button, params); button.setOnClickListener(this); button.setText(i + ""); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_to_top: mScrollView.fullScroll(ScrollView.FOCUS_UP); break; case R.id.bt_to_bottom: mScrollView.fullScroll(ScrollView.FOCUS_DOWN); break; default: Toast.makeText(this, "当前点击的是第" + ((Button) v).getText() + "个Button", Toast.LENGTH_SHORT).show(); break; } } }
效果如下:
我们在代码中通过 for 循环往 ScrollView 中添加了 10 个 Button,动态添加一个 View 主要有以下 4 步:
通过构造器创建 View。
设置其属性(宽、高、margin、padding 等)。
设置响应事件(比如点击、触摸、滚动等)。
添加到相应的 ViewGroup 中。
我们在创建 Button 的同时通过setText及setOnClickListener设置了文本及点击事件,然后在点击的时候展示当前 Button 的序号。
4. 小结
本节学习了一个新的 ViewGroup,它主要解决的就是当子 View 过多而导致屏幕显示不下的问题。通过将过多的 View 放在一个 ScrollView 当中,系统会让这些 View 支持列表滑动显示,并提供了简单的 API 帮助我们操作列表。对于需要横向排列的 View 我们直接将 ScrollView 换成 HorizontalScrollView 即可,其他的使用方式完全一样。
整体来说 ScrollView 是一种比较直接的实现列表的方式,优点是使用简单,而且一目了然;缺点是数据和 UI 强耦合在一起,我们需要考虑的东西非常多,在实现复杂列表逻辑的时候会显得很臃肿,这点在下一节以及后面学到 ListView / GridView 之后就会有深切的体会。