【Swift】Scroll Viewの設定項目。画像のズームやスクロール時の挙動を細かく設定する。(Swift 2.1、XCode 7.2)
UIScrollViewの設定
本記事ではUIScrollView(以下、スクロールビュー)の設定について説明する。
デバイス画面にスクロールビューを配置し(下図赤枠)、黄緑枠のアトリビュートインスペクタボタンを押すと設定項目の一覧が表示される。
Style
スクロールしたときにスクロールビューの下端と右端に表示されるスクロールバーの色を「Default」、「Black」、「White」の中から選択する。
Shows Horizontal Indicator
チェックを外した場合、下端のスクロールバーが表示されなくなる。ただし、バーが表示されないだけでスクロールはできる。
Shows Vertical Indicator
チェックを外した場合、右端のスクロールバーが表示されなくなる。ただし、バーが表示されないだけでスクロールはできる。
Scrolling Enabled
チェックが入っていると、スワイプで画面をスクロールできる。まあ、いつも通りということだ。
Paging Enabled
チェックを入れると、スクロールビューの幅または高さぶん移動するとスクロールがピタッと止まるようになる。電子書籍のページをめくるような感覚。
Direction Lock Enabled
チェックを入れると、1回のドラッグ&ドロックは水平方向または垂直方向のどちらか一方向しか移動できなくなる。
Bounces
チェックが入っていると、端にゴムがついついているかのようにスクロールビューが弾む。
以下はチェックを入れた場合のプレイ動画
以下はチェックを入れない場合のプレイ動画
Bounces Horizontally
部品の幅がスクロールビューより小さいと、水平方向にドラッグしてもスクロールやゴムのような弾みは通常おきないが、これにチェックを入れると水平方向の弾みが発生する。
Bounces Vertically
部品の高さがスクロールビューより小さいと、垂直方向にドラッグしてもスクロールやゴムのような弾みは通常おきないが、これにチェックを入れると垂直方向の弾みが発生する。
Zoom
スクロールビューをズームイン、ズームアウトする倍率の最小倍率(Min)と最大倍率(Max)を指定する。
スクロールビューにズームの機能を持たせるには以下のコードのように、スクロールビューのデリゲートメソッドである「ズームする部品を返すメソッド」を実装する。
検証では最小倍率を0.5、最大倍率を2.0に設定した。要するに、縮小は縦横2分の1まで、拡大は縦横2倍まで可能ということだ。
実装を試してみる人はこのサンプル画像をご利用されたし。⇒「サンプル画像」
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// // ViewController.swift // import UIKit class ViewController: UIViewController, UIScrollViewDelegate { var testImageView1:UIImageView! override func viewDidLoad() { super.viewDidLoad() //スクロールビューを作成する。 let testScrollView = SubUIScrollView() testScrollView.frame = CGRectMake(0, 0, 320, 568) testScrollView.contentSize = CGSizeMake(960, 1000) //イメージビューを作成する。 testImageView1 = UIImageView(image: UIImage(named:"sample_item.png")) testImageView1.frame = CGRectMake(0, 0, 960, 1000) //部品を登録する。 testScrollView.addSubview(testImageView1) self.view.addSubview(testScrollView) //ズームの最大最小倍率を設定する。 testScrollView.minimumZoomScale = 0.5 testScrollView.maximumZoomScale = 2.0 //デリゲート先に自分を設定する。 testScrollView.delegate = self } //ズームする部品を返すメソッド func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? { return self.testImageView1 } } |
以下は実際のプレイ動画
Bounces Zoom
チェッックが入っていると、ズームしたときにゴムがついたように弾む。
Delays Content Touches
チェックが入っていると、スクロールビュー内の部品のタッチ判定を遅らせることができる。
例えば、以下の動画のようにスクロールビューの中にボタンがあるとする。このボタンの上でドラッグを開始すると、ボタンのタッチ判定が若干遅れてスクロール判定が先に行われる。その結果、ボタンを押したことにはならずに画面がスクロールする。
ただし、ドラッグを開始からスワイプせずにもたもたしているとボタンのタッチ判定が行われる。
一方、チェックを入れなかった場合は、部品のタッチ判定が即座に行われる。そのためボタン押下が優先されてスクロールは発生しない。ただし、別の場所でドラッグすればいつもどおりスクロールできる。
Cancellable Content Touches
チェックが入っていると、タッチ判定をキャンセルできるようになる。といっても、そのままでは「キャンセルしない」が常に返ってくるのでチェックを入れても入れなくても同じ結果になる気がする。
「キャンセル(しない)をできる。」。。名前と意味で混乱しそうだ。
わかりづらいので使用例を挙げておこう。
例えば、下図のようにスクロールビューの上に2つのボタンがあったとする。ボタン1の上でドラッグ&ドロップした場合は必ずスクロールしたいが、ボタン2の上でドラッグ&ドロップした場合はスクロールしたくない。そんなときにこの機能を使う。
上記の機能を実装してみよう。
ViewController.swiftを以下のように変更する。なお、検証時間を短縮するために、部品の追加、設定の変更はソースコードで行っている。試してみる人は次のサンプル画像をご利用されたし。⇒「サンプル画像」
タッチ判定の有無はソースコードで制御するので、タッチ判定を遅延させる必要は無い。なので、delayContentTouchesプロパティはfalseに設定している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
// // ViewController.swift // import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //スクロールビューを作成する。 let testScrollView = SubUIScrollView() testScrollView.frame = CGRectMake(0, 0, 320, 320) testScrollView.contentSize = CGSizeMake(320*2, 568) //イメージビューを作成する。 let testImageView1 = UIImageView(image: UIImage(named:"sample_img1.png")) let testImageView2 = UIImageView(image: UIImage(named:"sample_img2.png")) testImageView1.frame = CGRectMake(0, 0, 320, 568) testImageView2.frame = CGRectMake(320, 0, 320, 568) //ボタンを作成する。 let button = UIButton() button.tag = 1 button.setTitle("ボタン1", forState: .Normal) button.backgroundColor = UIColor(red:0.4, green:0.3, blue:0.2, alpha: 0.5) button.frame = CGRectMake(100,100,200,50) button.layer.position = CGPoint(x:self.view.frame.width/2, y:100) button.addTarget(self, action:"tapButton:", forControlEvents:.TouchUpInside) //ボタンを作成する。 let button2 = UIButton() button2.tag = 2 button2.setTitle("ボタン2", forState: .Normal) button2.backgroundColor = UIColor(red:0.4, green:0.3, blue:0.2, alpha: 0.5) button2.frame = CGRectMake(100,100,200,50) button2.layer.position = CGPoint(x:self.view.frame.width/2, y:200) button2.addTarget(self, action:"tapButton:", forControlEvents:.TouchUpInside) //部品を登録する。 testScrollView.addSubview(testImageView1) testScrollView.addSubview(testImageView2) testScrollView.addSubview(button) testScrollView.addSubview(button2) self.view.addSubview(testScrollView) //スクロールビューの設定を変更する。 testScrollView.delaysContentTouches = false testScrollView.canCancelContentTouches = true } //ボタン押下時の呼び出しメソッド func tapButton(sender:UIButton){ sender.setTitle("ボタンが押されました", forState: .Normal) } } |
次に、UIScrollViewを継承した自作クラスを作り、「タッチ判定のキャンセル有無を返すメソッド」を追加する。
ボタンの上でドラッグが開始されるたびにこのメソッドが呼び出されるので、引数で渡ってきた部品のタグ番号がボタン1と同じ場合はタッチ判定をキャンセルするためにtrueを返す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// // SubUIScrollView.swift // import UIKit class SubUIScrollView: UIScrollView { //タッチ判定のキャンセル有無を返すメソッド override func touchesShouldCancelInContentView(view: UIView) -> Bool { //タグ番号がボタン1のならタッチをキャンセルする。 if (view.tag == 1) { return true } return super.touchesShouldCancelInContentView(view) } } |
以下が実際のプレイ動画。ボタン2の上ではどうやってもスクロールできなくなり、ボタン1の上ではゆっくりドラッグしてもスクロールできるようになった。
Keyboard
スクロールを始めたときにキーボードが表示されていた場合にキーボードをどうするかを「Do not dismiss」、「Dismiss on drag」、「Dismiss interactively」の3つから選択する。
「Do not dissmiss」は、キーボードはそのまま表示され続ける。
「Dismiss on drag」は、スクロールするとすぐににキーボードが閉じられる。
「Dismiss interactively」は、指でキードードを外に押し出すことができる。