【Swift】FoldingCellを使って折りたたみできるカードUIを作ってみる

Swift

こんちには、フリーのITエンジニアでWeb(PHP:Laravel)のバッグエンドをメインにフルリモートでお仕事させて頂きながら、個人開発でiOSアプリを作っているMoritaです。

FoldingCellを使用してかっこよく折りたたみできるカード型のUIを実装してみたくなったので挑戦してみました。

Ramotion/folding-cell
:octocat: 📃 FoldingCell is an expanding content cell with animation made by @Ramotion - Ramotion/folding-cell

以下サイトを参考にさせて頂いたのですが、一部記述間違い?バージョンの問題?なのか、そのままマネするとうまくいかないので修正を加えてます。

[iOS][Swift3.0] グリーティングカードを開くようなエフェクトが素晴らしいFoldingCell | DevelopersIO
FoldingCellはUITableViewCellを拡張して作られており、紙が折りたたまれるようなコンポーネントを実現することができます。 イメージはグリーティングカードをパタパタ開くような感じです。Ramotion …

検証環境

Xcode:11.4.1
Swift:5

FoldingCellをインストール

CocoaPodsをするためにPodfileに追記します。

  pod 'FoldingCell'

インストールコマンドを実行。

pod install

画面を用意

storyboardにUITableViewControllerを追加し、対応するクラスファイルも作成します。
(TableViewのStyleはPlainでもGroupedでもどっちでもいいみたい)

構成の概要

青く塗ってあるセルが閉じている時の状態で、その下にピンクの縁で表示されているのが展開された状態のセルになります。

FoldingCellを継承したカスタムセルを作成

import UIKit
import FoldingCell

class SampleCell: FoldingCell {
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
    
    override func animationDuration(_ itemIndex:NSInteger, type:AnimationType)-> TimeInterval {
        let durations = [0.26, 0.2, 0.2]
        return durations[itemIndex]
    }
}

storybordのTableViewCellにカスタムセルを設定

storybord上のTableViewCellと先ほど作成したカスタムセル(SampleCell)を紐付けます。

セル上にViewを配置

もとのTavleViewCell(白いところ)を適当に広げて大きくします。
次に閉じている時のUIView(青)と、開いてる時のUIView(ピンク)を配置します。

閉じている時のViewにカスタムセルのクラスを紐付ける

閉じている時のView(青)を選択して、ClassにRotatedViewを紐付けます。

制約の設定

セルに制約を設定します。
上下左右に自分の好みで設定すればいいですが、開いている時のView(ピンク)のTopは
SurperViewからのスペースになります。

閉じている時のViewは上下:0、左右:8に高さ80を設定。

開いている時のViewは上はSurperViewからの位置、左右:8に高さ352に設定。

Outlet接続

最初、UITableViewControllerのクラスファイルにOutlet接続したところエラーが発生しました。その方法ではだめみたいです。

開いた時のView(ピンク)の中に展開した時のViewを設定

viewを4つ配置して、上下:0、左右:8と高さ88にしました。

あと、セルがわかりやすいように偶数のViewの色を変更しました。

FoldingCellのプロパティを設定

storyboad上でSampleCellを選択してItem Countを4にします。
Back View Colorが展開時のセルの裏側の色になります。
また、IdentifierをCellを設定しています。

UITableViewControllerのコードを実装

参考記事だとdidSelectRowAtでselectedAnimationメソッドを使用していますが、
廃止されたようで、代わりにunfoldを使用すれがいいようです。

import UIKit
import FoldingCell

class ListTableViewController: UITableViewController {
    
    private let closeCellHeight: CGFloat = 96
    private let openCellHeight: CGFloat = 352

    private let cellCount = 3

    private var cellHeights: [CGFloat] = []
    
    static func createInstance() -> ListTableViewController {
        let storyboard = UIStoryboard(name: "list", bundle: nil)
        let instance = storyboard.instantiateViewController(withIdentifier: "ListTableViewController") as! ListTableViewController
        return instance
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        cellHeights = Array.init(repeating: closeCellHeight, count: cellCount)
        tableView.backgroundColor = UIColor.gray
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cellCount
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return cellHeights[indexPath.row]
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? SampleCell else {
            fatalError("Could not create SampleCell")
        }
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard case let cell as SampleCell = tableView.cellForRow(at: indexPath) else {
            return
        }

        var duration = 0.0
        if cellHeights[indexPath.row] == closeCellHeight { // open cell
            cellHeights[indexPath.row] = openCellHeight
            cell.unfold(true, animated: true, completion: nil)
            duration = 0.5
        } else {// close cell
            cellHeights[indexPath.row] = closeCellHeight
            cell.unfold(false, animated: true, completion: nil)
            duration = 1.1
        }

        UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
            tableView.beginUpdates()
            tableView.endUpdates()
        }, completion: nil)
    }
}

まとめ

いい感じに実装できました。スマフォだと画面が小さいので一画面で多くの情報が表示できるのはいいですね。
なによりアニメーションがあっておしゃれです。

コメント

タイトルとURLをコピーしました