Custom nav controller
This commit is contained in:
parent
f53f198071
commit
220fbf7b75
|
@ -47,6 +47,7 @@
|
|||
D6E2436E278BD8160005E546 /* ReadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E2436D278BD8160005E546 /* ReadViewController.swift */; };
|
||||
D6E24371278BE1250005E546 /* HTMLEntities in Frameworks */ = {isa = PBXBuildFile; productRef = D6E24370278BE1250005E546 /* HTMLEntities */; };
|
||||
D6E24373278BE2B80005E546 /* read.css in Resources */ = {isa = PBXBuildFile; fileRef = D6E24372278BE2B80005E546 /* read.css */; };
|
||||
D6EB531D278C89C300AD2E61 /* AppNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6EB531C278C89C300AD2E61 /* AppNavigationController.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -129,6 +130,7 @@
|
|||
D6E2436A278BB1880005E546 /* HomeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
D6E2436D278BD8160005E546 /* ReadViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadViewController.swift; sourceTree = "<group>"; };
|
||||
D6E24372278BE2B80005E546 /* read.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = read.css; sourceTree = "<group>"; };
|
||||
D6EB531C278C89C300AD2E61 /* AppNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppNavigationController.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -169,6 +171,7 @@
|
|||
D65B18AF2750468B004A9448 /* Screens */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D6EB531C278C89C300AD2E61 /* AppNavigationController.swift */,
|
||||
D65B18BF2750533E004A9448 /* Home */,
|
||||
D65B18B027504691004A9448 /* Login */,
|
||||
D6E2434A278B455C0005E546 /* Items */,
|
||||
|
@ -492,6 +495,7 @@
|
|||
D6E2435F278B97240005E546 /* Group+CoreDataClass.swift in Sources */,
|
||||
D6E24369278BABB40005E546 /* UIColor+App.swift in Sources */,
|
||||
D6E2435D278B97240005E546 /* Item+CoreDataClass.swift in Sources */,
|
||||
D6EB531D278C89C300AD2E61 /* AppNavigationController.swift in Sources */,
|
||||
D6E24360278B97240005E546 /* Group+CoreDataProperties.swift in Sources */,
|
||||
D6E2434C278B456A0005E546 /* ItemsViewController.swift in Sources */,
|
||||
D6E2435E278B97240005E546 /* Item+CoreDataProperties.swift in Sources */,
|
||||
|
|
|
@ -67,7 +67,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
|
||||
private func createAppUI() {
|
||||
let home = HomeViewController(fervorController: fervorController)
|
||||
let nav = UINavigationController(rootViewController: home)
|
||||
let nav = AppNavigationController(rootViewController: home)
|
||||
nav.navigationBar.prefersLargeTitles = true
|
||||
window!.rootViewController = nav
|
||||
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
//
|
||||
// AppNavigationController.swift
|
||||
// Reader
|
||||
//
|
||||
// Created by Shadowfacts on 1/10/22.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AppNavigationController: UINavigationController, UINavigationControllerDelegate {
|
||||
|
||||
private var statusBarBlockingView: UIView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
let appearance = UINavigationBarAppearance()
|
||||
appearance.configureWithOpaqueBackground()
|
||||
navigationBar.scrollEdgeAppearance = appearance
|
||||
|
||||
interactivePopGestureRecognizer?.isEnabled = false
|
||||
let recognizer = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized))
|
||||
recognizer.allowedScrollTypesMask = .continuous
|
||||
view.addGestureRecognizer(recognizer)
|
||||
|
||||
isNavigationBarHidden = true
|
||||
|
||||
statusBarBlockingView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
|
||||
statusBarBlockingView.translatesAutoresizingMaskIntoConstraints = false
|
||||
statusBarBlockingView.layer.zPosition = 101
|
||||
view.addSubview(statusBarBlockingView)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
statusBarBlockingView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
statusBarBlockingView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
statusBarBlockingView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
statusBarBlockingView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
|
||||
])
|
||||
|
||||
delegate = self
|
||||
}
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
|
||||
statusBarBlockingView.isHidden = viewController.prefersStatusBarHidden
|
||||
}
|
||||
|
||||
private var poppingViewController: UIViewController?
|
||||
private var prevNavBarHidden = false
|
||||
private var dimmingView: UIView = {
|
||||
let v = UIView()
|
||||
v.backgroundColor = .black
|
||||
return v
|
||||
}()
|
||||
|
||||
@objc private func panGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
|
||||
let translation = recognizer.translation(in: view)
|
||||
let translationProgress = max(0, translation.x) / view.bounds.width
|
||||
|
||||
switch recognizer.state {
|
||||
case .began:
|
||||
guard viewControllers.count > 1 else {
|
||||
break
|
||||
}
|
||||
prevNavBarHidden = isNavigationBarHidden
|
||||
poppingViewController = popViewController(animated: false)
|
||||
view.addSubview(poppingViewController!.view)
|
||||
poppingViewController!.view.transform = CGAffineTransform(translationX: max(0, translation.x), y: 0)
|
||||
poppingViewController!.view.layer.zPosition = 100
|
||||
dimmingView.frame = view.bounds
|
||||
dimmingView.layer.opacity = Float(1 - translationProgress) * 0.075
|
||||
dimmingView.layer.zPosition = 99
|
||||
view.addSubview(dimmingView)
|
||||
// changing the transform directly on topViewController.view doesn't work for some reason, have to go 2 superviews up
|
||||
topViewController!.view.superview?.superview?.transform = CGAffineTransform(translationX: (1 - translationProgress) * -0.3 * view.bounds.width, y: 0)
|
||||
|
||||
case .changed:
|
||||
guard let poppingViewController = poppingViewController else {
|
||||
break
|
||||
}
|
||||
|
||||
poppingViewController.view.transform = CGAffineTransform(translationX: max(0, translation.x), y: 0)
|
||||
dimmingView.layer.opacity = Float(1 - max(0, translation.x) / view.bounds.width) * 0.075
|
||||
topViewController!.view.superview?.superview?.transform = CGAffineTransform(translationX: (1 - translationProgress) * -0.3 * view.bounds.width, y: 0)
|
||||
|
||||
case .ended:
|
||||
guard let poppingViewController = poppingViewController else {
|
||||
break
|
||||
}
|
||||
|
||||
let velocity = recognizer.velocity(in: view)
|
||||
let shouldComplete = translation.x >= view.bounds.width / 2 || velocity.x >= 500
|
||||
|
||||
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) {
|
||||
if shouldComplete {
|
||||
poppingViewController.view.transform = CGAffineTransform(translationX: self.view.bounds.width, y: 0)
|
||||
self.topViewController!.view.superview?.superview?.transform = .identity
|
||||
} else {
|
||||
poppingViewController.view.transform = .identity
|
||||
self.topViewController!.view.superview?.superview?.transform = CGAffineTransform(translationX: -0.3 * self.view.bounds.width, y: 0)
|
||||
}
|
||||
self.dimmingView.layer.opacity = 0
|
||||
} completion: { _ in
|
||||
self.topViewController!.view.superview?.superview?.transform = .identity
|
||||
|
||||
if shouldComplete {
|
||||
poppingViewController.beginAppearanceTransition(false, animated: true)
|
||||
poppingViewController.willMove(toParent: nil)
|
||||
poppingViewController.removeFromParent()
|
||||
poppingViewController.view.removeFromSuperview()
|
||||
poppingViewController.endAppearanceTransition()
|
||||
} else {
|
||||
self.pushViewController(poppingViewController, animated: false)
|
||||
self.isNavigationBarHidden = self.prevNavBarHidden
|
||||
}
|
||||
|
||||
poppingViewController.view.layer.zPosition = 0
|
||||
self.poppingViewController = nil
|
||||
self.dimmingView.removeFromSuperview()
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -66,18 +66,6 @@ class ReadViewController: UIViewController {
|
|||
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
navigationController?.hidesBarsOnSwipe = true
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
navigationController?.hidesBarsOnSwipe = false
|
||||
}
|
||||
|
||||
private func itemContentHTML() -> String? {
|
||||
guard let content = item.content else {
|
||||
return nil
|
||||
|
|
Loading…
Reference in New Issue