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 */; };
|
D6E2436E278BD8160005E546 /* ReadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E2436D278BD8160005E546 /* ReadViewController.swift */; };
|
||||||
D6E24371278BE1250005E546 /* HTMLEntities in Frameworks */ = {isa = PBXBuildFile; productRef = D6E24370278BE1250005E546 /* HTMLEntities */; };
|
D6E24371278BE1250005E546 /* HTMLEntities in Frameworks */ = {isa = PBXBuildFile; productRef = D6E24370278BE1250005E546 /* HTMLEntities */; };
|
||||||
D6E24373278BE2B80005E546 /* read.css in Resources */ = {isa = PBXBuildFile; fileRef = D6E24372278BE2B80005E546 /* read.css */; };
|
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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
@ -129,6 +130,7 @@
|
||||||
D6E2436A278BB1880005E546 /* HomeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCollectionViewCell.swift; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -169,6 +171,7 @@
|
||||||
D65B18AF2750468B004A9448 /* Screens */ = {
|
D65B18AF2750468B004A9448 /* Screens */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D6EB531C278C89C300AD2E61 /* AppNavigationController.swift */,
|
||||||
D65B18BF2750533E004A9448 /* Home */,
|
D65B18BF2750533E004A9448 /* Home */,
|
||||||
D65B18B027504691004A9448 /* Login */,
|
D65B18B027504691004A9448 /* Login */,
|
||||||
D6E2434A278B455C0005E546 /* Items */,
|
D6E2434A278B455C0005E546 /* Items */,
|
||||||
|
@ -492,6 +495,7 @@
|
||||||
D6E2435F278B97240005E546 /* Group+CoreDataClass.swift in Sources */,
|
D6E2435F278B97240005E546 /* Group+CoreDataClass.swift in Sources */,
|
||||||
D6E24369278BABB40005E546 /* UIColor+App.swift in Sources */,
|
D6E24369278BABB40005E546 /* UIColor+App.swift in Sources */,
|
||||||
D6E2435D278B97240005E546 /* Item+CoreDataClass.swift in Sources */,
|
D6E2435D278B97240005E546 /* Item+CoreDataClass.swift in Sources */,
|
||||||
|
D6EB531D278C89C300AD2E61 /* AppNavigationController.swift in Sources */,
|
||||||
D6E24360278B97240005E546 /* Group+CoreDataProperties.swift in Sources */,
|
D6E24360278B97240005E546 /* Group+CoreDataProperties.swift in Sources */,
|
||||||
D6E2434C278B456A0005E546 /* ItemsViewController.swift in Sources */,
|
D6E2434C278B456A0005E546 /* ItemsViewController.swift in Sources */,
|
||||||
D6E2435E278B97240005E546 /* Item+CoreDataProperties.swift in Sources */,
|
D6E2435E278B97240005E546 /* Item+CoreDataProperties.swift in Sources */,
|
||||||
|
|
|
@ -67,7 +67,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
|
|
||||||
private func createAppUI() {
|
private func createAppUI() {
|
||||||
let home = HomeViewController(fervorController: fervorController)
|
let home = HomeViewController(fervorController: fervorController)
|
||||||
let nav = UINavigationController(rootViewController: home)
|
let nav = AppNavigationController(rootViewController: home)
|
||||||
nav.navigationBar.prefersLargeTitles = true
|
nav.navigationBar.prefersLargeTitles = true
|
||||||
window!.rootViewController = nav
|
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? {
|
private func itemContentHTML() -> String? {
|
||||||
guard let content = item.content else {
|
guard let content = item.content else {
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in New Issue