diff --git a/PHDemo/PHDemo.xcodeproj/project.pbxproj b/PHDemo/PHDemo.xcodeproj/project.pbxproj index ce3fa74..e3cb902 100644 --- a/PHDemo/PHDemo.xcodeproj/project.pbxproj +++ b/PHDemo/PHDemo.xcodeproj/project.pbxproj @@ -83,8 +83,8 @@ CDA83DB828C601E60025F0DF /* TableHeaderView.swift */, CD9C7B1D28CB8972006190CD /* Extensions.swift */, CD6537C028C35E1C00A5981B /* ListVC.swift */, - CDB7A1CF28C32A7400E034D8 /* AlertVC.swift */, CD6537C228C35E6200A5981B /* ToastVC.swift */, + CDB7A1CF28C32A7400E034D8 /* AlertVC.swift */, CD6537C428C35F2C00A5981B /* SheetVC.swift */, CD8EEF4028BC5C7200E660EA /* Main.storyboard */, CD8EEF4328BC5C7300E660EA /* Assets.xcassets */, diff --git a/PHDemo/PHDemo/Base.lproj/Main.storyboard b/PHDemo/PHDemo/Base.lproj/Main.storyboard index 0dea159..a90e296 100644 --- a/PHDemo/PHDemo/Base.lproj/Main.storyboard +++ b/PHDemo/PHDemo/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -18,10 +18,10 @@ - + - + @@ -36,7 +36,7 @@ - + @@ -50,9 +50,9 @@ - - - + + + @@ -69,10 +69,10 @@ - + - + @@ -87,7 +87,7 @@ - + @@ -99,10 +99,10 @@ - + - + @@ -122,10 +122,10 @@ - - + + - + diff --git a/PHDemo/PHDemo/SheetVC.swift b/PHDemo/PHDemo/SheetVC.swift index 18532f2..b6fd71a 100644 --- a/PHDemo/PHDemo/SheetVC.swift +++ b/PHDemo/PHDemo/SheetVC.swift @@ -86,6 +86,25 @@ class SheetVC: ListVC { } list.add(title: "自定义样式") { section in + section.add(title: "堆叠样式") { + Sheet { sheet in + sheet.config.stackDepthEffect = true + sheet.config.windowEdgeInset = 0 + sheet.add(title: "ProHUD") + sheet.add(subTitle: "堆叠样式") + sheet.add(message: "这个效果目前有个小BUG,切后台之后显示会有点问题,如果有解决方案请麻烦去社区反馈一下,谢谢~") + sheet.add(spacing: 24) + sheet.add(action: "去反馈", style: .destructive) { sheet in + guard let url = URL(string: "https://github.com/xaoxuu/ProHUD") else { + return + } + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + } + } + sheet.add(action: "取消", style: .gray) + } + } section.add(title: "圆角半径 & 屏幕边距") { Sheet { sheet in sheet.add(title: "圆角半径 & 屏幕边距") @@ -111,13 +130,13 @@ class SheetVC: ListVC { let s2 = UISlider() s2.minimumValue = 0 s2.maximumValue = 40 - s2.value = Float(sheet.config.screenEdgeInset) + s2.value = Float(sheet.config.windowEdgeInset) sheet.add(subview: s2).snp.makeConstraints { make in make.height.equalTo(50) } if #available(iOS 14.0, *) { s2.addAction(.init(handler: { [unowned s2] act in - sheet.config.screenEdgeInset = CGFloat(s2.value) + sheet.config.windowEdgeInset = CGFloat(s2.value) sheet.reloadData() }), for: .valueChanged) } else { diff --git a/PHDemo/PHDemo/ToastVC.swift b/PHDemo/PHDemo/ToastVC.swift index 2f8b9be..7db3a56 100644 --- a/PHDemo/PHDemo/ToastVC.swift +++ b/PHDemo/PHDemo/ToastVC.swift @@ -30,7 +30,7 @@ func updateProgress(in duration: TimeInterval, callback: @escaping (_ percent: C } } -let isTesting: Bool = false +let isTesting: Bool = true class TestToast: Toast { override func push() { @@ -173,7 +173,7 @@ class ToastVC: ListVC { var i = 0 section.add(title: "多实例共存") { Toast(.loading.title("多实例共存").message("直接创建的实例,以平铺方式排列").duration(2)) { toast in - toast.config.cardEdgeInsets = .init(top: 32, left: 20, bottom: 32, right: 20) + } } section.add(title: "不存在就创建,存在就更新") { @@ -209,7 +209,17 @@ class ToastVC: ListVC { } } } - + section.add(title: "修改内边距") { + Toast(.message("这条toast的内边距经过自定义设置,与其它的有所不同。")) { toast in + toast.config.cardEdgeInsets = .init(top: 40, left: 32, bottom: 40, right: 32) + } + } + section.add(title: "修改左右外边距") { + Toast(.message("这条toast的左右外边距经过自定义设置,与其它的有所不同。")) { toast in + toast.config.windowEdgeInset = 8 + toast.config.cardCornerRadius = 24 + } + } section.add(title: "圆角半径") { func foo() { Toast { toast in diff --git a/Sources/ProHUD/Alert/AlertDefaultLayout.swift b/Sources/ProHUD/Alert/AlertDefaultLayout.swift index f8286d8..da698bd 100644 --- a/Sources/ProHUD/Alert/AlertDefaultLayout.swift +++ b/Sources/ProHUD/Alert/AlertDefaultLayout.swift @@ -93,11 +93,12 @@ extension Alert: DefaultLayout { } if contentStack.superview == nil { contentView.addSubview(contentStack) + let cardEdgeInsets = config.cardEdgeInsetsByDefault contentStack.snp.remakeConstraints { make in - make.top.equalToSuperview().inset(config.cardEdgeInsets.top) - make.left.equalToSuperview().inset(config.cardEdgeInsets.left) - make.bottom.equalToSuperview().inset(config.cardEdgeInsets.bottom) - make.right.equalToSuperview().inset(config.cardEdgeInsets.right) + make.top.equalToSuperview().inset(cardEdgeInsets.top) + make.left.equalToSuperview().inset(cardEdgeInsets.left) + make.bottom.equalToSuperview().inset(cardEdgeInsets.bottom) + make.right.equalToSuperview().inset(cardEdgeInsets.right) } } // card background @@ -149,9 +150,10 @@ extension Alert { } if imageView.superview == nil { contentStack.insertArrangedSubview(imageView, at: 0) + let cardEdgeInsets = config.cardEdgeInsetsByDefault imageView.snp.remakeConstraints { (mk) in - mk.top.left.greaterThanOrEqualTo(contentView).inset(config.cardEdgeInsets.top * 2) - mk.right.bottom.lessThanOrEqualTo(contentView).inset(config.cardEdgeInsets.right * 2) + mk.top.left.greaterThanOrEqualTo(contentView).inset(cardEdgeInsets.top * 2) + mk.right.bottom.lessThanOrEqualTo(contentView).inset(cardEdgeInsets.right * 2) mk.width.equalTo(config.iconSize.width) mk.height.equalTo(config.iconSize.height) } @@ -177,11 +179,12 @@ extension Alert { } else { contentStack.insertArrangedSubview(textStack, at: 0) } + let cardEdgeInsets = config.cardEdgeInsetsByDefault textStack.snp.remakeConstraints { (mk) in mk.left.greaterThanOrEqualToSuperview().inset(config.textEdgeInsets.left) mk.right.lessThanOrEqualToSuperview().inset(config.textEdgeInsets.right) - mk.top.greaterThanOrEqualTo(contentView).inset(config.cardEdgeInsets.top + config.textEdgeInsets.top) - mk.bottom.lessThanOrEqualTo(contentView).inset(config.cardEdgeInsets.bottom + config.textEdgeInsets.bottom) + mk.top.greaterThanOrEqualTo(contentView).inset(cardEdgeInsets.top + config.textEdgeInsets.top) + mk.bottom.lessThanOrEqualTo(contentView).inset(cardEdgeInsets.bottom + config.textEdgeInsets.bottom) } } if titleCount > 0 { diff --git a/Sources/ProHUD/Alert/AlertManager.swift b/Sources/ProHUD/Alert/AlertManager.swift index 424109f..537578b 100644 --- a/Sources/ProHUD/Alert/AlertManager.swift +++ b/Sources/ProHUD/Alert/AlertManager.swift @@ -53,13 +53,12 @@ extension Alert: HUD { // hide window let count = window.alerts.count if count == 0 { + self.window = nil UIView.animateEaseOut(duration: duration) { window.backgroundView.alpha = 0 } completion: { done in - // 此时不能用self.window,因为alert已经释放掉了 - if window.alerts.count == 0, let scene = window.windowScene { - AppContext.alertWindow[scene] = nil - } + // 这里设置一下window属性,会使window的生命周期被延长到此处,即动画执行过程中window不会被提前释放 + window.isHidden = true } } } diff --git a/Sources/ProHUD/Core/Controllers/Controller.swift b/Sources/ProHUD/Core/Controllers/Controller.swift index e9dcf81..ac8a830 100644 --- a/Sources/ProHUD/Core/Controllers/Controller.swift +++ b/Sources/ProHUD/Core/Controllers/Controller.swift @@ -36,7 +36,7 @@ open class Controller: UIViewController { } deinit { - consolePrint("👌", self, "init") + consolePrint("👌", self, "deinit") } override public func viewDidLoad() { diff --git a/Sources/ProHUD/Core/Models/Configuration.swift b/Sources/ProHUD/Core/Models/Configuration.swift index ce76105..0c60913 100644 --- a/Sources/ProHUD/Core/Models/Configuration.swift +++ b/Sources/ProHUD/Core/Models/Configuration.swift @@ -66,9 +66,10 @@ public class Configuration: NSObject { public var cardMinHeight = CGFloat(32) /// 卡片内边距 - public var cardEdgeInsets: UIEdgeInsets = { - .init(top: 16, left: 16, bottom: 16, right: 16) - }() + public var cardEdgeInsets: UIEdgeInsets? + var cardEdgeInsetsByDefault: UIEdgeInsets { + cardEdgeInsets ?? .init(top: 16, left: 16, bottom: 16, right: 16) + } /// 文字区域内边距 public var textEdgeInsets: UIEdgeInsets = { diff --git a/Sources/ProHUD/Core/Utils/Utils.swift b/Sources/ProHUD/Core/Utils/Utils.swift index 2abc835..3b4d96e 100644 --- a/Sources/ProHUD/Core/Utils/Utils.swift +++ b/Sources/ProHUD/Core/Utils/Utils.swift @@ -15,7 +15,7 @@ extension UIImage { /// 是否是竖屏(紧凑布局)模式 -internal var isPortrait: Bool { +var isPortrait: Bool { if AppContext.appBounds.width < 450 { return true } @@ -26,3 +26,7 @@ internal var isPortrait: Bool { } return false } + +var isPhonePortrait: Bool { + UIDevice.current.userInterfaceIdiom == .phone && (AppContext.windowScene?.interfaceOrientation.isPortrait == true) +} diff --git a/Sources/ProHUD/Sheet/SheetConfiguration.swift b/Sources/ProHUD/Sheet/SheetConfiguration.swift index 48a2ea1..17067dc 100644 --- a/Sources/ProHUD/Sheet/SheetConfiguration.swift +++ b/Sources/ProHUD/Sheet/SheetConfiguration.swift @@ -11,8 +11,11 @@ public extension Sheet { class Configuration: ProHUD.Configuration { + /// 堆叠效果 + public var stackDepthEffect: Bool = false + /// 卡片距离屏幕的间距 - public var screenEdgeInset: CGFloat = 4 + public var windowEdgeInset: CGFloat = 16 /// 是否是全屏的页面 public var isFullScreen = false @@ -41,6 +44,10 @@ public extension Sheet { customBackgroundViewMask = callback } + override var cardEdgeInsetsByDefault: UIEdgeInsets { + cardEdgeInsets ?? .init(top: 24, left: 24, bottom: 24, right: 24) + } + override var cardMaxWidthByDefault: CGFloat { cardMaxWidth ?? 500 } override var cardMaxHeightByDefault: CGFloat { cardMaxHeight ?? (AppContext.appBounds.height - 50) } @@ -53,7 +60,7 @@ public extension Sheet { animateDurationForBuildOut ?? 0.5 } - override var cardCornerRadiusByDefault: CGFloat { cardCornerRadius ?? 40 } + override var cardCornerRadiusByDefault: CGFloat { cardCornerRadius ?? 32 } } diff --git a/Sources/ProHUD/Sheet/SheetDefaultLayout.swift b/Sources/ProHUD/Sheet/SheetDefaultLayout.swift index 01e1ce2..8885dce 100644 --- a/Sources/ProHUD/Sheet/SheetDefaultLayout.swift +++ b/Sources/ProHUD/Sheet/SheetDefaultLayout.swift @@ -44,7 +44,7 @@ extension Sheet: DefaultLayout { loadContentMaskViewIfNeeded() // layout let maxWidth = config.cardMaxWidthByDefault - var width = AppContext.appBounds.width - config.screenEdgeInset * 2 + var width = AppContext.appBounds.width - config.windowEdgeInset * 2 if width > maxWidth { // landscape iPhone or iPad width = maxWidth @@ -59,7 +59,7 @@ extension Sheet: DefaultLayout { make.centerY.equalToSuperview() } else { if isPortrait { - make.bottom.equalToSuperview().inset(config.screenEdgeInset) + make.bottom.equalToSuperview().inset(config.windowEdgeInset) } else { make.bottom.equalToSuperview().inset(AppContext.safeAreaInsets.bottom) } @@ -78,21 +78,30 @@ extension Sheet: DefaultLayout { // stack if contentStack.superview == nil { contentView.addSubview(contentStack) + let isFullScreen = config.isFullScreen + let cardEdgeInsets = config.cardEdgeInsetsByDefault contentStack.snp.remakeConstraints { make in - let safeArea: UIEdgeInsets - if config.isFullScreen { - safeArea = AppContext.safeAreaInsets - } else { - safeArea = .zero + var safeAreaInsets = cardEdgeInsets + if isFullScreen { + safeAreaInsets.top += AppContext.safeAreaInsets.top + safeAreaInsets.bottom += AppContext.safeAreaInsets.bottom } - make.top.equalToSuperview().offset(safeArea.top + config.cardEdgeInsets.top) - make.bottom.equalToSuperview().inset(safeArea.bottom + config.cardEdgeInsets.bottom) + make.top.equalToSuperview().inset(safeAreaInsets.top) + make.bottom.equalToSuperview().inset(safeAreaInsets.bottom) if isPortrait { - make.left.equalToSuperview().inset(safeArea.left + config.cardEdgeInsets.left) - make.right.equalToSuperview().inset(safeArea.right + config.cardEdgeInsets.right) + if isFullScreen { + safeAreaInsets.left += AppContext.safeAreaInsets.left + safeAreaInsets.right += AppContext.safeAreaInsets.right + } + make.left.equalToSuperview().inset(safeAreaInsets.left) + make.right.equalToSuperview().inset(safeAreaInsets.right) } else { - make.left.equalToSuperview().inset(safeArea.left + config.cardEdgeInsets.left * 2) - make.right.equalToSuperview().inset(safeArea.right + config.cardEdgeInsets.right * 2) + if isFullScreen { + safeAreaInsets.left += safeAreaInsets.left + AppContext.safeAreaInsets.left + safeAreaInsets.right += safeAreaInsets.right + AppContext.safeAreaInsets.right + } + make.left.equalToSuperview().inset(safeAreaInsets.left) + make.right.equalToSuperview().inset(safeAreaInsets.right) } } } diff --git a/Sources/ProHUD/Sheet/SheetManager.swift b/Sources/ProHUD/Sheet/SheetManager.swift index fda51a5..6c94061 100644 --- a/Sources/ProHUD/Sheet/SheetManager.swift +++ b/Sources/ProHUD/Sheet/SheetManager.swift @@ -67,6 +67,15 @@ extension Sheet { func translateIn(completion: (() -> Void)?) { UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) { self._translateIn() + if self.config.stackDepthEffect { + if isPhonePortrait { + AppContext.appWindow?.transform = .init(translationX: 0, y: 8).scaledBy(x: 0.9, y: 0.9) + } else { + AppContext.appWindow?.transform = .init(scaleX: 0.92, y: 0.92) + } + AppContext.appWindow?.layer.cornerRadiusWithContinuous = 16 + AppContext.appWindow?.layer.masksToBounds = true + } } completion: { done in completion?() } @@ -75,6 +84,10 @@ extension Sheet { func translateOut(completion: (() -> Void)?) { UIView.animateEaseOut(duration: config.animateDurationForBuildOutByDefault) { self._translateOut() + if self.config.stackDepthEffect { + AppContext.appWindow?.transform = .identity + AppContext.appWindow?.layer.cornerRadius = 0 + } } completion: { done in completion?() } @@ -87,7 +100,7 @@ extension Sheet { func _translateOut() { backgroundView.alpha = 0 - contentView.transform = .init(translationX: 0, y: view.frame.size.height - contentView.frame.minY + config.screenEdgeInset) + contentView.transform = .init(translationX: 0, y: view.frame.size.height - contentView.frame.minY + config.windowEdgeInset) } } diff --git a/Sources/ProHUD/Toast/ToastConfiguration.swift b/Sources/ProHUD/Toast/ToastConfiguration.swift index eeb54b5..5c25585 100644 --- a/Sources/ProHUD/Toast/ToastConfiguration.swift +++ b/Sources/ProHUD/Toast/ToastConfiguration.swift @@ -29,6 +29,12 @@ public extension Toast { customShared = callback } + /// 距离窗口左右的间距 + public var windowEdgeInset: CGFloat? + var windowEdgeInsetByDefault: CGFloat { + windowEdgeInset ?? 16 + } + override var cardMaxWidthByDefault: CGFloat { cardMaxWidth ?? 500 } diff --git a/Sources/ProHUD/Toast/ToastDefaultLayout.swift b/Sources/ProHUD/Toast/ToastDefaultLayout.swift index af5abf9..d1696fe 100644 --- a/Sources/ProHUD/Toast/ToastDefaultLayout.swift +++ b/Sources/ProHUD/Toast/ToastDefaultLayout.swift @@ -95,11 +95,12 @@ extension Toast: DefaultLayout { // stacks if contentStack.superview != contentView { contentView.addSubview(contentStack) + let cardEdgeInsets = config.cardEdgeInsetsByDefault contentStack.snp.remakeConstraints { make in - make.top.equalToSuperview().inset(config.cardEdgeInsets.top) - make.left.equalToSuperview().inset(config.cardEdgeInsets.left) - make.bottom.equalToSuperview().inset(config.cardEdgeInsets.bottom) - make.right.equalToSuperview().inset(config.cardEdgeInsets.right) + make.top.equalToSuperview().inset(cardEdgeInsets.top) + make.left.equalToSuperview().inset(cardEdgeInsets.left) + make.bottom.equalToSuperview().inset(cardEdgeInsets.bottom) + make.right.equalToSuperview().inset(cardEdgeInsets.right) } } contentStack.insertArrangedSubview(infoStack, at: 0) diff --git a/Sources/ProHUD/Toast/ToastWindow.swift b/Sources/ProHUD/Toast/ToastWindow.swift index bf5a163..eca1042 100644 --- a/Sources/ProHUD/Toast/ToastWindow.swift +++ b/Sources/ProHUD/Toast/ToastWindow.swift @@ -63,7 +63,8 @@ class ToastWindow: Window { let config = toast.config // frame - let width = CGFloat.minimum(AppContext.appBounds.width - config.cardEdgeInsets.left - config.cardEdgeInsets.right, config.cardMaxWidthByDefault) + let cardEdgeInsets = config.cardEdgeInsetsByDefault + let width = CGFloat.minimum(AppContext.appBounds.width - config.windowEdgeInsetByDefault - config.windowEdgeInsetByDefault, config.cardMaxWidthByDefault) toast.view.frame.size = CGSize(width: width, height: config.cardMaxHeightByDefault) toast.titleLabel.sizeToFit() toast.bodyLabel.sizeToFit() @@ -113,6 +114,8 @@ class ToastWindow: Window { toast.view.removeFromSuperview() toast.removeFromParent() toast.navEvents[.onViewDidDisappear]?(toast) + // 这里设置一下window属性,会使window的生命周期被延长到此处,即动画执行过程中window不会被提前释放 + window.isHidden = true } } @@ -128,7 +131,8 @@ fileprivate extension ToastWindow { let config = window.toast.config var y = window.frame.origin.y if i == 0 { - y = max(AppContext.appWindow?.safeAreaInsets.top ?? config.margin, config.margin) + let topLayoutMargins = AppContext.appWindow?.layoutMargins.top ?? config.margin + y = max(topLayoutMargins - config.margin, config.margin) } else { if i - 1 < windows.count && i > 0 { y = config.margin + windows[i-1].frame.maxY @@ -147,6 +151,7 @@ fileprivate extension ToastWindow { updateToastsLayoutWorkItem?.cancel() updateToastsLayoutWorkItem = DispatchWorkItem { setToastWindowsLayout(windows: windows) + updateToastsLayoutWorkItem = nil } DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: updateToastsLayoutWorkItem!) } @@ -175,7 +180,8 @@ fileprivate extension Toast { height = CGFloat.maximum(v.frame.maxY, height) } // 上下边间距 - height += config.cardEdgeInsets.top + config.cardEdgeInsets.bottom + let cardEdgeInsets = config.cardEdgeInsetsByDefault + height += cardEdgeInsets.top + cardEdgeInsets.bottom return height } }