滾動(dòng)條 ScrollView
到這里基本上你已經(jīng)掌握了 Android 所有的常用控件,不知道有沒(méi)有這樣的疑惑:如果控件太多,在有的小尺寸手機(jī)上將屏幕占滿了怎么辦?是不是有一種通用的解決方法?沒(méi)錯(cuò),本節(jié)的主角——ScrollView 就是來(lái)幫你解決這個(gè)問(wèn)題的,它讓你的控件能夠在屏幕顯示不足的情況下,支持滾動(dòng)展示。
1. ScrollView 的特性
ScrollView 是一種可以有效解決由于 View 過(guò)多顯示不全的布局,它可以讓控件在橫向或者縱向上支持滾動(dòng)顯示。它其實(shí)是一個(gè) FrameLayout,內(nèi)部可以包含一個(gè)或多個(gè) View / ViewGroup,當(dāng)然它的滾動(dòng)效果也只會(huì)作用于子 View / ViewGroup 當(dāng)中。
另外需要注意的是因?yàn)樗且粋€(gè) FrameLayout,所以我們需要注意它的布局排列方式(對(duì)于 FrameLayout 的布局方式可以參考第 11 節(jié)的內(nèi)容),大多數(shù)場(chǎng)景下我們需要結(jié)合其他的布局一起使用,其實(shí)最簡(jiǎn)單的使用方式就是直接在寫好的布局外面套一個(gè) ScrollView 就可以支持滾動(dòng)了。
ScrollView 默認(rèn)是縱向的滾動(dòng),如果需要橫向滾動(dòng)可以使用HorizontalScrollView
,只是方向不同,用法是完全一樣的。
注:對(duì)于需要支持滾動(dòng)的場(chǎng)景而言,ScrollView 是一個(gè)非常完美的解決方案,但是我們后面會(huì)學(xué)到兩大滾動(dòng)列表控件——ListView / GridView,因?yàn)檫@兩個(gè)控件天生就帶有滾動(dòng)效果,所以通常我們不會(huì)將 ScrollView 和這兩個(gè)控件一起使用。
2. ScrollView 的基本用法
通常無(wú)論是控件還是布局我們會(huì)先介紹屬性,但是 ScrollView 本質(zhì)是一個(gè) FrameLayout,作用也只是增加一個(gè)滾動(dòng)效果,并沒(méi)有什么很特別的屬性,這里主要介紹一下幾個(gè)控制滾動(dòng)的 API:
- fullScroll():
將列表滾動(dòng)到頂部或者底部:ScrollView.FOCUS_DOWN
表示滾動(dòng)到底部;ScrollView.FOCUS_UP
表示滾動(dòng)到頂部。 - scrollTo():
將列表滾動(dòng)到指定位置,參數(shù)為 x/y,分別表示橫縱坐標(biāo)的坐標(biāo)值。這里要注意如果是縱向的 ScrollView,那么橫坐標(biāo)(x)是無(wú)效的;相反橫向的 ScrollView,縱向(y)是無(wú)效的。
3. ScrollView 使用示例
ScrollView 的適用場(chǎng)景也很明顯,我們?nèi)藶閯?chuàng)造一個(gè) View 過(guò)多的場(chǎng)景即可。
3.1 布局文件的編寫
首先布局文件主要包括 3 個(gè)部分:
- Button——用于點(diǎn)擊回到頂部;
- Button——用于點(diǎn)擊跳轉(zhuǎn)底部;
- ScrollView——包含過(guò)多的子 View,支持滾動(dòng)。
然后我們將兩個(gè)用于跳轉(zhuǎn)的 Button 放入一個(gè) LinearLayout 中,和 ScrollView 同層,這樣兩個(gè) Button 就不會(huì)響應(yīng) ScrollView 的滑動(dòng),然后在 ScrollView 中添加一個(gè) LinearLayout 用來(lái)管理需要滑動(dòng)的 n 個(gè) 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 Imooc Android" />
<!-- 在Java代碼中動(dòng)態(tài)添加若干個(gè)Button,超出屏幕范圍即可滑動(dòng) -->
</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="滾動(dòng)到頂部" />
<Button
android:id="@+id/bt_to_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="跳轉(zhuǎn)到底部" />
</LinearLayout>
</FrameLayout>
3.2 Java 文件編寫
以上代碼主要實(shí)現(xiàn)了兩個(gè) Button 及一個(gè) ScrollView,可以看到 ScrollView 中只有一個(gè) LinearLayout,而 LinearLayout 中只有兩個(gè) Button,所以我們需要在 Java 代碼中動(dòng)態(tài)添加 Button,這里也可以讓大家熟悉一下如何動(dòng)態(tài)創(chuàng)建并添加 Button。接下來(lái)在 Java 代碼中主要做兩件事:
- 為兩個(gè) Button 設(shè)置點(diǎn)擊事件,分別實(shí)現(xiàn)回到頂部及跳轉(zhuǎn)到底部;
- 往 ScrollView 中添加 View,并綁定點(diǎn)擊事件。
代碼如下:
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, "當(dāng)前點(diǎn)擊的是第" + ((Button) v).getText() + "個(gè)Button", Toast.LENGTH_SHORT).show();
break;
}
}
}
效果如下:
我們?cè)诖a中通過(guò) for 循環(huán)往 ScrollView 中添加了 10 個(gè) Button,動(dòng)態(tài)添加一個(gè) View 主要有以下 4 步:
- 通過(guò)構(gòu)造器創(chuàng)建 View。
- 設(shè)置其屬性(寬、高、margin、padding 等)。
- 設(shè)置響應(yīng)事件(比如點(diǎn)擊、觸摸、滾動(dòng)等)。
- 添加到相應(yīng)的 ViewGroup 中。
我們?cè)趧?chuàng)建 Button 的同時(shí)通過(guò)setText
及setOnClickListener
設(shè)置了文本及點(diǎn)擊事件,然后在點(diǎn)擊的時(shí)候展示當(dāng)前 Button 的序號(hào)。
4. 小結(jié)
本節(jié)學(xué)習(xí)了一個(gè)新的 ViewGroup,它主要解決的就是當(dāng)子 View 過(guò)多而導(dǎo)致屏幕顯示不下的問(wèn)題。通過(guò)將過(guò)多的 View 放在一個(gè) ScrollView 當(dāng)中,系統(tǒng)會(huì)讓這些 View 支持列表滑動(dòng)顯示,并提供了簡(jiǎn)單的 API 幫助我們操作列表。對(duì)于需要橫向排列的 View 我們直接將 ScrollView 換成 HorizontalScrollView 即可,其他的使用方式完全一樣。
整體來(lái)說(shuō) ScrollView 是一種比較直接的實(shí)現(xiàn)列表的方式,優(yōu)點(diǎn)是使用簡(jiǎn)單,而且一目了然;缺點(diǎn)是數(shù)據(jù)和 UI 強(qiáng)耦合在一起,我們需要考慮的東西非常多,在實(shí)現(xiàn)復(fù)雜列表邏輯的時(shí)候會(huì)顯得很臃腫,這點(diǎn)在下一節(jié)以及后面學(xué)到 ListView / GridView 之后就會(huì)有深切的體會(huì)。