見出し画像

【徒然iOS】気ままにUIKit99〜Collection View Controller レイアウト変更をアニメーション〜

概要

このマガジンは四十を過ぎたおっさんが、

を参考にStoryboardでiOSアプリを完全に趣味で楽しんでいるだけな記事を気ままに上げてます。

今回

をハイ、レッツゴ🕺

前準備

念の為、

  1. バックアップ

をいつも通りやってから本題へ💃

こんな感じで〜〜〜

本題

とりあえず、サイト記事をザッと見ると、

カスタムクラスを書き換えていってるだけ感

なので、まずは、恒例の一覧表で整理する〜〜〜🕺

一覧表

こんな感じらしい💦

ひとつひとつ試してみよう🕺

⒈事前準備

でやったビューを新規で追加して、カスタムクラスを組み替えていく手順で、ひとつひとつ検証してみよう
(流石にビューを全て増やすのはちょっと効率が悪すぎるので💦)

てな感じで増やして〜〜〜
ハイ、準備完了
class MyCollectionAnimationViewController: UICollectionViewController {
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    //データの個数を返すメソッド
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 7
    }
    //データを返すメソッド
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        //セルを取得し、イメージビューに画像を設定して返す。
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionCell", for: indexPath as IndexPath)
        let imageView = cell.contentView.viewWithTag(1) as! UIImageView
        imageView.image = UIImage(named: "item" + String(indexPath.row) + ".png")
        return cell
    }
    //セル選択時の呼び出しメソッド
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        //セグエを実行する。
        performSegue(withIdentifier: "MySegue", sender: nil)
    }
    //画面遷移実行前の呼び出しメソッド
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        //選択中のセルの画像を取得する。
        let index = collectionView?.indexPathsForSelectedItems?.first
        let cell = collectionView?.cellForItem(at: index!)
        let imageView = cell!.viewWithTag(1) as! UIImageView
        //遷移先のビューコントローラーを取得し、インスタンス変数に画像とテキストを設定する。
        let controller: CollectionAnimationViewController = (segue.destination as? CollectionAnimationViewController)!
        controller.myTitle = String(index!.row + 1)
        controller.myImage = imageView.image
    }
}

今回はこのコードを色々、書き換えるみたいなので、
以降は、大項目ごとに説明してく〜〜〜

clearsSelectionOnViewWillAppearプロパティ

    //データを返すメソッド
    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        //セルを取得し、イメージビューに画像を設定して返す。
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TestCell", forIndexPath: indexPath)
        let imageView = cell.contentView.viewWithTag(1) as! UIImageView
        imageView.image = UIImage(named: "item" + String(indexPath.row) + ".png")
        //セル選択時の背景色を設定する。
        let selectedView = UIView()
        selectedView.backgroundColor = UIColor.redColor();
        cell.selectedBackgroundView = selectedView;
        return cell
    }

コードを見ると、
中身を書き換えればいいみたいなので〜〜〜

てな感じに書き換えて、
てな感じで背景が赤になるアニメーション
てな感じで追記して〜〜〜
試したけど、あっても無くても変わらなかった💦
仕様が当時とすでに変わってそう👀

installsStandardGestureForInteractiveMovementプロパティ

てな感じで追記して〜〜〜
移動できた〜〜〜

useLayoutToLayoutNavigationTransitionsプロパティ

なんかもうひとつクラスを増やさないといけないみたいだから、

//
//  TestCollectionViewController2.swift
//
import UIKit
class TestCollectionViewController2: UICollectionViewController {
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        //レイアウトの変更
        if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout{
            //画像サイズと画面サイズを同じにし、スペースを無くす。
            let width = floor(collectionView!.bounds.width)
            layout.itemSize = CGSizeMake(width, width)
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 0
            layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }
    }
}

を参考にコードを追加して、コイツ用のクラスを増やす

増やしたところ〜〜〜
//
//  TestCollectionViewController.swift
//
import UIKit
class TestCollectionViewController: UICollectionViewController {
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView?.backgroundColor = UIColor.whiteColor()
        //clearsSelectionOnViewWillAppear = false
    }
    //データの個数を返すメソッド
    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    //データを返すメソッド
    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        //セルを取得し、イメージビューに画像を設定して返す。
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TestCell", forIndexPath: indexPath)
        let imageView = cell.contentView.viewWithTag(1) as! UIImageView
        imageView.image = UIImage(named: "item" + String(indexPath.row) + ".png")
        //セル選択時の背景色を設定する。
        let selectedView = UIView()
        selectedView.backgroundColor = UIColor.redColor();
        cell.selectedBackgroundView = selectedView;
        return cell
    }
    //セル選択時の呼び出しメソッド
    override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        //レイアウト変更用のコレクションビューコントローラーのインスタンスをナビゲーションコントローラーにpushする。
        let controller = TestCollectionViewController2(collectionViewLayout:UICollectionViewFlowLayout())
        controller.useLayoutToLayoutNavigationTransitions = true;
        navigationController!.pushViewController(controller, animated: true)
    }  
}

を参考に増やした元クラスを書き換え〜〜〜

適用して〜〜〜
起動直後〜〜〜
大きくなりました👀

レイアウトを連続で変更する。

//
//  TestCollectionViewController.swift
//
import UIKit
//レイアウト変更残回数
var count:CGFloat = 7.0
class TestCollectionViewController: UICollectionViewController, UINavigationControllerDelegate {
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView?.backgroundColor = UIColor.whiteColor()
        clearsSelectionOnViewWillAppear = false
        //画面幅をレイアウト変更残回数で割った値を画像サイズにする。
        let width = floor(self.collectionView!.bounds.width / count--)
        //レイアウトの変更
        if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout{
            //スペースを無くす。
            layout.itemSize = CGSizeMake(width, width)
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 0
            layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }
    }
    //データの個数を返すメソッド
    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    //データを返すメソッド
    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        //セルを取得し、イメージビューに画像を設定して返す。
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TestCell", forIndexPath: indexPath)
        let imageView = cell.contentView.viewWithTag(1) as! UIImageView
        imageView.image = UIImage(named: "item" + String(indexPath.row) + ".png")
        //セル選択時の背景色を設定する。
        let selectedView = UIView()
        selectedView.backgroundColor = UIColor.redColor();
        cell.selectedBackgroundView = selectedView;
        return cell
    }
    //セル選択時の呼び出しメソッド
    override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        if(count > 0) {
            //自クラスのインスタンスを作り、ナビゲーションコントローラーにpushする。
            let controller = TestCollectionViewController(collectionViewLayout:UICollectionViewFlowLayout())
            controller.useLayoutToLayoutNavigationTransitions = true;
            navigationController!.pushViewController(controller, animated: true)
        }
    }
    //ビューコントローラー追加削除時の呼び出しメソッド
    override func didMoveToParentViewController(parent: UIViewController?) {
        if parent == nil {
            //削除(戻るボタンが押された)の場合はレイアウト変更残回数をインクリメントする。
            count++
        }
    }
}

を参考に書き換えて動かしてみたけど、

動かないね、、、

オペランド値でデクリメントとインクリメントをしているので、
Swift3以降では使えないから当たり前〜〜〜

コードまとめ

clearsSelectionOnViewWillAppearプロパティ、installsStandardGestureForInteractiveMovementプロパティ

class MyCollectionAnimationViewController: UICollectionViewController {
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        //clearsSelectionOnViewWillAppearプロパティ:clearsSelectionOnViewWillAppearプロパティをfalseに設定して選択を解除しない
        collectionView?.backgroundColor = UIColor.white
        //ビューが表示されるときに選択を解除しない設定にする。
        clearsSelectionOnViewWillAppear = false
    }
    
    //データの個数を返すメソッド
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 7
    }
    //データを返すメソッド
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        //clearsSelectionOnViewWillAppearプロパティ:ビューが表示されるときにテーブルの選択を解除する(true)、または、解除しない(false)を設定するプロパティ。
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionCell", for: indexPath)
        let imageView = cell.contentView.viewWithTag(1) as! UIImageView
        imageView.image = UIImage(named: "item" + String(indexPath.row) + ".png")
        //セル選択時の背景色を設定する。
        let selectedView = UIView()
        selectedView.backgroundColor = UIColor.red;
        cell.selectedBackgroundView = selectedView;
        return cell
    }
    //セル選択時の呼び出しメソッド
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        //セグエを実行する。
        performSegue(withIdentifier: "MySegue", sender: nil)
    }
    //画面遷移実行前の呼び出しメソッド
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        //選択中のセルの画像を取得する。
        let index = collectionView?.indexPathsForSelectedItems?.first
        let cell = collectionView?.cellForItem(at: index!)
        let imageView = cell!.viewWithTag(1) as! UIImageView
        //遷移先のビューコントローラーを取得し、インスタンス変数に画像とテキストを設定する。
        let controller: CollectionAnimationViewController = (segue.destination as? CollectionAnimationViewController)!
        controller.myTitle = String(index!.row + 1)
        controller.myImage = imageView.image
    }
    //installsStandardGestureForInteractiveMovementプロパティ:セルの並び替えを行うためのジェスチャーリコグナイザーをインストールする(true)、しない(false)を設定するプロパティ。
    override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        print("移動元インデックス番号 \(sourceIndexPath.row)")
        print("移動先インデックス番号 \(destinationIndexPath.row)")
    }
}

useLayoutToLayoutNavigationTransitionsプロパティ

//useLayoutToLayoutNavigationTransitionsプロパティ:このプロパティをtrueにするとコレクションビューのレイアウトをアニメーションさせながら変更できるようになる。
class MyAnimationCollectionViewController: UICollectionViewController {
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        //レイアウトの変更
        if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout{
            //画像サイズと画面サイズを同じにし、スペースを無くす。
            let width = floor(collectionView!.bounds.width)
            layout.itemSize = CGSizeMake(width, width)
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 0
            layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }
    }
}
//MyAnimationCollectionViewController用のクラス
class MyCollectionAnimation2ViewController: UICollectionViewController {
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        
        collectionView?.backgroundColor = UIColor.white
        //clearsSelectionOnViewWillAppear = false
    }
    //データの個数を返すメソッド
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    //データを返すメソッド
    override  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        //セルを取得し、イメージビューに画像を設定して返す。
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionCell", for: indexPath)
        let imageView = cell.contentView.viewWithTag(1) as! UIImageView
        imageView.image = UIImage(named: "item" + String(indexPath.row) + ".png")
        //セル選択時の背景色を設定する。
        let selectedView = UIView()
        selectedView.backgroundColor = UIColor.red;
        cell.selectedBackgroundView = selectedView;
        return cell
    }
    //セル選択時の呼び出しメソッド
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        //レイアウト変更用のコレクションビューコントローラーのインスタンスをナビゲーションコントローラーにpushする。
        let controller = MyAnimationCollectionViewController(collectionViewLayout:UICollectionViewFlowLayout())
        controller.useLayoutToLayoutNavigationTransitions = true;
        navigationController!.pushViewController(controller, animated: true)
    }
}

レイアウトを連続で変更する:使えないけど、これだとNGってサンプルも参考になるだろうから載せとく〜〜〜〜

//レイアウト変更残回数
var count:CGFloat = 7.0

//レイアウトを連続で変更する:使えない
class MyRepeatAnimationCollectionViewController: UICollectionViewController, UINavigationControllerDelegate {
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView?.backgroundColor = UIColor.white
        clearsSelectionOnViewWillAppear = false
        //画面幅をレイアウト変更残回数で割った値を画像サイズにする。
        let width = floor(self.collectionView!.bounds.width / count)
        //レイアウトの変更
        if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout{
            //スペースを無くす。
            layout.itemSize = CGSizeMake(width, width)
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 0
            layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }
    }
    //データの個数を返すメソッド
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    //データを返すメソッド
    override  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        //セルを取得し、イメージビューに画像を設定して返す。
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionCell", for: indexPath)
        let imageView = cell.contentView.viewWithTag(1) as! UIImageView
        imageView.image = UIImage(named: "item" + String(indexPath.row) + ".png")
        //セル選択時の背景色を設定する。
        let selectedView = UIView()
        selectedView.backgroundColor = UIColor.red;
        cell.selectedBackgroundView = selectedView;
        return cell
    }
    //セル選択時の呼び出しメソッド
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if(count > 0) {
            //自クラスのインスタンスを作り、ナビゲーションコントローラーにpushする。
            let controller = MyRepeatAnimationCollectionViewController(collectionViewLayout:UICollectionViewFlowLayout())
            controller.useLayoutToLayoutNavigationTransitions = true;
            navigationController!.pushViewController(controller, animated: true)
        }
    }
    //ビューコントローラー追加削除時の呼び出しメソッド
    override func didMove(toParent parent: UIViewController?) {
        if parent == nil {
            //削除(戻るボタンが押された)の場合はレイアウト変更残回数をインクリメントする。
            count += 1
        }
    }
}

ブラッシュアップ

他は特に使わないので、最初のクラスに適用を戻す

戻した〜〜〜

AutoLayout〜〜〜

てな感じで〜〜〜
制約を追加して〜〜〜
Addして〜〜〜
問題無し👀

恒例の地球儀ボタン〜〜〜

追加後〜〜〜

記事公開後、

ハイ、完了💃
実機も問題無し🕺

Apple公式

さて次回は、

をレッツゴする🕺

この記事が気に入ったらサポートをしてみませんか?