【Swift4】UIScrollViewで電子書籍風に。

UIScrollViewを使って電子書籍風?な感じで見れるものを作ってみました。

参考サイト
[iPhone] UIScrollView ページ スクロール
【Swift】UIScrollViewの使い方。大きい部品をスクロールして見る。 | はじはじアプリ体験記
【Swift】UIScrollViewとUIPageControlを使ってページを移動する方法 | はじはじアプリ体験記
UIScrollView、UIKit座標計算系に関しての復習 – これが最後じゃないからね

基本条件
・表示させる画像ファイルを用意する。
・画像のサイズは多少、大小してもscrollViewの幅にリサイズ、画面中央に配置。
・漫画のように右から左へ見ていく。
・1画面1ページ。

UIScrollViewについて。
UIScrollViewはいろいろとサイズのプロパティがあってややこしい。

とりあえず参考サイトから真似てプロパティを説明する画像を作ってみた。
UIScrollのプロパティ

UIScrollViewに使われるサイズは大きく分けて2つ。
frameとcontentSizeだ。
frameのサイズは画面に表示される「枠」のサイズ。
contentSizeが枠のなかに表示される「移動可能な領域」のサイズ。
イメージとしてはframeの上にcontentSizeが乗ってる感じだけど、
実際にはcontentSizeのうえにframeがあってそこから覗き込んでる感じなのでややこしく感じる。

frameには
frameの位置座標をあらわす(frame.origin.x , frame.origin.y)というプロパティと
frame.size.widthという幅と、
frame.size.heightという高さのプロパティを持っている。
frame.originはiPhoneの画面の起点からの距離というところに注意。

contentSizeは
contentOffset.x , contentOffset.yというscrollViewに対する位置情報と
contentSize.widthという幅と、
contentSize.heightという高さのプロパティを持っている。

contentInsetは今回使わないので割愛。

今回は電子書籍風ということでscrollViewのframeとcontentSizeの高さを揃えて、contentOffset.xの値が変動することによって画面が横スクロールするイメージです。
moveScroll

ではまず、StoryboardでViewControllerを開き、ScrollViewを配置します。
スクリーンショット 2018-07-13 15.49.29のコピー

AutoLayoutで位置を決めて、Paging Enabledにチェックを入れます。これでscrollViewがページ単位で動くようになります。

次いで、Assetsに画像を放り込みます。
スクリーンショット 2018-07-13 21.43.09

コードの記述

・AutoLayoutの処理を待ってviwDidApearから処理を始めます。
・scrollViewのサイズが決まったら高さと幅を取得。
・scrollView幅に合わせて画像のサイズを変更してsubviewに貼っていく。
・subviewを配列に取り込んで順番を逆転。
・順にscrollViewの幅ずつずらしていく。
・scrollViewの幅×画像の数をcontentSizeの幅にする。
・contentSizeの高さはscrollViewの高さと同じ。
・scrollViewの初期位置を一番右の画像に持ってくる。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!
    
    // contentSize(領域)のなかの各ページ《画像)の高さを入れるインスタンス
    var scrollPageHeight:CGFloat!
    // contentSize(領域)のなかの各ページ《画像)の幅を入れるインスタンス
    var scrollPageWidth:CGFloat!
    
    //表示する画像の名前を配列に入れる
    let img:[String] = ["image-1","image-2","image-3","image-4","image-5"]
    // ページ数を入れるインスタンス
    var pageNum:Int!
    //取り込む元の画像のサイズを保持しておくインスタンス
    var imageWidth:CGFloat!
    var imageHeight:CGFloat!

    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //AutoLayoutでscrollViewのサイズが決定してから計算しないとおかしくなるのでここで処理。
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // ページでスクロールするためにscrollViewのサイズを取得
        scrollPageWidth = scrollView.frame.width
        scrollPageHeight = scrollView.frame.height
        
        //画像の枚数を取得
        pageNum = img.count
        
        //配列のイメージを連続で取り込む
        for i in 0 ..< pageNum {
            // 配列から画像を取り込む
            let image:UIImage = UIImage(named:img[i])!
            let imageView = UIImageView(image:image)
            
            //元画像の幅と高さを取得
            imageWidth = image.size.width
            imageHeight = image.size.height
            
            //元画像からframe情報を取得
            var rect:CGRect = imageView.frame
            //scrollViewの幅に合わせて高さを計算し幅と高さを入力。
            rect.size.width = scrollPageWidth
            rect.size.height =  scrollPageWidth * imageHeight/imageWidth
            
            //scrollViewの幅に合わせたframeサイズを画像に適用
            imageView.frame = rect
            //タグを付ける
            imageView.tag = i + 1
            
            // UIScrollViewのインスタンスに画像を貼付ける
            self.scrollView.addSubview(imageView)
            
        }
        //①
        setupScrollImages()
    }
    
    
    
    func setupScrollImages(){
        
        //配列を作って、scrollViewに貼り付けられたsubviewの画像を取り込む。
        var subviews:Array = scrollView.subviews
        //配列の並び順を逆転させる。
        subviews = subviews.reversed()
        
        // 描画開始の x の位置
        var px:CGFloat = 0.0
        
        //配置された画像を一枚ずつscrollViweの幅でずらしていく
        for i in 0 ..< subviews.count {
            //配列からi番目の画像を取り出す
            let imgView = subviews[i] as! UIImageView
            
            if (imgView.isKind(of: UIImageView.self) && imgView.tag > 0){
                
                //画面の真ん中の高さに写真が来るように計算。
                let py:CGFloat = (scrollPageHeight - imgView.frame.height)/2
                
                //CGRectインスタンスを作ってiamgeViewの座標とサイズを保持。
                var viewFrame:CGRect = imgView.frame
                //原点座標を指定し直す。pxは毎回幅分増えていく。
                viewFrame.origin = CGPoint(x: px, y: py)
                imgView.frame = viewFrame
                
                //次の画像のX軸を画面の幅だけずらす。
                px += (scrollPageWidth)
                
                
            }
        }
        
        // UIScrollViewのcontentSizeを画像の合計サイズに合わせる
        //contentSizeの幅は、scrollViewの幅 × 画像の枚数
        let nWidth:CGFloat = scrollPageWidth * CGFloat(pageNum)
        scrollView.contentSize = CGSize(width: nWidth, height: scrollPageHeight)
        
        //scrollViewの初期位置を右端の画像に合わせる。
        scrollView.contentOffset.x = scrollPageWidth * CGFloat(pageNum - 1)
        
        //②
    }
    
}

①の時点でのイメージはこんな感じ。
scrollViewレイヤーイメージ-01

contentSizeはまだ指定していないので存在しないか(0,0)なので画面は動きません。

画像の順番を並べ替えて右へずらしてframeを初期位置へ移動させて、
最終的に起動した時のイメージは②でこんな感じ。

scrollViewレイヤーイメージ-02

contentSizeの範囲をflameの幅で左右にページ移動します。
一応こんな感じでscrollViewが使えました。

うじゃうじゃ。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です