LoginSignup
17
12

More than 5 years have passed since last update.

UIPageViewControllerでページ移動の際にオリジナルで作ったタブをスムーズに移動する

Last updated at Posted at 2018-01-29

タイトルが???になってしまいました( ・ὢ・ )
PageViewControllerで移動した際に上部に作成したタブを少しずつPage移動と比例させて動かしたいを今回のテーマとして作成しました。

これまでに参考にさせていただいたもの書いておきます。
iPhoneアプリでUIを作るためのTipsとContainerView・UIPageViewControllerを使ったサンプル紹介

【Swift 3】UIPageViewControllerとUINavigationControllerを使ってスワイプで画面切り替えをしよう

使うと手放せなくなるSwift Extension集 (Swift3版)

参考にしたかもしれないっと思ったものはまた都度あげて行きます:hatched_chick:

で今回作成したものです。
ソースなどみたい場合は以下のgithubからよろしくお願いします。むしろ見てもらう程で書いてます。

https://github.com/sachiko-kame/UITabSample

タブUIsampleNew.gif

で、私はこれを作成する前に困っていたこと

  • アニメーションでのタブ移動だとカクカクなるし時には左、右に余白ができる
  • 少しずつページ移動した際に上のタブも少しずつ動かしたい

で、なんでこの記事を書いたか

  • 似たものはあったのですが、上がCollectionViewでってのがなかなか見つからなかった。あとライブラリだったりした
  • この実装を説明するためには簡単にこれだけになるべく焦点を当てたものを作成したかった。
  • 作ったらqiitaに絶対書きたくなる。そしてqiitaに書くって尊敬する先輩に約束したのです(◍•ᴗ•◍)

では早速書きます!よろしくお願いします:hatching_chick:

まず、要点などをいう前に先に主たるファイルのソースを見てください!

ViewController.swift
import UIKit

class ViewController: UIPageViewController,UIPageViewControllerDataSource,UIPageViewControllerDelegate,UICollectionViewDelegateFlowLayout{

    let pagelist = ["PAGE0", "PAGE1", "PAGE2", "PAGE3", "PAGE4", "PAGE5", "PAGE6", "PAGE7", "PAGE8", "PAGE9"]
    var pageControllergrop = [UIViewController]()

    var collectionView:UICollectionView!
    let labeheight:CGFloat = 60
    var page:Int = 0


    init(){
        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.makeViewcontoller()
        self.setViewControllers([pageControllergrop.first!], direction: .forward, animated: false, completion: nil)


        // collectionViewレイアウト作成
        CollectionViewLayoutSet()

        // collectionViewその他設定
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.showsVerticalScrollIndicator = false
        collectionView.delaysContentTouches = false

        //デリゲートの設定(PageViewControllerとUICollectionView)
        dataSource = self
        delegate = self
        collectionView.dataSource = self
        collectionView.delegate = self

        view.addSubview(collectionView)

        self.view.subviews
            .filter{ $0.isKind(of: UIScrollView.self) }
            .forEach{($0 as! UIScrollView).delegate = self }

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

    func CollectionViewLayoutSet(){
        let flowLayout = UICollectionViewFlowLayout()
        flowLayout.minimumInteritemSpacing = 0.0
        flowLayout.minimumLineSpacing = 0.0
        flowLayout.scrollDirection = .horizontal
        flowLayout.itemSize = CGSize(width:viewframewidth / 3 ,  height:CGFloat(labeheight))
        let rec = CGRect(x: 0.0, y:statusBarHeight , width:viewframewidth , height: labeheight)
        collectionView = UICollectionView(frame: rec, collectionViewLayout: flowLayout)
    }

    func makeViewcontoller(){
        for i in 0...(pagelist.count - 1){
            let viewController:SampleViewController = SampleViewController()
            viewController.Set(Text:pagelist[i])
            self.pageControllergrop.append(viewController)
        }
    }
}

extension ViewController{
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        let index:Int = pageControllergrop.index(of: viewController)!
        page = index

        view.viewWithTag(index + 1)?.backgroundColor = UIColor.gray
        //1ページ何もしない
        switch index {
        case 0:
            return nil
        default:
            //2だったら1に、 3だったら2に
            return pageControllergrop[index-1]
        }

    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        let index:Int = pageControllergrop.index(of: viewController)!
        page = index

        view.viewWithTag(index + 1)?.backgroundColor = UIColor.gray
        switch index {
        //最終ページ何もしない
        case pageControllergrop.count-1:
            return nil
        default:
            //最終ページでない場合進める
            return pageControllergrop[index+1]
        }

    }
}


extension ViewController:UICollectionViewDataSource, UICollectionViewDelegate{
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return pagelist.count
    }


    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        collectionView.register(cellType: SampleCollectionViewCell.self)
        let cell:SampleCollectionViewCell = collectionView.dequeueReusableCell(with: SampleCollectionViewCell.self, for: indexPath)
        cell.Set(Text:pagelist[indexPath.row])
        return cell
    }

    // Cell が選択された場合
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        //選択された所に遷移
        self.setViewControllers([pageControllergrop[indexPath.row]], direction: .forward, animated: false, completion: nil)
    }

}

extension ViewController{

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if(scrollView.className ==  "UICollectionView"){
            return
        }
        let LeftRightJug = viewframewidth - scrollView.contentOffset.x
        if(LeftRightJug == 0){
            return
        }
        let Move = scrollView.contentOffset.x / 3
        let first:Int = LeftRightJug > 0 ? 1 : 0
        let End:Int = LeftRightJug > 0 ? (pagelist.count - 1) : (pagelist.count - 2)
        if(first < page && page < End){
            let pageWidth = CGFloat(page - 2) * viewframewidth //タブ真ん中に
            let TabPageWidth = pageWidth / 3

            collectionView.contentOffset = CGPoint(x:Move + TabPageWidth, y:0)
        }
    }
}



このほかに作成したものはgithubで確認していただけると嬉しいです。このほかで作成したファイルの種類のみ書きます。
・CollectionViewで使うためのUICollectionViewExtensionファイル
・CollectionViewの名前設定の時に使うためのクラスの名前取得NSObjectExtensionファイル
・UICollectionViewCellファイル
・ページビューコントローラーで使うビューコントローラーのファイル

で、メインのファイルで何を行っているかを書きます。

  • UIPageViewControllerを継承させてクラス自体PageViewControllerにしている。
  • CollectionViewの作成を行っている。
  • CollectionViewとUIPageViewControllerとUIPageViewControllerのSubViewにあたるScrollViewにdelegateをセットしている
  • ページ移動ができるようにPageViewControllerのdelegateに記述
  • CollectionViewのdelegateにはCollectionViewCell作成とタッチ(タッチされたところのView表示が行われるようになってる)
  • ページ移動(少しずつ)の際にスクロール量をscrollViewDidScrollで取得してCollectionViewのcontentOffsetの位置の調整を行っています 今回の肝になる部分です!

実装の際の注意点

  • CollectionViewのcontentOffsetですがcontentOffset.xとできればやりたいのですが、なぜかうまく行かないとどこかに書いてあったためcontentOffset.xでなくcontentOffsetの設定を行っています。ちなみにcontentOffset.yは0で設定してあります。
if(scrollView.className ==  "UICollectionView"){
            return
        }
  • 上記のところで?と思ったかたもいると思いますが、このデリゲートメソッドではCollectionViewのスクロール検知とPageViewControllerのSubViewのScrollの検知が入っています。もし両方に同じ処理を行ってしまったらPageViewContorollerのScrollView動かして、CollectionView動かしてと適応がうまく行かなくなることもありますし、そもそもCollectionViewのスクロールに今回の処理を入れたくないためreturnで返しています。

最後に

シンプルでありますが、以上で説明を終了させていただきます:hatched_chick:
見ていただきありがとうございました!:hatched_chick:シャキッ!

17
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
12