Created
June 14, 2019 18:36
-
-
Save amadeu01/dbd50cfb3d74c471b51ce88df8371129 to your computer and use it in GitHub Desktop.
Bug -> https://www.youtube.com/watch?v=2BBRnZ444bE question -> https://stackoverflow.com/questions/56602500/uirefreshcontrol-endrefresh-jumps-when-used-with-large-title-enabled
This file contains hidden or 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 UIKit | |
| @UIApplicationMain | |
| class AppDelegate: UIResponder, UIApplicationDelegate { | |
| var window: UIWindow? | |
| func application( | |
| _ application: UIApplication, | |
| didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? | |
| ) -> Bool { | |
| let window = UIWindow(frame: UIScreen.main.bounds) | |
| window.makeKeyAndVisible() | |
| let nav = UINavigationController() | |
| nav.title = "My Nav" | |
| nav.navigationBar.prefersLargeTitles = true | |
| nav.viewControllers = [ViewController()] | |
| window.rootViewController = nav | |
| self.window = window | |
| return true | |
| } | |
| } |
This file contains hidden or 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 UIKit | |
| import Foundation | |
| final class ViewController: UICollectionViewController { | |
| let randomHeight = Int.random(in: 100..<300) | |
| init() { | |
| let layout = UICollectionViewFlowLayout() | |
| layout.scrollDirection = .vertical | |
| layout.estimatedItemSize = CGSize(width: 20, height: 20) | |
| super.init(collectionViewLayout: layout) | |
| } | |
| required init?(coder aDecoder: NSCoder) { | |
| fatalError("init(coder:) has not been implemented") | |
| } | |
| override func viewDidLoad() { | |
| super.viewDidLoad() | |
| navigationItem.title = "Try to refresh" | |
| self.navigationController?.navigationBar.isTranslucent = false | |
| self.extendedLayoutIncludesOpaqueBars = true | |
| self.navigationController?.navigationBar.prefersLargeTitles = false | |
| self.navigationController?.navigationBar.prefersLargeTitles = true | |
| collectionView.backgroundColor = .white | |
| registerCells() | |
| setupRefreshControl() | |
| } | |
| private func registerCells() { | |
| self.collectionView.register( | |
| Cell.self, | |
| forCellWithReuseIdentifier: "Cell" | |
| ) | |
| } | |
| private func setupRefreshControl() { | |
| let refreshControl = UIRefreshControl() | |
| refreshControl.addTarget( | |
| self, | |
| action: #selector(refreshControlDidFire), | |
| for: .valueChanged | |
| ) | |
| self.collectionView.refreshControl = refreshControl | |
| } | |
| @objc private func refreshControlDidFire(_ sender: Any?) { | |
| if let sender = sender as? UIRefreshControl, sender.isRefreshing { | |
| refresh() | |
| } | |
| } | |
| override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { | |
| if collectionView.refreshControl!.isRefreshing { | |
| refresh() | |
| } | |
| } | |
| private func refresh() { | |
| if !collectionView.isDragging { | |
| collectionView.refreshControl!.endRefreshing() | |
| collectionView.perform(#selector(collectionView.reloadData), with: nil, afterDelay: 0.05) | |
| } | |
| } | |
| } | |
| extension ViewController { | |
| override func numberOfSections(in collectionView: UICollectionView) -> Int { | |
| return 1 | |
| } | |
| override func collectionView( | |
| _ collectionView: UICollectionView, | |
| numberOfItemsInSection section: Int | |
| ) -> Int { | |
| return 10 | |
| } | |
| override func collectionView(_ collectionView: UICollectionView, | |
| cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { | |
| guard let cell = collectionView.dequeueReusableCell( | |
| withReuseIdentifier: "Cell", for: indexPath | |
| ) as? Cell else { | |
| return UICollectionViewCell() | |
| } | |
| cell.label.text = "Text number \(indexPath.row), with height \(randomHeight)" | |
| cell.heightAnchorConstraint.constant = CGFloat(randomHeight) | |
| return cell | |
| } | |
| } | |
| extension ViewController: UICollectionViewDelegateFlowLayout { | |
| func collectionView(_ collectionView: UICollectionView, | |
| layout collectionViewLayout: UICollectionViewLayout, | |
| insetForSectionAt section: Int) -> UIEdgeInsets { | |
| return UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0) | |
| } | |
| } | |
| final class Cell: UICollectionViewCell { | |
| private let shadowView = UIView() | |
| private let containerView = UIView() | |
| private let content = UIView() | |
| let label = UILabel() | |
| var heightAnchorConstraint: NSLayoutConstraint! | |
| override init(frame: CGRect = .zero) { | |
| super.init(frame: frame) | |
| setupViews() | |
| } | |
| required init?(coder aDecoder: NSCoder) { | |
| fatalError("init(coder:) has not been implemented") | |
| } | |
| private func setupViews() { | |
| insertSubview(shadowView, at: 0) | |
| addSubview(containerView) | |
| containerView.addSubview(label) | |
| containerView.addSubview(content) | |
| activateConstraints() | |
| } | |
| private func activateConstraints() { | |
| self.translatesAutoresizingMaskIntoConstraints = false | |
| shadowView.translatesAutoresizingMaskIntoConstraints = false | |
| containerView.translatesAutoresizingMaskIntoConstraints = false | |
| label.translatesAutoresizingMaskIntoConstraints = false | |
| content.translatesAutoresizingMaskIntoConstraints = false | |
| shadowView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true | |
| shadowView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true | |
| shadowView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true | |
| shadowView.bottomAnchor | |
| .constraint(equalTo: self.bottomAnchor).isActive = true | |
| containerView.backgroundColor = .white | |
| containerView.layer.cornerRadius = 14 | |
| containerView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true | |
| containerView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true | |
| containerView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true | |
| containerView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true | |
| let widthAnchorConstraint = containerView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width - 20) | |
| widthAnchorConstraint.identifier = "Width ContainerView" | |
| widthAnchorConstraint.priority = .defaultHigh | |
| widthAnchorConstraint.isActive = true | |
| label.numberOfLines = 0 | |
| label.textAlignment = .center | |
| label.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true | |
| label.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true | |
| label.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true | |
| label.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true | |
| content.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 20).isActive = true | |
| content.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 10).isActive = true | |
| content.bottomAnchor.constraint(lessThanOrEqualTo: containerView.bottomAnchor, constant: -10).isActive = true | |
| heightAnchorConstraint = content.heightAnchor.constraint(greaterThanOrEqualToConstant: 220) | |
| heightAnchorConstraint.identifier = "Height Content" | |
| heightAnchorConstraint.priority = .defaultHigh | |
| heightAnchorConstraint.isActive = true | |
| content.widthAnchor.constraint(equalToConstant: 40).isActive = true | |
| content.backgroundColor = .red | |
| } | |
| override func layoutSubviews() { | |
| super.layoutSubviews() | |
| applyShadow(width: 0.20, height: -0.064) | |
| } | |
| private func applyShadow(width: CGFloat, height: CGFloat) { | |
| let shadowPath = UIBezierPath(roundedRect: shadowView.bounds, cornerRadius: 14.0) | |
| shadowView.layer.masksToBounds = false | |
| shadowView.layer.shadowRadius = 8.0 | |
| shadowView.layer.shadowColor = UIColor.black.cgColor | |
| shadowView.layer.shadowOffset = CGSize(width: width, height: height) | |
| shadowView.layer.shadowOpacity = 0.3 | |
| shadowView.layer.shadowPath = shadowPath.cgPath | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment