I researched fairly a bit however simply could not discover the reply to my query.
I’ve created a desk (fashion: .grouped
) in Xcode with two headers I need to make sticky. The higher one ought to collapse on scrolling till the peak of the others cells is reached, the decrease one ought to simply keep like it’s – so fairly just like the behaviour proper now (see beneath) – simply sticking to the highest.
My code is as follows:
- HomeTableViewController.swift
import UIKit
class HomeTableViewController: UITableViewController {
var headerView: HeaderView = {
let nib = UINib(nibName: "HeaderView", bundle: nil)
return nib.instantiate(withOwner: HomeTableViewController.self, choices: nil).first as! HeaderView
}()
override func viewDidLoad() {
tremendous.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// Uncomment the next line to protect choice between displays
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the next line to show an Edit button within the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
headerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
headerView.titleLabel.textual content = "Title"
headerView.scrollView = tableView
headerView.body = CGRect(
x: 0,
y: tableView.safeAreaInsets.prime,
width: view.body.width,
top: 250)
tableView.backgroundView = UIView()
tableView.backgroundView?.addSubview(headerView)
tableView.contentInset = UIEdgeInsets(
prime: 250,
left: 0,
backside: 0,
proper: 0)
}
override func viewSafeAreaInsetsDidChange() {
tremendous.viewSafeAreaInsetsDidChange()
tableView.contentInset = UIEdgeInsets(prime: 250 + tableView.safeAreaInsets.prime,
left: 0,
backside: 0,
proper: 0)
headerView.updatePosition()
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection part: Int) -> UIView? {
let sectionHeaderLabelView = UIView()
sectionHeaderLabelView.backgroundColor = .systemBackground
let sectionHeaderLabel = UILabel()
sectionHeaderLabel.textual content = "Subtitle"
sectionHeaderLabel.textColor = .label
sectionHeaderLabel.font = UIFont.systemFont(ofSize: 20.0, weight: .semibold)
sectionHeaderLabel.body = CGRect(x: view.body.width * 0.05, y: 0, width: view.body.width, top: 58)
sectionHeaderLabelView.addSubview(sectionHeaderLabel)
let sectionHeaderButton = UIButton()
sectionHeaderButton.body = CGRect(x: view.body.width * 0.58, y: 0, width: view.body.width * 0.5, top: 58)
sectionHeaderButton.setTitle("alle anzeigen →", for: .regular)
sectionHeaderButton.setTitleColor(.secondaryLabel, for: .regular)
sectionHeaderButton.titleLabel?.font = UIFont.systemFont(ofSize: 15.0, weight: .semibold)
sectionHeaderButton.addTarget(self, motion: #selector(buttonAction), for: .touchUpInside)
sectionHeaderLabelView.addSubview(sectionHeaderButton)
return sectionHeaderLabelView
}
@objc func buttonAction(sender: UIButton!) {
print("Button tapped")
}
override func viewWillLayoutSubviews() {
tremendous.viewWillLayoutSubviews()
headerView.updatePosition()
}
// MARK: Desk view knowledge supply
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the variety of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection part: Int) -> Int {
// #warning Incomplete implementation, return the variety of rows
return 20
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "providerCell", for: indexPath) as! HomeTableViewCell
[...]
return cell
}
[...]
}
- HeaderView.swift (only for the collapsing “prime” header)
import Basis
import UIKit
class HeaderView: UIView {
@IBOutlet non-public(set) var titleLabel: UILabel!
@IBOutlet weak var topBlurView: UIVisualEffectView!
@IBOutlet weak var bottomBlurView: UIVisualEffectView!
@IBOutlet weak var scrollView: UIScrollView?
non-public var cachedMinimumSize: CGSize?
override func layoutSubviews() {
tremendous.layoutSubviews()
topBlurView.impact = .none
bottomBlurView.impact = .none
}
// Calculate and cache the minimal measurement the header's constraints will match.
// This worth is cached since it may be a pricey calculation to make, and
// we need to preserve the framerate excessive.
non-public var minimumHeight: CGFloat {
get {
guard let scrollView = scrollView else { return 0 }
if let cachedSize = cachedMinimumSize {
if cachedSize.width == scrollView.body.width {
return cachedSize.top
}
}
// Ask Auto Format what the minimal top of the header ought to be.
let minimumSize = systemLayoutSizeFitting(CGSize(width: scrollView.body.width, top: 0),
withHorizontalFittingPriority: .required,
verticalFittingPriority: .defaultLow)
cachedMinimumSize = minimumSize
return minimumSize.top
}
}
func updatePosition() {
guard let scrollView = scrollView else { return }
// Calculate the minimal measurement the header's constraints will match
let minimumSize = minimumHeight
// Calculate the baseline header top and vertical place
let referenceOffset = scrollView.safeAreaInsets.prime
let referenceHeight = scrollView.contentInset.prime - referenceOffset
// Calculate the brand new body measurement and place
let offset = referenceHeight + scrollView.contentOffset.y
let targetHeight = referenceHeight - offset - referenceOffset
var targetOffset = referenceOffset
if targetHeight < minimumSize {
targetOffset += targetHeight - minimumSize
}
// Replace the header's top and vertical place.
var headerFrame = body;
headerFrame.measurement.top = max(minimumSize, targetHeight)
headerFrame.origin.y = targetOffset
body = headerFrame;
}
}
Might anybody help kindly on the right way to make these two persist with the highest when scrolling?
All the very best!