Home > front end >  Interactive push view controller
Interactive push view controller

Time:10-07

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: enter image description here

CodePudding user response:

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:

enter image description here

  • Related