はじめに
こんにちは、nukkyです。
スライドショーやウォークスルーなどで何かしらのページングビューを使用するかとは思いますが、お手軽に使えるUIScrollViewだとループができないので、今回は自作でループができるように作ってみました!
前提条件
Xcode 9.x
iOS 11 Simulator
Swift 4.0
ページングビューとは
スクロールと違い任意の位置で止まるようなビューではなく、1ページ単位で切り替わるビューのことです、
今回作成する画面の完成イメージはこのようになります。
実装
Storyboardの準備
まずはStoryboardにUIScrollViewを用意します。
そうしたら、UIScrollViewの「indicators」と「Scrolling」を画像のように設定してください。
今回はページングなのでindicatorの表示はなくしています、それと忘れずに「Paging Enabled」にはチェックを入れてください。
それではこのUIScrollViewをViewControllerにリレーションしてください。
1 | @IBOutlet weakvarscrollView:UIScrollView! |
コードの実装
まずは今回使用する変数を宣言しておきます。
1 2 3 4 5 6 7 8 9 10 | // ページビューのラベルのタグ staticletLABEL_TAG=100 // ページビューの背景色 private letcolorArray:[UIColor]=[.red,.green,.blue,.yellow,.purple] // 現在表示されているページ private varpage:Int=0 // ScrollViewをスクロールする前の位置 private varstartPoint:CGPoint! // 表示するページビューの配列 private varpageViewArray:[UIView]=[] |
viewDidLoadでscrollViewのdelegateを設定します。
1 2 3 4 | overridefuncviewDidLoad(){ super.viewDidLoad() scrollView.delegate=self } |
scrollViewに各ページのビューを生成します、オートレイアウトが適用されているviewDidAppear後が望ましいです、今回はviewDidAppear内で生成を行っています。
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 | overridefuncviewDidAppear(_animated:Bool){ super.viewDidAppear(animated) // scrollViewの表示サイズ letsize=CGSize(width:scrollView.frame.size.width,height:scrollView.frame.size.height) // 5ページ分のcontentSize letcontentRect=CGRect(x:0,y:0,width:size.width*CGFloat(5),height:size.height) letcontentView=UIView(frame:contentRect) foriin0..<5{ letpageView=UIView(frame:CGRect(x:size.width*CGFloat(i),y:0,width:size.width,height:size.height)) pageView.backgroundColor=colorArray[i] letlabel=UILabel() label.text="View_\(i)" label.backgroundColor=.white label.sizeToFit() label.center=pageView.center label.frame.origin.x=10 // あとで使いたいのでtagを設定 label.tag=ViewController.LABEL_TAG pageView.addSubview(label) contentView.addSubview(pageView) // あとで再描画をできるように保持 pageViewArray.append(pageView) } // scrollViewに5ページ分のViewとサイズを設定する scrollView.addSubview(contentView) scrollView.contentSize=contentView.frame.size // 5つの真ん中のViewを初期位置に変更 scrollView.contentOffset=CGPoint(x:((size.width*2)),y:0) startPoint=scrollView.contentOffset; // 最初に表示するページ page=0 // 各ページの再描画 setPageView() } // 各ページの再描画 funcsetPageView(){ foriin0..<pageViewArray.count{ // 5つあるビューの真ん中が現在選択されているページになるようにする letindex=getPageIndex(page:page+(i-2)) pageViewArray[i].backgroundColor=colorArray[index] // tagからラベルを取得しtextを再設定 letlabel:UILabel=pageViewArray[i].viewWithTag(ViewController.LABEL_TAG)as!UILabel label.text="View_\(index)" label.sizeToFit() } } // ページがpageViewArray.count以上や0以下になった時に適切な値を返す funcgetPageIndex(page:Int)->Int{ varindex=page ifindex<0{ index=(pageViewArray.count+page) }elseifindex>=pageViewArray.count{ index=page-pageViewArray.count } returnindex } |
ループの肝となるUIScrollViewDelegateを追加します。
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 | extensionViewController: UIScrollViewDelegate{ funcscrollViewWillBeginDragging(_scrollView:UIScrollView){ // 左右のスワイプを判断するのでスクロール開始時に設定 self.startPoint=scrollView.contentOffset; } funcscrollViewDidEndDecelerating(_scrollView:UIScrollView){ ifstartPoint.x>scrollView.contentOffset.x{//左スワイプ pageChange(num:-1) }elseifstartPoint.x<scrollView.contentOffset.x{//右スワイプ pageChange(num:1) } // scrollViewのスクロール位置を真ん中のビューに戻す letpoint=CGPoint(x:((scrollView.frame.size.width*2)),y:0) scrollView.setContentOffset(point,animated:false) // pageが切り替わったのでビューを再描画 setPageView() } // ページがループできるように適切な値をセットする private funcpageChange(num:Int){ ifpage+num<0{ page=pageViewArray.count-1 }elseifpage+num>=pageViewArray.count{ page=0 }else{ page=page+num } } } |
仕組み
駆け足でコードを貼ってしまいましたが、実際どのようにしてループさせているかというと以下のような流れです。
- まず5つ分のページのビューを用意します。
- このビューをUIScrollViewにaddSubViewします。
- 真ん中のビューが表示されるように位置を調整します。
- 真ん中のビューが初期のページになるように「1」のビューを更新します。
- UIScrollViewDelegateでスクロール終了を取得します。
- スクロール終了したら真ん中のビューが表示されるように位置を戻します。
- 「1」で用意したビューを更新して現在のページが真ん中に表示されるようにします。
「1」で用意した時のページの並びが[0,1,2,3,4]とした時に「4」のタイミングで0ページ目を初期位置にしたい場合ページの並びは[3,4,0,1,2]になります。
上記の状態で左スワイプをおこない「5」のタイミングで1ページ目が表示された場合、「7」のタイミングでページの並びを[4,0,1,2,3]に変更しビューの更新を行い、常に真ん中のビューに現在のページをセットすることで、ページングしているように見せつつループして表示することができます。
さいごに
UIScrollViewでのページングのループ処理どうでしょうか、今回は5つでサンプルを書きましたがViewの数は5つのままでページの要素を増やしていけば、メモリはView5つ分のままでまだまだページを増やすことも可能です!結構便利にできているのではないかと思うので同じようなものが欲しい方の力になれれば嬉しいです!
RE:ENGINESブログ「iOS記事」まとめページはこちらから