UIPageViewController not calling delegate methods (Swift 5) - ios

I have an extremely simple UIPageViewController setup in my project. When I create my page view controller and navigate to it, everything seems to work properly and it loads the first page properly. However, when I try to swipe or switch to other pages in the array of ViewControllers, my page controller does not call its delegate methods to do so.
Here is how I am instantiating and navigating to the page view controller from the parent view:
let tutorialPageVC = TareTutorialPageViewController()
let nc = UINavigationController(rootViewController: tutorialPageVC)
nc.modalPresentationStyle = .fullScreen
nc.definesPresentationContext = true
nc.setNavigationBarHidden(true, animated: true)
self.present(nc, animated: true, completion: nil)
And here is my page view controller class:
import UIKit
class TareTutorialPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var tutorialPages = [UIViewController]()
let pageControl = UIPageControl()
override init(transitionStyle style: UIPageViewController.TransitionStyle, navigationOrientation: UIPageViewController.NavigationOrientation, options: [UIPageViewController.OptionsKey : Any]? = nil) {
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
self.dataSource = self
self.delegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
let initialTutorialPage = 0
let tutorialPage1 = TutorialPage1ViewController()
let tutorialPage2 = TutorialPage2ViewController()
let tutorialPage3 = TutorialPage3ViewController()
self.tutorialPages.append(tutorialPage1)
self.tutorialPages.append(tutorialPage2)
self.tutorialPages.append(tutorialPage3)
setViewControllers([tutorialPages[initialTutorialPage]], direction: .forward, animated: true, completion: nil)
self.pageControl.frame = CGRect()
self.pageControl.currentPageIndicatorTintColor = UIColor.white
self.pageControl.pageIndicatorTintColor = UIColor.lightGray
self.pageControl.numberOfPages = self.tutorialPages.count
self.pageControl.currentPage = initialTutorialPage
self.view.addSubview(self.pageControl)
self.pageControl.translatesAutoresizingMaskIntoConstraints = false
self.pageControl.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -5).isActive = true
self.pageControl.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: -20).isActive = true
self.pageControl.heightAnchor.constraint(equalTo: self.view.heightAnchor, constant: 20).isActive = true
self.pageControl.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
//Might not need any of this if we only want the user to move forward??
if let viewControllerIndex = self.tutorialPages.firstIndex(of: viewController)
{
if viewControllerIndex == 0
{
return self.tutorialPages.last
}
else
{
return self.tutorialPages[viewControllerIndex-1]
}
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if let viewControllerIndex = self.tutorialPages.firstIndex(of: viewController)
{
if viewControllerIndex < self.tutorialPages.count - 1
{
return self.tutorialPages[viewControllerIndex + 1]
}
else
{
//Navigation to go to scale tare settings here...
//For now just returns to first page of page view
return self.tutorialPages.first
}
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if let viewControllers = pageViewController.viewControllers {
if let viewControllerIndex = self.tutorialPages.firstIndex(of: viewControllers[0])
{
self.pageControl.currentPage = viewControllerIndex
}
}
}
}
Here is an example of one my extremely simple view controllers that are shown by the page view controller:
import UIKit
class TutorialPage1ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.black
let label = UILabel()
label.text = "Tutorial page 1"
label.textColor = UIColor.white
self.view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50).isActive = true
label.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 20).isActive = true
}
}

The problem is not that the delegate funcs are not being called, the problem is that you are completely overlaying your UIPageViewController with a UIPageControl.
You can confirm this by adding this line:
// existing line
self.view.addSubview(self.pageControl)
// add this line
self.pageControl.backgroundColor = .orange
Change your constraint setup like this:
// completely remove these lines
//self.pageControl.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -5).isActive = true
//self.pageControl.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: -20).isActive = true
//self.pageControl.heightAnchor.constraint(equalTo: self.view.heightAnchor, constant: 20).isActive = true
//self.pageControl.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
pageControl.widthAnchor.constraint(equalTo: g.widthAnchor, constant: -20.0),
pageControl.centerXAnchor.constraint(equalTo: g.centerXAnchor),
pageControl.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -5.0),
])
Now you should see the page control at the bottom, and you'll be able to swipe through the pages.
By the way, UIPageViewController has a "built-in" UIPageControl that you might find works better anyway.

Related

Interactive push view controller

I am looking to have an interactive push view controller. So if the user pans from the right edge of the screen, it will pop to the next view controller. I have found this CocoaPods: https://github.com/rickytan/RTInteractivePush, but it is written in Objective-C, so I am unsure how to use it. On my own I have been able to come up with a pan gesture that pushes a view, however it is not interactive:
swipeGesture = UIPanGestureRecognizer(target: self, action:#selector(swiped(_:)))
swipeGesture.delegate = self
view.addGestureRecognizer(swipeGesture)
#objc func swiped(_ gestureRecognizer: UIPanGestureRecognizer) {
let newView = View()
self.navigationController?.pushViewController(newView, animated: true)
}
Any help would be greatly appreciated!
You can do it programmatically with UIPageViewController:
Set your UIPageViewController class:
import UIKit
class MyControllerContainer: UIPageViewController {
// set UIPageViewController transition style
override init(transitionStyle style: UIPageViewController.TransitionStyle, navigationOrientation: UIPageViewController.NavigationOrientation, options: [UIPageViewController.OptionsKey : Any]? = nil) {
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
print("init(coder:) has not been implemented")
}
var pages = [UIViewController]()
var pageControl = UIPageControl()
let initialPage = 0
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setup()
style()
layout()
}
}
Now set style, setup, and layout func:
extension MyControllerContainer {
func setup() {
dataSource = self
delegate = self
pageControl.addTarget(self, action: #selector(pageControlDragged(_:)), for: .valueChanged)
// create an array of viewController
let page1 = ViewController1()
let page2 = ViewController2()
let page3 = ViewController3()
pages.append(page1)
pages.append(page2)
pages.append(page3)
// set initial viewController to be displayed
setViewControllers([pages[initialPage]], direction: .forward, animated: true, completion: nil)
}
func style() {
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.currentPageIndicatorTintColor = .white
pageControl.pageIndicatorTintColor = UIColor(white: 1, alpha: 0.3)
pageControl.numberOfPages = pages.count
pageControl.currentPage = initialPage
}
func layout() {
view.addSubview(pageControl)
NSLayoutConstraint.activate([
pageControl.widthAnchor.constraint(equalTo: view.widthAnchor),
pageControl.heightAnchor.constraint(equalToConstant: 20),
view.bottomAnchor.constraint(equalToSystemSpacingBelow: pageControl.bottomAnchor, multiplier: 1),
])
}
}
set how we change controller when pageControl Dragged:
extension MyControllerContainer {
// How we change controller when pageControl Dragged.
#objc func pageControlDragged(_ sender: UIPageControl) {
setViewControllers([pages[sender.currentPage]], direction: .forward, animated: true, completion: nil)
}
}
after that set UIPageViewController delegate and datasource:
// MARK: - DataSources
extension MyControllerContainer: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let currentIndex = pages.firstIndex(of: viewController) else { return nil }
if currentIndex == 0 {
return nil // stop presenting controllers when swipe from left to right in ViewController1
} else {
return pages[currentIndex - 1] // go previous
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let currentIndex = pages.firstIndex(of: viewController) else { return nil }
if currentIndex == 2 {
print("Last index...")
}
if currentIndex < pages.count - 1 {
return pages[currentIndex + 1] // go next
} else {
return nil // stop presenting controllers when swipe from right to left in ViewController3
}
}
}
// MARK: - Delegates
extension MyControllerContainer: UIPageViewControllerDelegate {
// How we keep our pageControl in sync with viewControllers
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard let viewControllers = pageViewController.viewControllers else { return }
guard let currentIndex = pages.firstIndex(of: viewControllers[0]) else { return }
pageControl.currentPage = currentIndex
}
}
Now add your viewControllers, in my case 3:
// MARK: - ViewControllers
class ViewController1: UIViewController {
let mylabel1: UILabel = {
let label = UILabel()
label.text = "Controller 1"
label.textAlignment = .center
label.textColor = .white
label.font = .systemFont(ofSize: 20, weight: .semibold)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemRed
view.addSubview(mylabel1)
mylabel1.heightAnchor.constraint(equalToConstant: 50).isActive = true
mylabel1.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
mylabel1.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
mylabel1.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
class ViewController2: UIViewController {
let mylabel2: UILabel = {
let label = UILabel()
label.text = "Controller 2"
label.textAlignment = .center
label.textColor = .white
label.font = .systemFont(ofSize: 20, weight: .semibold)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGreen
view.addSubview(mylabel2)
mylabel2.heightAnchor.constraint(equalToConstant: 50).isActive = true
mylabel2.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
mylabel2.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
mylabel2.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
class ViewController3: UIViewController {
let mylabel3: UILabel = {
let label = UILabel()
label.text = "Controller 3"
label.textAlignment = .center
label.textColor = .white
label.font = .systemFont(ofSize: 20, weight: .semibold)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBlue
view.addSubview(mylabel3)
mylabel3.heightAnchor.constraint(equalToConstant: 50).isActive = true
mylabel3.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
mylabel3.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
mylabel3.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
This is the result:
The current code is perfect it you have only one viewcontroller up next.
But if you have to 2 or more viewController up next then interactive push is unuseful technique. Vies versa for the interactive pop controller we just have to pop top view form the navigation stack which make sense. Please have a look the the image below which describe the scenario for both push and pop.

Why my app is crashing after opening new controller?

This is my image with code
My app is launching and after clicking on new controller crashed. My error is
Thread 1: EXC_BAD_ACCESS (code=2, address=0x1d27fc844)
Error is in this line NSLayoutConstraint.activate(constants)
var dimmedBaclroundView : UIView {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.black.withAlphaComponent(0.3)
return view
}
lazy var CView = CustomView { [weak self] in
guard let self = self else {return}
self.dismiss(animated: true, completion: nil)
}
init() {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .overCurrentContext
modalTransitionStyle = .crossDissolve
}
required init?(coder:NSCoder) {
fatalError("init(coder :) has not been implanted")
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(dimmedBaclroundView)
view.addSubview(CView)
var constants = [
dimmedBaclroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
dimmedBaclroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
dimmedBaclroundView.topAnchor.constraint(equalTo: view.topAnchor),
dimmedBaclroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
]
constants.append(contentsOf: [
CView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor),
CView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor),
CView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 10),
CView.heightAnchor.constraint(equalTo: view.heightAnchor, constant: 0.3)
])
NSLayoutConstraint.activate(constants) //Here is my error
}
Your view should not be a computed property, you should only initialize it once when viewcontroller initialize, like this:
var dimmedBaclroundView : UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.black.withAlphaComponent(0.3)
return view
}()
Crashing happen probably because it cannot find the previous instance of dimmedBaclroundView because it got created again after every call, also you should fix the name..

How can you make this view in iOS Swift?

please click here to see which view I have to make
I have to make a map view which is similar to apple maps, and it has description view on top of the map view. The user can slide the description view left and right to see the route description in order.
I have no idea what these are called or how these are made. I really want to google but have no idea which keyword I have to use.
Please Help!
It is pagerview, you can use this library FSPagerView. Or, you can do it yourself by using scrollview or collectionview. Implement the scrollViewDidScroll to detect what is the current page and show the correct view
To make that view shown in picture, all you need to do is
take a UICollectionView and put it on your mapview. Provide UICollectionView a constraints at top, leading and trailing. Also you need yo provide height constraint of about 120-150.
in your ViewController drag and make an outlet of this UICollectionView.
Make your UIViewController follow UICollectionViewDelegate and UICollectionViewDataSource.
create a UICollectionViewCell with a xib file.
register that cell in your UIViewController.
create a datamodel which has properties that you need in order to show the direction data.
create an array in that UIViewController.
use that array as a data source of UICollectionView.
Make sense?
As others have said, UIPageViewController works well:
class ViewController: UIViewController, UIPageViewControllerDataSource {
var mapView: MKMapView!
var data: [String] = {
var data = [String]()
for _ in 0...5 {
data.append("덕원 아파트에서 출발합니다.")
}
return data
}()
override func viewDidLoad() {
super.viewDidLoad()
mapView = MKMapView()
self.view.addSubview(mapView)
mapView.translatesAutoresizingMaskIntoConstraints = false
// pageVC setup
let cardVC = CardViewController(data: data[0])
let pageVC = PageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
pageVC.setViewControllers([cardVC], direction: .forward, animated: false, completion: nil)
pageVC.dataSource = self
// container view for containment
let containerView = UIView()
view.addSubview(containerView)
containerView.backgroundColor = .black
// containment
addChild(pageVC)
containerView.addSubview(pageVC.view)
pageVC.didMove(toParent: self)
containerView.translatesAutoresizingMaskIntoConstraints = false
pageVC.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// mapView
mapView.widthAnchor.constraint(equalTo: view.widthAnchor),
mapView.heightAnchor.constraint(equalTo: view.heightAnchor),
// container view
containerView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8),
containerView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.2),
// pageVC
pageVC.view.widthAnchor.constraint(equalTo: containerView.widthAnchor),
pageVC.view.heightAnchor.constraint(equalTo: containerView.heightAnchor)
])
let pageControl = UIPageControl.appearance()
pageControl.pageIndicatorTintColor = UIColor.gray.withAlphaComponent(0.6)
pageControl.currentPageIndicatorTintColor = .white
pageControl.backgroundColor = .clear
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let info = (viewController as! CardViewController).label.text, var index = data.firstIndex(of: info) else { return nil }
index += 1
if index > data.count {
return nil
}
return CardViewController(data: data[index])
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let info = (viewController as! CardViewController).label.text, var index = data.firstIndex(of: info) else { return nil }
index -= 1
if index <= 0 {
return nil
}
return CardViewController(data: data[index])
}
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return data.count
}
func presentationIndex(for pageViewController: UIPageViewController) -> Int {
let pageVC = pageViewController.viewControllers![0] as! CardViewController
let t = pageVC.label.text!
return data.firstIndex(of: t)!
}
}
class PageViewController: UIPageViewController {
}
class CardViewController: UIViewController {
var label: UILabel!
var containerView: UIView!
var iconView: IconView!
init(data: String) {
self.label = UILabel()
self.label.text = data
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
let v = UIView()
v.backgroundColor = .black
view = v
}
override func viewDidLoad() {
super.viewDidLoad()
containerView = UIView()
view.addSubview(containerView)
// container view
containerView.addSubview(label)
containerView.translatesAutoresizingMaskIntoConstraints = false
// label
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = .black
label.textColor = .white
label.numberOfLines = 0
// icon view
iconView = IconView()
containerView.addSubview(iconView)
iconView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// containerView
containerView.heightAnchor.constraint(equalTo: view.heightAnchor),
containerView.widthAnchor.constraint(equalTo: view.widthAnchor),
// icon view
iconView.widthAnchor.constraint(equalTo: containerView.widthAnchor, multiplier: 0.4),
iconView.heightAnchor.constraint(equalTo: containerView.heightAnchor),
iconView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
// label
label.leadingAnchor.constraint(equalTo: iconView.trailingAnchor),
label.heightAnchor.constraint(equalTo: containerView.heightAnchor),
label.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -10),
])
}
}
class IconView: UIView {
override func draw(_ rect: CGRect) {
let circle = UIBezierPath(arcCenter: self.center, radius: 20, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
UIColor.orange.setFill()
circle.fill()
}
}

Reusable ViewControllers in ScrollView Pass By Reference

I am attempting to create a UIScrollView with infinitely many horizontally scrolling pages. I plan to use instances of several reusable cached ViewControllers to fill the pages. To achieve this I am trying to create a similar effect to UIPageViewController by using a beforeViewController a currentViewController and an afterViewController to fill the the three positions as the user scrolls so there is always one viewController before and after the current one the user is looking at to scroll to.
I would like to keep setting these instances equal to varying viewControllers from my cache but as I scroll back and forth eventually I am left with an empty ViewController. I believe it is caused by the passed by reference nature of the ViewController and setting one equal to the other.
Below is the code I have created is there any way to improve the functionality. Thank you in advance for your help.
import UIKit
class ViewController: UIViewController,UIScrollViewDelegate {
var previousOffset:CGFloat = 0
var viewControllers:[UIViewController] = [UIViewController](){
didSet{
print("viewControllers.count: \(viewControllers.count)")
}
}
var beforeViewController:UIViewController?
var currentViewController:UIViewController?
var nextViewController:UIViewController?
var scrollView:UIScrollView = {
let scrollView = UIScrollView()
scrollView.isPagingEnabled = true
scrollView.backgroundColor = UIColor.lightGray
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
scrollView.delegate = self
//3 Pages
scrollView.contentSize = CGSize(width: 3 * self.view.bounds.width, height: self.view.bounds.height)
self.view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0),
scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0),
scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0),
scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0)
])
currentViewController = getViewController()
addViewController(viewController: currentViewController!, index: 0) { (view) in
view.backgroundColor = UIColor.green
}
nextViewController = getViewController()
addViewController(viewController: nextViewController!, index: 1) { (view) in
view.backgroundColor = UIColor.purple
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let currentPage = scrollView.contentOffset.x/scrollView.bounds.width
print("current page: \(currentPage)")
if scrollView.contentOffset.x > previousOffset{
print("User scrolled Forward")
scrolledForwards(currentPage: Int(currentPage))
}else if scrollView.contentOffset.x < previousOffset{
print("User scrolled backwards")
scrolledBackwards(currentPage: Int(currentPage))
}
previousOffset = scrollView.contentOffset.x
}
func getViewController()->UIViewController{
let unusedViewControllers:[UIViewController] = self.viewControllers.filter({return $0.parent == nil})
if let unusedViewController = unusedViewControllers.first{
print("reusing viewController: \(viewControllers.count)")
print("reusing viewController: \(unusedViewController.description)")
return unusedViewController
}else{
let newViewController = UIViewController()
self.viewControllers.append(newViewController)
print("creating new viewController")
return newViewController
}
}
func addViewController(viewController:UIViewController,index:Int, completion: ((UIView)->Void)? = nil){
self.willMove(toParent: viewController)
self.addChild(viewController)
guard let view = viewController.view else{
removeViewController(viewController: viewController)
fatalError("view controller sent without a view")
}
self.scrollView.addSubview(view)
viewController.didMove(toParent: self)
let offset = self.view.bounds.width * CGFloat(index)
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0),
view.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: offset),
view.heightAnchor.constraint(equalTo: scrollView.heightAnchor, constant: 0),
view.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: 0)
])
if let completion = completion{
completion(view)
}
}
func removeViewController(viewController:UIViewController?, completion: ((UIView)->Void)? = nil){
viewController?.willMove(toParent: nil)
viewController?.view.removeFromSuperview()
viewController?.removeFromParent()
if let completion = completion{
completion(view)
}
}
func scrolledForwards(currentPage:Int = 0){
removeViewController(viewController: beforeViewController)
let index = currentPage + 1
self.beforeViewController = self.currentViewController
self.currentViewController = self.nextViewController
print("index: \(index)")
if index > 2{
print("There is no more forwards")
return
}
self.nextViewController = getViewController()
if nextViewController?.parent == nil{
let index = currentPage + 1
self.addViewController(viewController: nextViewController!, index: index) { (view) in
view.backgroundColor = .magenta
}
}
}
func scrolledBackwards(currentPage:Int = 0){
let index = currentPage - 1
removeViewController(viewController: nextViewController)
nextViewController = currentViewController
currentViewController = beforeViewController
print("index: \(index)")
if index < 0{
print("There is no more backwards")
return
}
beforeViewController = getViewController()
currentViewController?.view.backgroundColor = UIColor.brown
if beforeViewController?.parent == nil{
self.addViewController(viewController: beforeViewController!, index: index) { (view) in
view.backgroundColor = .cyan
}
}
}
}

Unable to Hide NavBar when Swiped

I am attempting to hide my navBar when swiped and has implemented navigationController?.hidesBarsOnSwipe = true at both viewWillAppear() and viewDidLoad() but the navBar remains unhidden. In my case, I have implemented a custom segmentedController below the navBar which toggles between two different tableViewControllers.
I am not sure if this is the reason why the navBar doesn't hide. My app looks like this, and the portion I want to hide is the 'Tickets' portion.
My code as such:
class TicketsViewController: UIViewController {
var upcomingTableViewController: UpcomingTableViewController!
var pastTransactionTableViewController: PastTransactionsTableViewController!
let segmentedControllerView: SegmentedController = {
let sc = SegmentedController()
sc.translatesAutoresizingMaskIntoConstraints = false
sc.segmentedController.addTarget(self, action: #selector(segmentedControlValueChanged), for: .valueChanged)
sc.segmentedController.selectedSegmentIndex = 0
return sc
}()
let containerView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.hidesBarsOnSwipe = true
}
override func viewDidLoad() {
super.viewDidLoad()
//These are the two tableViewControllers that are being toggled
upcomingTableViewController = UpcomingTableViewController()
pastTransactionTableViewController = PastTransactionsTableViewController()
setupNavigationBar()
setupViews()
}
#objc func segmentedControlValueChanged(_ sender: UISegmentedControl) {
let segmentedControl = sender
if segmentedControl.selectedSegmentIndex == 0 {
configureChildViewController(childController: upcomingTableViewController, onView: containerView)
} else {
configureChildViewController(childController: pastTransactionTableViewController, onView: containerView)
}
}
func setupNavigationBar() {
Helper.sharedInstance.setupNavigationBar(title: "Tickets", homeVC: self)
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.hidesBarsOnSwipe = true
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.plain, target: nil, action: nil)
}
func setupViews() {
view.addSubview(segmentedControllerView)
view.addSubview(containerView)
segmentedControllerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
segmentedControllerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
segmentedControllerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
segmentedControllerView.heightAnchor.constraint(equalToConstant: 44).isActive = true
containerView.topAnchor.constraint(equalTo: segmentedControllerView.bottomAnchor, constant: 0).isActive = true
containerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
containerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
configureChildViewController(childController: upcomingTableViewController, onView: containerView)
}
func configureChildViewController(childController: UIViewController, onView: UIView?) {
var holderView = UIView()
if let onView = onView {
holderView = onView
} else {
holderView = self.view
}
addChildViewController(childController)
holderView.addSubview(childController.view)
constraintViewEqual(to: holderView, childControllerView: childController.view)
childController.didMove(toParentViewController: self)
}
func constraintViewEqual(to containerView: UIView, childControllerView: UIView) {
childControllerView.translatesAutoresizingMaskIntoConstraints = false
childControllerView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
childControllerView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
childControllerView.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
childControllerView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
}
}
The above code is my complete code for this ticketsViewController. Appreciate some advice why is the hideBarsWhenSwipe isn't hiding my navBar. Thanks.
Try resizing the element you have below to match the view controller height.

Resources