Search code examples
iosswiftuitableviewheaderparallax

Parallax effect in tableview section Header throws a UIView-nil error?


I have a custom UITableViewHeaderFooterView header.I took the extension on this article Swift - Parallax Header View - ScrollView overlap cells.

import UIKit

class CustomSoccerHeaderView: UITableViewHeaderFooterView {

    var clickBravisso: Soccer?
    @IBOutlet weak var bravoBtn: UIButton!
    @IBOutlet weak var countBravo: UILabel!
   @IBOutlet weak var nameHeader: UILabel!
    @IBOutlet weak var imageHeader: UIImageView!
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code



    }


extension UITableView {

    func addImageHeaderView(headerView: UIView, height: CGFloat) {
        self.contentInset = UIEdgeInsets(top: height, left: 0, bottom: 0, right: 0)
        self.contentOffset = CGPoint(x: 0, y: -height)
        self.tableHeaderView = headerView
        self.tableHeaderView?.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: height)
    }

    func updateHeaderView(height kTableHeaderHeight: CGFloat) {

        var headerRect = CGRect(x: 0, y: -kTableHeaderHeight , width: self.bounds.width, height: kTableHeaderHeight)
        if self.contentOffset.y < -kTableHeaderHeight {
            headerRect.origin.y = self.contentOffset.y
            headerRect.size.height = -self.contentOffset.y
        }
        self.tableHeaderView?.frame = headerRect
    }

}

In the method of down loading data to the cell header.Stalled in the function to implement Parallax effect.I will be very grateful who will be able to prompt and correct me.Experience in this is not enough and can't find the article right.

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "CustomSoccerHeaderView") as! CustomSoccerHeaderView

        header.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 350)

        header.clickBravisso = detailSoccer

        header.nameHeader.text = detailSoccer.matchS
        header.countBravo.text = ""


        // header.bravoBtn.addTarget(CustomSoccerHeaderView(), action: #selector(CustomSoccerHeaderView.likeBtn(_:)), for: UIControlEvents.touchUpInside)


        detailSoccer.imagePrS.getDataInBackground { (data, error) in
            header.imageHeader.image = error == nil ? UIImage(data: data!) : nil
        }


        return header
    }

    class DetailSoccerTableViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate  {

    @IBOutlet weak var tableView: UITableView!

        var detailSoccer: Soccer!
        var selectedSoccer = [Soccer]()

        var headerView: UIView!

    override func viewDidLoad() {
            super.viewDidLoad()

            let backButton = UIBarButtonItem()
            backButton.title = ""

           self.navigationController?.navigationBar.topItem?.backBarButtonItem = backButton

           // self.navigationItem.rightBarButtonItem = barButton
          //  self.navigationItem.rightBarButtonItem?.tintColor = UIColor.universalColorYellow
            let yourBackImage = UIImage(named: "backItem")
            self.navigationController?.navigationBar.backIndicatorImage = yourBackImage
            self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = yourBackImage
            self.navigationController?.navigationItem.leftItemsSupplementBackButton = true
            self.navigationController?.navigationBar.tintColor = UIColor.universalColorYellow


            //title = detailSoccer.detailTitleS

            let nib: UINib = UINib(nibName: "CustomSoccerHeaderView", bundle: nil)
            tableView.register(nib, forHeaderFooterViewReuseIdentifier: "CustomSoccerHeaderView")


            tableView.tableFooterView = UIView(frame: .zero)

            //tableView.layer.masksToBounds = true
            tableView.estimatedRowHeight = 280
            tableView.rowHeight = UITableView.automaticDimension
            tableView.separatorStyle = .none
            tableView.delegate = self
            tableView.dataSource = self
            tableView.register(UINib(nibName:"FootTableViewCell",bundle:nil), forCellReuseIdentifier: "cellSoc")
            self.view.addSubview(tableView)

            self.edgesForExtendedLayout = UIRectEdge.init(rawValue: 0)
            self.extendedLayoutIncludesOpaqueBars = true

            tableView.addImageHeaderView(headerView: headerView, height: 0)// error 

            tableView.reloadData()
            loadMatchSoccer()

            tableView.rowHeight = UITableView.automaticDimension

        }
 func scrollViewDidScroll(_ scrollView: UIScrollView) {
        tableView.updateHeaderView(height: 200)
    }

        }

this line gives an error - tableView.addImageHeaderView(headerView: headerView, height: 0) headerView = (UIView?) nil


Solution

  • If your custom view is defined in a xib, try changing this line:

    var headerView: UIView!
    

    To this:

    lazy var headerView: CustomSoccerHeaderView = {
        return Bundle.main.loadNibNamed("CustomSoccerHeaderView", owner: nil, options: nil)!.first as! CustomSoccerHeaderView
    }()
    

    Be careful not to become confused by the two concepts:

    1. UITableViewHeaderFooterView - has specific child views into which you should put your customisations, ideally should be registered with an identifier.
    2. tableHeaderView - is just any old UIView subclass, does not participate in the cell reuse mechanism.

    As described, you need the second option, but your posted code seems to be doing work to support the first option.