Custom nav controller

This commit is contained in:
Shadowfacts 2022-01-10 22:11:14 -05:00
parent f53f198071
commit 220fbf7b75
4 changed files with 131 additions and 13 deletions

View File

@ -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 */,

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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