mrGott
mrGott

Reputation: 1076

Stretchy Header for a programmatically created UITAbleView - Swift

I have created UITableView programmatically. I'm not using storyboards. I read and watched tons of tutorials on how to create a stretchy header but all of them use Storyboards.

As I understood, to achieve stretchy effect you have to add tableViewHeader as a subview and then move it to the back with .sendSubviewToBack and then the rest of the logic will apply.

but I can't figure out what has to be sent to subview when the header is created programmatically. When using storyboards you assign a custom header class to a variable and then add that to subview. So here's my TableViewcontroller:

import UIKit

private let reuseIdentifier = "contentCellId"
private let headerIdentifier = "headerCellId"

class ItemDetailViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        tableView.registerClass(ItemDetailsContentCell.self, forCellReuseIdentifier: reuseIdentifier)
        tableView.registerClass(ItemDetailsHeaderCell.self, forHeaderFooterViewReuseIdentifier: headerIdentifier)

        let headerView = tableView.tableHeaderView
        print(headerView) // returns NIL     

        tableView.separatorStyle = .None

        // TableView heights
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 500.0

    }

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

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 1
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! ItemDetailsContentCell

        // Configure the cell...

        return cell
    }

    override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerView = tableView.dequeueReusableHeaderFooterViewWithIdentifier(headerIdentifier)
        return headerView
    }

    override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        let cell = tableView.dequeueReusableHeaderFooterViewWithIdentifier(headerIdentifier) as! ItemDetailsHeaderCell

        let width = view.frame.width
        let imageRatio = (cell.itemImage.image?.size.height)! / (cell.itemImage.image?.size.width)!

        let newHeight = width * imageRatio

        return newHeight
    }

//    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
//        return UITableViewAutomaticDimension
//    }
//    
//    override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
//        return 500
//    }

}

Its nothing fancy. Here's the code sample I'm trying to replicate:

 @IBOutlet weak var tableView:UITableView!
@IBOutlet weak var headerView:ArticleHeaderView!

var article: Article?

// Header view configuration
private var defaultTableHeaderHeight:CGFloat = 250.0
private var lastContentOffset:CGFloat = 0.0
private let defaultHeaderImageName = "bg-pattern"


override func viewDidLoad() {
    super.viewDidLoad()

    tableView.separatorStyle = .None
    tableView.rowHeight = UITableViewAutomaticDimension

    // Add the header view to the table view background
    defaultTableHeaderHeight = headerView.frame.size.height
    lastContentOffset = -defaultTableHeaderHeight

    print(defaultTableHeaderHeight)
    print(tableView.tableHeaderView!.frame.height)


    tableView.tableHeaderView = nil
    tableView.addSubview(headerView)
    tableView.sendSubviewToBack(headerView)

    tableView.contentInset = UIEdgeInsets(top: defaultTableHeaderHeight, left: 0, bottom: 0, right: 0)
    tableView.contentOffset = CGPoint(x: 0, y: -defaultTableHeaderHeight)

    // Disable content inset adjustment
    self.automaticallyAdjustsScrollViewInsets = false

what's equivalent of headerView:ArticleHeaderView! in my code?

It might sound dumb but I'm stuck. HELP!

Upvotes: 2

Views: 2532

Answers (1)

userx
userx

Reputation: 1121

You could see an example here:

https://medium.com/@jeremysh/creating-a-sticky-header-for-a-uitableview-40af71653b55

The author of the article talks about how to create a Custom Header View and use it using constraints in code and applying the transformation using delegates of the scrollView which the UITableView inherits from.

He talks about both the downward and upward scrolling to make the headerView smaller or larger.

    func animateHeader() {
      self.headerHeightConstraint.constant = 150
      UIView.animateWithDuration(0.4, delay: 0.0, 
       usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, 
       options: .CurveEaseInOut, animations: {
     self.view.layoutIfNeeded()
    }, completion: nil)
   }

    func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if self.headerHeightConstraint.constant > 150 {
animateHeader()
}
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if self.headerHeightConstraint.constant > 150 {
animateHeader()
}
}

Upvotes: 3

Related Questions