#UIScrollViewクラスとは
UIScrollView(以下,SV)は,画面に触れた指などの動きを追跡することで,画面サイズよりもはみ出たコンテンツを表示させるためのUI部品です。 UITableViewやUITextViewも画面からはみ出た範囲をスクロールさせることができますが,その理由は,SVがこれらのスーパークラスであるためです。
#環境
- XCode Version 10.2.1
- Swift 5.0
第1章 とりあえずスクロールさせる
ここではスクロールするコンテンツをstoryboardを用いて作製してみます。実践には程遠いですが何事も基本が大切なので基礎固めしていきましょう。でも本当に固まってはいけません。
###SVの配置
ナビゲータエリアからMain.storyboardを選択し,Objectライブラリから「Scroll View」を選びます。それを画面(View)上にドロップします。ドロップしたSVを画面全体に広げます。もちろん必ずしも画面全体に広げる必要はありません。用途に応じてサイズを変更させてください。ここでは練習のため画面全体に広げているだけです。
###コンテンツビューの配置
実際にスクロールさせる部品であるコンテンツビュー(contents view)を配置します。コンテンツビューにはUIViewを用いることが多いと思います。Objectライブラリから「View」を選択し,SV上にドロップします。以後分かりやすいようにViewの名前を「contentsView」に変更します。
大きさと位置を決めましょう。右上にある「Show the Size inspector」にある「width」と「height」にぞれぞれ「800」と「1200」を設定します。このcontentsView
を上下左右に青い点線が出るところに配置します。もし上手くいかなければ,「Show the Size inspector」の「X」と「Y」にそれぞれ「-193」と「-152」を入力してください(iPhoneXRを選択していること)。もちろんこれらも用途に合わせて自由に設定してください。
コンテンツビューだけではスクロールしているかどうかの判別が付かないのでUILabelを配置させましょう。Objectライブラリから「label」を選び,contentsView
上にドロップさせ,上下左右に青い点線が出るところに配置させます。
###コンテンツビューのレイアウト
まだ各UI部品の位置関係についても何も制約をかけていませんでしたので制約をかけていきます。View Controllerを選択してある状態で画面右下の「Resolve Auto Layout issues」を押します。その中にある「All Views in Container」欄の「Add Missing Constraints」を押します。すると下図のように制約がかかると思います。
お疲れさまです。ここまできたら一旦ビルドしてみて下さい。ビルド後,画面をマウスなどで動かして見てください。おそらく動かないはずです。衝撃的ですよね。ここまで説明しておいて動かないなんて。SV上にはそれより大きなcontentsView
を配置したのでスクロールできても良さそうですが何故かできせん。Appleが悪いわけではありません。制約のかけ方が間違っているからです。下図の青色の点線で囲んだところをよく見てください。
例えばSVのbottomの位置をみるとcontentsView
から152下がった位置で制約がかかっています。上下左右ともSVとcontentsView
の位置はガチガチに制約がかかっている状態です。この状態ではスクロールはできません。
それではスクロールができるように制約をかけ直しましょう。まず上の青い点線で囲んだ「Constraints」を消します。次に,contentsViewを選択し,画面右下にある「Add New Constraints」を押し,4つとも「0」を入力します。そして最後に「Add 4 Constraints」を押し,ビルドしてください。今度はスクロールできるはずです。
スクロールできた理由が大切です。SVの上下左右の位置とcontentsView
の上下左右の位置を一致させたためです。これによって,スクロールできる範囲は,左方向に関してはcontentsView
の左端がSVの左端に一致するまでとなりました。その他の位置も同様です。
第2章 コードでやってみる
SVの配置のみstoryboard上で行い,上記で行ったコンテンツビューの配置などはコードでやってみましょう。
###Outlet接続
SV以外のUIは全て削除し,SVをscrollViewという名前でOutlet接続させます。
###コンテンツビューの作製
コンテンツビューとその中身を作っていきましょう。以下がコード全体になります。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
configureSV()
}
func createLabel(contentsView: UIView) -> UILabel {
// labelを作る
let label = UILabel()
// labelの座標をcontentsViewの中心にする
let labelX = contentsView.center.x
let labelY = contentsView.center.y
label.frame = CGRect(x: labelX, y: labelY, width: 95, height: 50)
label.text = "Label"
return label
}
func createContentsView() -> UIView {
// contentsViewを作る
let contentsView = UIView()
contentsView.frame = CGRect(x: 0, y: 0, width: 800, height: 1200)
// contentsViewにlabelを配置させる
let label = createLabel(contentsView: contentsView)
contentsView.addSubview(label)
return contentsView
}
func configureSV() {
// scrollViewにcontentsViewを配置させる
let subView = createContentsView()
scrollView.addSubview(subView)
// scrollViewにcontentsViewのサイズを教える
scrollView.contentSize = subView.frame.size
}
}
それでは細かく見ていきましょう。
####func createLabel(contentsView: UIView) -> UILabel
ラベルを生成するメソッドです。
let label = UILabel()
// labelの座標をcontentsViewの中心にする
let labelX = contentsView.center.x
let labelY = contentsView.center.y
label.frame = CGRect(x: labelX, y: labelY, width: 95, height: 50)
label.text = "Label"
return label
引数であるcontentsView
の中心にlabel
が配置するように設定しています。return
でそのlabel
を返します。
####func createContentsView() -> UIView
コンテンツビューを生成するメソッドです。
let contentsView = UIView()
contentsView.frame = CGRect(x: 0, y: 0, width: 800, height: 1200)
// contentsViewにlabelを配置させる
let label = createLabel(contentsView: contentsView)
contentsView.addSubview(label)
return contentsView
####func configureSV()
SVの設定を行うメソッドです。
// scrollViewにcontentsViewを配置させる
let subView = createContentsView()
scrollView.addSubview(subView)
// scrollViewにcontentsViewのサイズを教える
scrollView.contentSize = subView.frame.size
スクロールさせるためにはSVにコンテンツビューの大きさを教える必要があります。SVのcontentSize
プロパティーにその大きさを設定することでSVにコンテンツビューの大きさを教えることができます。
これでビルドすると第1章と同様にスクロールさせることができると思います。ただ現状では,初期の「label」の位置が右下付近によっています。上下左右の中央にずらしたいですが,初期位置に関しては別の章で説明します。
第3章 横スクロールさせる
第1,2章だけではあまり面白みがありません。SVを使用する時は,横か縦方向にスクロールさせることが多いと思います。この章では横スクロールに焦点を当て,もうすこし実践的にしましょう。
###スクロールで色が変わる画面を作る
次のようにスクロールさせることでページごとに色が変わるのアプリケーションを作りましょう。
スクロールビューのみstoryboardを使用して,それ以外はコードで実装していきます。任意ですが,スクロールビューの制約はSafeAreaに対して行います。全体のコードです。
import UIKit
class ViewController: UIViewController {
let numberOfPages = 5
let colors: [UIColor] = [.yellow, .gray, .red, .blue, .brown]
@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
configureSV()
}
func createPages(page: Int) -> UIView {
let pageView = UIView()
let pageSize = scrollView.frame.size
let positionX = pageSize.width * CGFloat(page)
let position = CGPoint(x: positionX, y: 0)
pageView.frame = CGRect(origin: position, size: pageSize)
pageView.backgroundColor = colors[page]
return pageView
}
func createContentsView() -> UIView {
let contentsView = UIView()
let contentsWidth = scrollView.frame.width * CGFloat(numberOfPages)
let contentsHeight = scrollView.frame.height
contentsView.frame = CGRect(x: 0, y: 0, width: contentsWidth, height: contentsHeight)
for i in 0 ..< numberOfPages {
let pageView = createPages(page: i)
contentsView.addSubview(pageView)
}
return contentsView
}
func configureSV() {
let contentsView = createContentsView()
scrollView.addSubview(contentsView)
scrollView.contentSize = contentsView.frame.size
}
}
細かく見ていきましょう。
####インスタンスプロパティー
numberOfPages
:ページ数
colors
:色の設定
####func createPages(page: Int) -> UIView
ページを生成するメソッドです。
let pageView = UIView()
let pageSize = scrollView.frame.size
let positionX = pageSize.width * CGFloat(page)
let position = CGPoint(x: positionX, y: 0)
pageView.frame = CGRect(origin: position, size: pageSize)
pageView.backgroundColor = colors[page]
return pageView
ページの幅はscrollView
と同じにしています。引数page
は現在のページの番号です。ページがスクロールした分だけページの位置がずれ,その値をpositionX
に格納します。pageの背景色はcolors
に格納されている色を順に取り出して
backgroundColor
で設定します。
####func configureSV()
前章と同じでSVの設定を行います。
さて,これでビルドすると以下のようにスクロールができると思います。
###スクロールビューの設定
ここではスクロールビューにどんな設定ができるかを見てみましょう。すべてBool
型で設定します。
インスタンスプロパティー名 |
true の時の内容 |
デフォルト値 |
---|---|---|
isScrollEnabled |
スクロール可能 | true |
isDirectionalLockEnabled |
最初にスクロールさせた方向(水平か垂直)のみスクロール可能 | false |
isPagingEnabled |
1ページずつスクロールする | false |
scrollsToTop |
ステータスバーをタップすると一番上までスクロールする | true |
bounces |
スクロールがコンテンツの一番端に到達すると跳ね返る(バウンドする) | true |
alwaysBounceVertical |
コンテンツがスクロールビューよりも小さい場合でも常に垂直方向のバウンドを許可する。ただしbounces=true であることも必要 |
false |
alwaysBounceHorizontal |
コンテンツがスクロールビューよりも小さい場合でも常に水平方向のバウンドを許可する。ただしbounces=true であることも必要 |
false |
例えば,ページ単位でスクロールするには以下のように設定します。
let scrollView = UIScrollView()
scrollView.isPagingEnabled = true
記事が長くなってきたのでここで一旦区切ります。第4章以降は別記事で説明します。お疲れ様でした。
続編
【徹底解説】UIScrollViewクラス その2(執筆中)
参考文献
詳細! Swift iPhoneアプリ開発入門ノート 著者:大重 美幸 出版社: ソーテック社
ご意見等あれば連絡ください。