Last active
January 21, 2017 21:17
-
-
Save xtravar/8425d0401e1ed30532415543577b14d4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import UIKit | |
// emulates table view sticky headers and demonstrates content inset usage | |
public class FakeTableViewController: UIViewController, UIScrollViewDelegate { | |
// set up views neatly using anonymous closures | |
let scrollView: UIScrollView = { | |
let v = UIScrollView() | |
v.backgroundColor = UIColor.lightGray | |
return v | |
}() | |
// this will be the header that gets 'scrolled over', kind of like a refresh control | |
let headerView: UIView = { | |
let v = UIView() | |
v.backgroundColor = UIColor.blue.withAlphaComponent(0.5) | |
v.translatesAutoresizingMaskIntoConstraints = false | |
return v | |
}() | |
// this will be a sticky section header ala UITableView plain | |
let sectionHeaderView: UIView = { | |
let v = UIView() | |
v.backgroundColor = UIColor.red.withAlphaComponent(0.5) | |
v.translatesAutoresizingMaskIntoConstraints = false; | |
return v | |
}() | |
// some content to take up the screen | |
let fakeContentView: UIView = { | |
let v = UIView() | |
v.backgroundColor = UIColor.white | |
v.translatesAutoresizingMaskIntoConstraints = false; | |
return v | |
}() | |
// the constraints we need to modify later | |
var headerTopConstraint: NSLayoutConstraint! | |
var contentWidthConstraint: NSLayoutConstraint! | |
// we don't want no nibs | |
public override func loadView() { | |
// these lines happen automatically in UITableViewController/UICollectionViewController subclasses | |
self.scrollView.delegate = self; | |
self.scrollView.alwaysBounceVertical = true | |
// cause it's a fake table | |
self.scrollView.isDirectionalLockEnabled = true | |
// add views and fix to edges | |
// order matters for layering | |
[self.headerView, self.fakeContentView, self.sectionHeaderView].forEach { | |
self.scrollView.addSubview($0) | |
$0.leftAnchor.constraint(equalTo: self.scrollView.leftAnchor).isActive = true | |
$0.rightAnchor.constraint(equalTo: self.scrollView.rightAnchor).isActive = true | |
} | |
// fixed constraints - heights | |
self.headerView.heightAnchor.constraint(equalToConstant: 50).isActive = true | |
self.sectionHeaderView.heightAnchor.constraint(equalToConstant: 20).isActive = true | |
self.fakeContentView.heightAnchor.constraint(equalToConstant: 1000).isActive = true | |
// fix content to top and bottom | |
self.fakeContentView.topAnchor.constraint(equalTo: self.scrollView.topAnchor).isActive = true | |
self.fakeContentView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true | |
// keep the section bottom fixed to the top of the content *if it can* be | |
do { | |
let c = self.sectionHeaderView.bottomAnchor.constraint(equalTo: self.fakeContentView.topAnchor) | |
c.priority = UILayoutPriorityDefaultLow | |
c.isActive = true | |
} | |
// require that it's no higher than the top of the background header (which is the top of the content window) | |
self.sectionHeaderView.topAnchor.constraint(greaterThanOrEqualTo: self.headerView.topAnchor).isActive = true | |
// edge insets | |
self.scrollView.contentInset = UIEdgeInsets(top: 70, left: 0, bottom: 0, right: 0) | |
self.scrollView.scrollIndicatorInsets = UIEdgeInsets(top: 70, left: 0, bottom: 0, right: 0) | |
// mutable constraints | |
// make sure width of content exists, otherwise size = 0,0 - table views do not have this problem | |
self.contentWidthConstraint = { | |
let c = self.headerView.widthAnchor.constraint(equalToConstant: 0) | |
c.isActive = true | |
return c | |
}() | |
// keep the 'behind' header fixed | |
self.headerTopConstraint = { | |
let c = self.headerView.topAnchor.constraint(equalTo: self.scrollView.topAnchor) | |
c.isActive = true | |
return c | |
}() | |
// always set self.view last and don't use it until then | |
self.view = self.scrollView | |
} | |
public override func viewWillLayoutSubviews() { | |
super.viewWillLayoutSubviews() | |
// this forces the scrolling content to fill the space (width) given to the view controller | |
self.contentWidthConstraint.constant = self.view.frame.width | |
// TODO: take into account the edge insets of the VC w/r/t status bar and UINavigationBar | |
} | |
public func scrollViewDidScroll(_ scrollView: UIScrollView) { | |
self.headerTopConstraint.constant = scrollView.contentOffset.y | |
// adjust scroll indicator offsets here to match content bouncing | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment