やりたい事
UIPageViewController
の子クラス PageViewController
を作成し、extension
の中で右にスワイプした時と左にスワイプさせたときで次のページもしくは前のページを表示させるようにしたいです。ページは要素数3つだけの配列にし、ループさせることでページがたくさんあるように見せようとしています。
困っていること
毎回綺麗にスワイプをすればほぼ思い通りに動くのですが、ページをめくりかけて「やっぱや〜めた」をすると、次にスワイプした時に2ページ分進んでしまいます。
理由が全く分からないわけではないのですが、「めくりかけてやっぱやめた」に対して page だけでなく index も変わらないようにするにはどうしたらいいのかが分からなくて困っています。回避する方法がありましたらご教授願います。
後、「ほぼ」と言いましたが、先へスワイプする時に一旦戻って進む事がある、もしくはその逆があります(print
文で確認)。
swift
1// 2// PageViewController.swift 3// ColorSample 4// 5 6import UIKit 7 8let count: Int = 1 << (6 * 3) 9 10class PageViewController: UIPageViewController { 11 12 var eachViewControllers: [EachViewController] = [] 13 var red: [Int] = [] 14 var green: [Int] = [] 15 var blue: [Int] = [] 16 var rgba: [UIColor] = [] 17 var index: Int = 1 18 var lastPage: Int = 1 19 20 override func viewDidLoad() { 21 super.viewDidLoad() 22 23 self.dataSource = self 24 25 // 1677万色の色の配列(要素数:count個)を作る 26 for i in 0..<count { 27 red.append(Int(arc4random_uniform(256))) 28 green.append(Int(arc4random_uniform(256))) 29 blue.append(Int(arc4random_uniform(256))) 30 rgba.append(UIColor(red: CGFloat(red[i]) / 255.0, green: CGFloat(green[i]) / 255.0, blue: CGFloat(blue[i]) / 255.0, alpha: CGFloat(1.0))) 31 } 32 33 // EachViewController を3つだけ作る 34 for i in 0..<3 { 35 let eachViewController = EachViewController() 36 eachViewController.setIndexTo(i) 37 eachViewController.setBackgroundRgba(rgba[i]) 38 eachViewControllers.append(eachViewController) 39 } 40 41 // 1番目の EachViewController をセットする 42 setViewControllers([eachViewControllers[1]], direction: .reverse, animated: false, completion: nil) 43 } 44 45 override func didReceiveMemoryWarning() { 46 super.didReceiveMemoryWarning() 47 // Dispose of any resources that can be recreated. 48 } 49 50} 51 52extension PageViewController : UIPageViewControllerDataSource { 53 54 // 次のページを表示する時に呼ばれる 55 func pageViewController(_ pageViewController: 56 UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { 57 58 // ページを取得する 59 let page = eachViewControllers.index(of: viewController as! EachViewController)! 60 61 // インデックスをセットする 62 index = (index + 1) % count 63 64 // 前後ののページの値をセットする 65 let nextPage = (page + 1) % 3 66 let prevPage = (page + 2) % 3 67 68 // デバッグ 69 print("index: \(index), lastPage: \(lastPage) , page: >> [\(prevPage) -> \(page) -> \(nextPage)]") 70 71 lastPage = nextPage 72 73 // 新しく表示するページに変数をセットする 74 eachViewControllers[lastPage].setBackgroundRgba(rgba[index]) 75 eachViewControllers[lastPage].setIndexTo(index) 76 77 // 要らなくなったページをリリースする処理をここに入れる 78 79 80 // 新しいページを返す 81 return eachViewControllers[lastPage] 82 } 83 84 // 前のページを表示する時に呼ばれる 85 func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController:UIViewController) -> UIViewController? { 86 87 // ページを取得する 88 let page = eachViewControllers.index(of: viewController as! EachViewController)! 89 90 // 前後ののページの値をセットする 91 let nextPage = (page + 1) % 3 92 let prevPage = (page + 2) % 3 93 94 // インデックスをセットする 95 index = (index - 1 + count) % count 96 97 // デバッグ 98 print("index: \(index), lastPage: \(lastPage) , page: << [\(prevPage) -> \(page) -> \(nextPage)]") 99 100 lastPage = prevPage 101 102 // 新しく表示するページに変数をセットする 103 eachViewControllers[lastPage].setBackgroundRgba(rgba[index]) 104 eachViewControllers[lastPage].setIndexTo(index) 105 106 // 要らなくなったページをリリースする処理をここに入れる 107 108 109 // 新しいページを返す 110 return eachViewControllers[lastPage] 111 } 112}
補足
言葉が足りませんでした。
swift
1 eachViewControllers[lastPage].setBackgroundRgba(rgba[lastPage]) 2 eachViewControllers[lastPage].setIndexTo(lastPage)
だと3ページ分しか表示できません。
やりたいのは
swift
1let count: Int = 1 << (6 * 3)
と定義したとても大きい数(count
)だけのページを表示させたいのです。
(その、何番目なのかを index
で持たせようとしています)
でも、
EachViewController
クラスのインスタンスを count
個作るとメモリを喰って大変ですよね。
なので、添字が 0, 1, 2 の3つのインスタンスを
swift
1 for i in 0..<3 { 2 let eachViewController = EachViewController() 3 eachViewController.setIndexTo(i) 4 eachViewController.setBackgroundRgba(rgba[i]) 5 eachViewControllers.append(eachViewController) 6 }
の様に作り、
その背景色(rgba
)及びページ番号(index
)だけを書き換えて使いまわすことで大きい数のページがあるかのように見せたいという事です。
最初に eachViewControllers[0]
, eachViewControllers[1]
, eachViewControllers[2]
を作って真ん中の eachViewControllers[1]
を表示させておき、
1ページ進んだら[0]
, [1]
, [2]
、から [1]
, [2]
, [0]
へ(添字だけで書いてます)、さらに進んだら[2]
, [0]
, [1]
と進めていくことで使いまわそうという考えです(戻る時も同様)。
どうしても言葉でうまく説明できないのがもどかしいのですが、少しでも伝わるでしょうか?
8/27 (14:03) 追記
コメントにも書きましたが、
pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
は使わずに、意図している動きが出来ているように見えています。
swift
1// PageViewController.swift 2extension PageViewController : UIPageViewControllerDataSource { 3 4 // 次のページを表示する時に呼ばれる 5 func pageViewController(_ pageViewController: 6 UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { 7 8 // ここにスワイプする前のページが入ってくるみたい(前回、スワイプ完了でも途中でやめても) 9 let eachViewController = pageViewController.viewControllers?.first as! EachViewController 10 11 // インデックスをインクリメントする 12 index = (eachViewController.index + 1) % count 13 14 // ページを取得する 15 let page = eachViewControllers.index(of: viewController as! EachViewController)! 16 17 // 次のページの値をセットする 18 let nextPage = (page + 1) % 3 19 20 // 新しく表示するページに変数をセットする 21 eachViewControllers[nextPage].setBackgroundRgba(rgba[index]) 22 eachViewControllers[nextPage].setRgb(red: red[index], green: green[index], blue: blue[index]) 23 eachViewControllers[nextPage].setIndexTo(index) 24 25 26 // 新しいページを返す 27 return eachViewControllers[nextPage] 28 } 29}
で上手く行ってそうです。
swift
1let eachViewController = pageViewController.viewControllers?.first as! EachViewController 2index = (eachViewController.index + 1) % count
がスワイプを途中でやめたときにインクリメントされない(経験則ですが)ようなので、
これを使ったのが良かったのかなと思っています。
勘違い等あるかも知れないので、閉めるのはまだにしておこうと思います。
気付いていない点、勘違いしてる点、
そもそもコードの書き方が汚い等ありましたら教えて下さい。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/08/27 07:16