diff --git a/Sources/Lantern/Lantern.swift b/Sources/Lantern/Lantern.swift index 6dca298..f0ead7e 100644 --- a/Sources/Lantern/Lantern.swift +++ b/Sources/Lantern/Lantern.swift @@ -8,112 +8,124 @@ import UIKit +/// 主界面vc open class Lantern: UIViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate { - + /// 通过本回调,把图片浏览器嵌套在导航控制器里 public typealias PresentEmbedClosure = (Lantern) -> UINavigationController - + /// 打开方式类型 public enum ShowMethod { case push(inNC: UINavigationController?) case present(fromVC: UIViewController?, embed: PresentEmbedClosure?) } - + /// 滑动方向类型 public enum ScrollDirection { case horizontal case vertical } - + /// 自实现转场动画 open lazy var transitionAnimator: LanternAnimatedTransitioning = LanternFadeAnimator() - + /// 滑动方向 open var scrollDirection: Lantern.ScrollDirection { set { browserView.scrollDirection = newValue } get { browserView.scrollDirection } } - + /// 项间距 open var itemSpacing: CGFloat { set { browserView.itemSpacing = newValue } get { browserView.itemSpacing } } - + /// 新增更多num之前的数据总量 open var lastNumberOfItems: Int { set { browserView.lastNumberOfItems = newValue } get { browserView.lastNumberOfItems } } - + /// 当前页码 open var pageIndex: Int { set { browserView.pageIndex = newValue } get { browserView.pageIndex } } - + /// 浏览过程中实时获取数据总量 open var numberOfItems: () -> Int { set { browserView.numberOfItems = newValue } get { browserView.numberOfItems } } - + /// 返回可复用的Cell类。用户可根据index返回不同的类。本闭包将在每次复用Cell时实时调用。 open var cellClassAtIndex: (_ index: Int) -> LanternCell.Type { set { browserView.cellClassAtIndex = newValue } get { browserView.cellClassAtIndex } } - + /// Cell刷新时用的上下文。index: 刷新的Cell对应的index;currentIndex: 当前显示的页 public typealias ReloadCellContext = (cell: LanternCell, index: Int, currentIndex: Int) - + /// 刷新Cell数据。本闭包将在Cell完成位置布局后调用。 open var reloadCellAtIndex: (ReloadCellContext) -> Void { set { browserView.reloadCellAtIndex = newValue } get { browserView.reloadCellAtIndex } } - + /// 自然滑动引起的页码改变时回调 open lazy var didChangedPageIndex: (_ index: Int) -> Void = { _ in } - + /// Cell将显示 open var cellWillAppear: (LanternCell, Int) -> Void { set { browserView.cellWillAppear = newValue } get { browserView.cellWillAppear } } - + /// Cell将不显示 open var cellWillDisappear: (LanternCell, Int) -> Void { set { browserView.cellWillDisappear = newValue } get { browserView.cellWillDisappear } } - + /// Cell已显示 open var cellDidAppear: (LanternCell, Int) -> Void { set { browserView.cellDidAppear = newValue } get { browserView.cellDidAppear } } - + /// 主视图 open lazy var browserView = LanternView() - + /// 页码指示 open var pageIndicator: LanternPageIndicator? - + /// 背景蒙版 open lazy var maskView: UIView = { let view = UIView() view.backgroundColor = .black return view }() - + + /// 导航条是否隐藏,默认为true + open var isNavigationBarHidden = true + + /// 上面的导航条和下面的toolbar是否隐藏 + open var isMenuHidden: Bool = false { + didSet { + self.navigationController?.setNavigationBarHidden(isMenuHidden, animated: true) + self.navigationController?.setToolbarHidden(isMenuHidden, animated: true) + } + } + open weak var previousNavigationControllerDelegate: UINavigationControllerDelegate? - + deinit { LanternLog.high("deinit - \(self.classForCoder)") navigationController?.delegate = previousNavigationControllerDelegate } - + /// 显示图片浏览器 open func show(method: ShowMethod = .present(fromVC: nil, embed: nil)) { switch method { @@ -124,14 +136,14 @@ open class Lantern: UIViewController, UIViewControllerTransitioningDelegate, UIN nav?.pushViewController(self, animated: true) case .present(let fromVC, let embed): let toVC = embed?(self) ?? self - toVC.modalPresentationStyle = .custom + toVC.modalPresentationStyle = .overFullScreen toVC.modalPresentationCapturesStatusBarAppearance = true toVC.transitioningDelegate = self let from = fromVC ?? Lantern.topMost from?.present(toVC, animated: true, completion: nil) } } - + /// 刷新 open func reloadData() { // 图片数量为0时,移除 @@ -142,42 +154,42 @@ open class Lantern: UIViewController, UIViewControllerTransitioningDelegate, UIN browserView.reloadData() pageIndicator?.reloadData(numberOfItems: numberOfItems(), pageIndex: pageIndex) } - + open override func viewDidLoad() { super.viewDidLoad() - + automaticallyAdjustsScrollViewInsets = false hideNavigationBar(true) - + browserView.lantern = self transitionAnimator.lantern = self - + view.backgroundColor = .clear view.addSubview(maskView) view.addSubview(browserView) - + browserView.didChangedPageIndex = { [weak self] index in guard let `self` = self else { return } self.pageIndicator?.didChanged(pageIndex: index) self.didChangedPageIndex(index) } - + view.setNeedsLayout() view.layoutIfNeeded() } - + open override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() maskView.frame = view.bounds browserView.frame = view.bounds pageIndicator?.reloadData(numberOfItems: numberOfItems(), pageIndex: pageIndex) } - + open override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) hideNavigationBar(true) } - + open override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) navigationController?.delegate = previousNavigationControllerDelegate @@ -186,41 +198,43 @@ open class Lantern: UIViewController, UIViewControllerTransitioningDelegate, UIN indicator.setup(with: self) } } - + open override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) hideNavigationBar(false) } - + open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) browserView.isRotating = true } - + // // MARK: - Navigation Bar // - + /// 在PhotoBrowser打开之前,导航栏是否隐藏 open var isPreviousNavigationBarHidden: Bool? - + private func hideNavigationBar(_ hide: Bool) { if hide { - if isPreviousNavigationBarHidden == nil { - isPreviousNavigationBarHidden = navigationController?.isNavigationBarHidden + if isNavigationBarHidden { + if isPreviousNavigationBarHidden == nil { + isPreviousNavigationBarHidden = navigationController?.isNavigationBarHidden + } + // navigationController?.setNavigationBarHidden(true, animated: false) } - navigationController?.setNavigationBarHidden(true, animated: false) } else { if let barHidden = isPreviousNavigationBarHidden { - navigationController?.setNavigationBarHidden(barHidden, animated: false) + // navigationController?.setNavigationBarHidden(barHidden, animated: false) } } } - + // // MARK: - Status Bar // - + private lazy var isPreviousStatusBarHidden: Bool = { var previousVC: UIViewController? if let vc = self.presentingViewController { @@ -232,13 +246,13 @@ open class Lantern: UIViewController, UIViewControllerTransitioningDelegate, UIN } return previousVC?.prefersStatusBarHidden ?? false }() - + private lazy var isStatusBarHidden = self.isPreviousStatusBarHidden - + open override var prefersStatusBarHidden: Bool { return isStatusBarHidden } - + open func setStatusBar(hidden: Bool) { if hidden { isStatusBarHidden = true @@ -247,32 +261,48 @@ open class Lantern: UIViewController, UIViewControllerTransitioningDelegate, UIN } setNeedsStatusBarAppearanceUpdate() } - + // // MARK: - 转场 // - + public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { transitionAnimator.isForShow = true transitionAnimator.lantern = self return transitionAnimator } - + public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { transitionAnimator.isForShow = false transitionAnimator.lantern = self return transitionAnimator } - + public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { transitionAnimator.isForShow = (operation == .push) transitionAnimator.lantern = self transitionAnimator.isNavigationAnimation = true return transitionAnimator } - + + /// 拖动图片,背景颜色变化 + open var maskAlphaChaged: (_ lantern: Lantern, _ alpha: CGFloat) -> Void = { _,_ in } + + /// 点击图片的效果 + public enum TapStyle { + case dismiss + case hideNavigationBar + } + + /// 单击图片的效果,默认为隐藏视图 + open var tapStyle = TapStyle.dismiss + + /// 即将消失的事件 + open var willDismiss: ((_ lantern: Lantern) -> Void)? + /// 关闭PhotoBrowser open func dismiss() { + willDismiss?(self) setStatusBar(hidden: false) pageIndicator?.removeFromSuperview() if presentingViewController != nil { @@ -282,7 +312,7 @@ open class Lantern: UIViewController, UIViewControllerTransitioningDelegate, UIN navigationController?.popViewController(animated: true) } } - + // // MARK: - 取顶层控制器 // @@ -291,38 +321,38 @@ open class Lantern: UIViewController, UIViewControllerTransitioningDelegate, UIN open class var topMost: UIViewController? { return topMost(of: UIApplication.shared.keyWindow?.rootViewController) } - + open class func topMost(of viewController: UIViewController?) -> UIViewController? { // presented view controller if let presentedViewController = viewController?.presentedViewController { return self.topMost(of: presentedViewController) } - + // UITabBarController if let tabBarController = viewController as? UITabBarController, - let selectedViewController = tabBarController.selectedViewController { + let selectedViewController = tabBarController.selectedViewController { return self.topMost(of: selectedViewController) } - + // UINavigationController if let navigationController = viewController as? UINavigationController, - let visibleViewController = navigationController.visibleViewController { + let visibleViewController = navigationController.visibleViewController { return self.topMost(of: visibleViewController) } - + // UIPageController if let pageViewController = viewController as? UIPageViewController, - pageViewController.viewControllers?.count == 1 { + pageViewController.viewControllers?.count == 1 { return self.topMost(of: pageViewController.viewControllers?.first) } - + // child view controller for subview in viewController?.view?.subviews ?? [] { if let childViewController = subview.next as? UIViewController { return self.topMost(of: childViewController) } } - + return viewController } } diff --git a/Sources/Lantern/LanternAnimatedTransitioning.swift b/Sources/Lantern/LanternAnimatedTransitioning.swift index f1caac0..be9f7c1 100644 --- a/Sources/Lantern/LanternAnimatedTransitioning.swift +++ b/Sources/Lantern/LanternAnimatedTransitioning.swift @@ -17,8 +17,16 @@ public protocol LanternAnimatedTransitioning: UIViewControllerAnimatedTransition private var isForShowKey = "isForShowKey" private var lanternKey = "lanternKey" +/// 对象不支持使用assign来存储,会崩溃,用object的weak变量包装一下,刚修改就遇到了这个崩溃,所以修改一下 +class LanternWeakObject: NSObject { + weak var object: AnyObject? + init(_ object: AnyObject) { + self.object = object + } +} + extension LanternAnimatedTransitioning { - + public var isForShow: Bool { get { if let value = objc_getAssociatedObject(self, &isForShowKey) as? Bool { @@ -30,21 +38,25 @@ extension LanternAnimatedTransitioning { objc_setAssociatedObject(self, &isForShowKey, newValue, .OBJC_ASSOCIATION_ASSIGN) } } - + public weak var lantern: Lantern? { get { - objc_getAssociatedObject(self, &lanternKey) as? Lantern + (objc_getAssociatedObject(self, &lanternKey) as? LanternWeakObject)?.object as? Lantern } set { - objc_setAssociatedObject(self, &lanternKey, newValue, .OBJC_ASSOCIATION_ASSIGN) + if let newValue { + objc_setAssociatedObject(self, &lanternKey, LanternWeakObject(newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } else { + objc_setAssociatedObject(self, &lanternKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } } } - + public var isNavigationAnimation: Bool { get { false } set { } } - + public func fastSnapshot(with view: UIView) -> UIView? { UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale) view.drawHierarchy(in: view.bounds, afterScreenUpdates: false) @@ -52,7 +64,7 @@ extension LanternAnimatedTransitioning { UIGraphicsEndImageContext() return UIImageView(image: image) } - + public func snapshot(with view: UIView) -> UIView? { UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale) guard let context = UIGraphicsGetCurrentContext() else { return nil } diff --git a/Sources/Lantern/LanternImageCell.swift b/Sources/Lantern/LanternImageCell.swift index 709a19f..abfff7c 100644 --- a/Sources/Lantern/LanternImageCell.swift +++ b/Sources/Lantern/LanternImageCell.swift @@ -203,7 +203,11 @@ open class LanternImageCell: UIView, UIScrollViewDelegate, UIGestureRecognizerDe /// 单击 @objc open func onSingleTap(_ tap: UITapGestureRecognizer) { - lantern?.dismiss() + if lantern?.tapStyle == .dismiss { + lantern?.dismiss() + } else { + lantern?.isMenuHidden.toggle() + } } /// 双击 @@ -247,9 +251,12 @@ open class LanternImageCell: UIView, UIScrollViewDelegate, UIGestureRecognizerDe case .changed: let result = panResult(pan) imageView.frame = result.frame - lantern?.maskView.alpha = result.scale * result.scale - lantern?.setStatusBar(hidden: result.scale > 0.99) - lantern?.pageIndicator?.isHidden = result.scale < 0.99 + let alpha = result.scale * result.scale + guard let lantern else { return } + lantern.maskView.alpha = alpha + lantern.maskAlphaChaged(lantern, alpha) + lantern.setStatusBar(hidden: result.scale > 0.99) + lantern.pageIndicator?.isHidden = result.scale < 0.99 case .ended, .cancelled: imageView.frame = panResult(pan).frame let isDown = pan.velocity(in: self).y > 0 @@ -260,6 +267,9 @@ open class LanternImageCell: UIView, UIScrollViewDelegate, UIGestureRecognizerDe lantern?.setStatusBar(hidden: true) lantern?.pageIndicator?.isHidden = false resetImageViewPosition() + if let lantern = lantern { + lantern.maskAlphaChaged(lantern, alpha) + } } default: resetImageViewPosition()