uitableviewで複雑なレイアウトを作る方法

はじめに

今回作りたい画面はこんなかんじ。

スクロール前
f:id:yoppy0066:20150421104234p:plain


スクロール後
f:id:yoppy0066:20150421104240p:plain

webとかでもありがちなページです。
ページ上部にヘッダがあって、ページ下部にフッターがあって、間にリストみたいなのがある。
ちなみにヘッダーとフッターは固定ではありません

が、ずっとUIScrollViewを使ってやろうとしてたんですけど、なかなかうまくいかず、、、
どこかの記事でiPhoneアプリ開発はUITableViewを使ってナンボみたいなのを読んで記憶があって無理やりUITableViewで実現してみました。

実装

ViewController.swif

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    // テーブルビュー
    var tableView: UITableView!
    
    // テーブルデータ
    var tableData = [
        "データ1",
        "データ2",
        "データ3",
        "データ4",
        "データ5",
        "データ6",
        "データ7",
        "データ8",
        "データ9",
        "データ10",
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let displayWidth = self.view.frame.width
        let displayHeight = self.view.frame.height
        
        tableView = UITableView(frame: CGRect(x:0, y:0, width:displayWidth, height:displayHeight))
        
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        tableView.registerClass(CustomTableViewFooterCell.self, forCellReuseIdentifier: "FooterCell")
        
        tableView.delegate = self
        tableView.dataSource = self
        
        self.view.addSubview(tableView)
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // 1セクション目のフッターをヘッダーとして使うためにダミーのセクションを返します
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 2
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 {
            return 0
        } else {
            return tableData.count + 1 // 行数+フッター数
        }
    }
    
    // テーブルヘッダーの高さをかえします(フッターだけどヘッダーとして利用)
    func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        if section == 0 {
            let heightView = self.setHeaderView(tableView,isLayout: false) as! CGFloat
            return heightView
        } else {
            return 0
        }
    }
    
    // テーブルヘッダーにViewをセットしてかえします(フッターだけどヘッダーとして利用)
    func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        if section == 0 {
            let viewHeader = self.setHeaderView(tableView, isLayout: true) as! UIView
            return viewHeader
        } else {
            return UIView()
        }
    }

    // Viewの追加とViewの高さを求めてかえします
    func setHeaderView(tableView: UITableView, isLayout: Bool) -> AnyObject {
        // View全体の高さ
        var heightView: CGFloat = 0
        
        // ベースとなるView(高さは変わるので暫定)
        let viewHeader = UIView()
        viewHeader.frame = CGRectMake(0, 0, tableView.frame.width, 100)
        
        //  ヘッダーラベル
        let myLabel = UILabel(frame: CGRectMake(0, 0, self.view.frame.width, 200))
        myLabel.text = "ヘッダー"
        myLabel.font = UIFont.systemFontOfSize(22)
        myLabel.textAlignment = NSTextAlignment.Center
        myLabel.backgroundColor = UIColor.redColor()
        
        heightView += myLabel.frame.height
        
        if isLayout == true {
            viewHeader.addSubview(myLabel)
            return viewHeader
        } else {
            return heightView
        }
    }

    // テーブルセルの高さをかえします
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        // 1セクション目はダミー
        if indexPath.section == 0 {
            return 0
        // 2セクション目が本来のデータ
        } else {
            if self.tableData.count > indexPath.row {
                return 44
            } else {
                let cell = CustomTableViewFooterCell()
                var height = cell.setData(false) as! CGFloat
                return height
            }
        }
    }
    
    // テーブルセルにデータをセットします
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // 1セクション目はダミー
        if indexPath.section == 0 {
            let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
            return cell
        // 2セクション目が本来のデータ
        } else {
            if self.tableData.count > indexPath.row {
                let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
                cell.textLabel?.text = self.tableData[indexPath.row]
                return cell
            } else {
                let cell = tableView.dequeueReusableCellWithIdentifier("FooterCell", forIndexPath: indexPath) as! CustomTableViewFooterCell
                cell.setData(true)
                return cell
            }
        }
    }
}

CustomTableViewFooterCell.swift

class CustomTableViewFooterCell: UITableViewCell
{
    var buttonShowMore = UIButton()
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
        //First Call Super
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    func setData(isLayout: Bool) -> AnyObject {
        // View全体の高さ
        var heightView: CGFloat = 1
        
        var myLabel = UILabel(frame: CGRectMake(0, 0, self.frame.width, 200))
        myLabel.text = "フッター"
        myLabel.backgroundColor = UIColor.blueColor()
        myLabel.font = UIFont.systemFontOfSize(22)
        myLabel.textAlignment = NSTextAlignment.Center
        
        heightView += myLabel.frame.height
        
        if isLayout == true {
            self.contentView.addSubview(myLabel)
            return true
        } else {
            return heightView
        }
    }
}

ポイントとしては
1. UITableViewにはセクションごとにヘッダーとフッターが用意されているのですが、それのフッターをヘッダーとして使った
2. UITableViewCellのカスタムセルにViewをつくって突っ込めば色々複雑なデザインが作れる
とかでしょうか

1. をヘッダではなく、フッターを使って理由はヘッダーを使うとスクロールしても付いてきてしまって
調べるとやり方はいくつか出てきたんですけど、なんか理解できなくてフッターを使うという手段を使いました。

初心者ですので、こんな奇異なやり方なんですけど、
ちゃんとしたかたからしたら、そんなやり方やらなくても、、、とかあると思うのでアドバイスいただけると嬉しいです!

けど、テーブルビュー使うと直感的にわかりやすいですね

以上です