代码优化

This commit is contained in:
xaoxuu 2023-08-21 16:56:51 +08:00
parent a37cb52b79
commit f68b0c3a9b
24 changed files with 281 additions and 112 deletions

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CD8EEF3628BC5C7200E660EA"
BuildableName = "PHDemo.app"
BlueprintName = "PHDemo"
ReferencedContainer = "container:PHDemo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CD8EEF3628BC5C7200E660EA"
BuildableName = "PHDemo.app"
BlueprintName = "PHDemo"
ReferencedContainer = "container:PHDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CD8EEF3628BC5C7200E660EA"
BuildableName = "PHDemo.app"
BlueprintName = "PHDemo"
ReferencedContainer = "container:PHDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -84,15 +84,15 @@ class DemoCapsuleVC: ListVC {
}
}
list.add(title: "不同位置、不同动画") { section in
section.add(title: "顶部,默认滑入") {
Capsule(.info("一条简短的消息"))
list.add(title: "不同位置、不同动画,队列推送") { section in
section.add(title: "顶部,默认动画") {
Capsule(.info("一条简短的消息").queuedPush(true).duration(1))
}
section.add(title: "中间,默认缩放") {
Capsule(.middle.info("一条简短的消息"))
section.add(title: "中间,默认动画") {
Capsule(.middle.queuedPush(true).info("一条简短的消息").duration(2))
}
section.add(title: "中间,黑底白字,透明渐变") {
Capsule(.middle.info("一条简短的消息")) { capsule in
Capsule(.middle.queuedPush(true).info("一条简短的消息").duration(1)) { capsule in
capsule.config.tintColor = .white
capsule.config.cardCornerRadius = 8
capsule.config.contentViewMask { mask in
@ -119,7 +119,7 @@ class DemoCapsuleVC: ListVC {
}
}
section.add(title: "底部,渐变背景,默认回弹滑入") {
Capsule(.bottom.enter("点击进入")) { capsule in
Capsule(.bottom.queuedPush(true).enter("点击进入").duration(1)) { capsule in
capsule.config.tintColor = .white
capsule.config.cardEdgeInsets = .init(top: 12, left: 20, bottom: 12, right: 20)
capsule.config.customTextLabel { label in
@ -146,6 +146,25 @@ class DemoCapsuleVC: ListVC {
}
}
}
list.add(title: "lazy push") { section in
section.add(title: "id:1, text:1") {
Capsule(.test1("111:111"))
}
section.add(title: "id:1, text:2") {
Capsule(.test1("111:222"))
}
section.add(title: "id:2, text:1") {
Capsule(.test2("222:111"))
}
section.add(title: "id:2, text:2") {
Capsule(.test2("222:222"))
}
section.add(title: "id:2, text:2") {
Capsule(.test2("222:222"))
Capsule(.test2("222:111"))
}
}
}
}
@ -179,4 +198,22 @@ extension CapsuleViewModel {
.message(text)
}
static func test1(_ text: String) -> CapsuleViewModel {
.identifier("id:1")
.icon(.init(systemName: "video.circle.fill"))
.tintColor(.systemGreen)
.duration(1)
.queuedPush(true)
.message(text)
}
static func test2(_ text: String) -> CapsuleViewModel {
.identifier("id:2")
.icon(.init(systemName: "mic.circle.fill"))
.tintColor(.systemOrange)
.duration(1)
.queuedPush(true)
.message(text)
}
}

View File

@ -106,7 +106,7 @@ class DemoToastVC: ListVC {
}
}
section.add(title: "图标 + 一段长文本") {
Toast(.note.message(message))
Toast(.note.message(message).duration(1))
}
section.add(title: "网络图标 + 一段文本") {
Toast(.message("这是网络图标").icon(.init(string: "https://xaoxuu.com/assets/xaoxuu/avatar/rect-256@2x.png")))
@ -167,7 +167,7 @@ class DemoToastVC: ListVC {
section.add(title: "禁止手势移除") {
let title = "这条消息很重要"
let message = "向上滑动将不会移除消息,您必须手动处理,用于重要但非阻塞性的事件。(通过代码处理或者在点击事件处理)"
Toast(.warning.title(title).message(message)) { toast in
Toast(.warning.title(title).message(message).duration(.infinity)) { toast in
toast.isRemovable = false
toast.onTapped { toast in
toast.pop()

View File

@ -30,8 +30,8 @@ public class AlertConfiguration: CommonConfiguration {
customBackgroundViewMask = callback
}
override var animateDurationForBuildInByDefault: CGFloat {
animateDurationForBuildIn ?? 0.6
override var animateDurationForBuildOutByDefault: CGFloat {
animateDurationForBuildOut ?? 0.2
}
}

View File

@ -124,13 +124,6 @@ extension AlertTarget: DefaultLayout {
}
}
func updateTimeoutDuration() {
//
vm?.timeoutHandler = DispatchWorkItem(block: { [weak self] in
self?.pop()
})
}
}
extension AlertTarget {

View File

@ -16,7 +16,7 @@ extension AlertTarget {
return
}
setDefaultAxis()
view.transform = .init(scaleX: 1.2, y: 1.2)
view.transform = .init(scaleX: 1.12, y: 1.12)
view.alpha = 0
navEvents[.onViewWillAppear]?(self)
window.vc.addChild(self)
@ -33,6 +33,7 @@ extension AlertTarget {
window.backgroundView.alpha = 1
} completion: { done in
self.navEvents[.onViewDidAppear]?(self)
self.updateTimeoutDuration()
}
window.alerts.append(self)
AlertTarget.updateAlertsLayout(alerts: window.alerts)
@ -42,9 +43,9 @@ extension AlertTarget {
navEvents[.onViewWillDisappear]?(self)
AlertTarget.removeAlert(alert: self)
let duration = config.animateDurationForBuildOut ?? config.animateDurationForBuildOutByDefault
UIView.animateEaseOut(duration: duration) {
UIView.animateLinear(duration: duration) {
self.view.alpha = 0
self.view.transform = .init(scaleX: 1.08, y: 1.08)
self.view.transform = .init(scaleX: 1.05, y: 1.05)
} completion: { done in
self.view.removeFromSuperview()
self.removeFromParent()
@ -55,7 +56,7 @@ extension AlertTarget {
let count = window.alerts.count
if count == 0 {
AppContext.alertWindow[windowScene] = nil
UIView.animateEaseOut(duration: duration) {
UIView.animateLinear(duration: duration) {
window.backgroundView.alpha = 0
} completion: { done in
// window使windowwindow
@ -74,6 +75,13 @@ extension AlertTarget {
}
}
func updateTimeoutDuration() {
//
vm?.timeoutHandler = DispatchWorkItem(block: { [weak self] in
self?.pop()
})
}
}
// MARK: - layout

View File

@ -36,6 +36,6 @@ class AlertWindow: Window {
extension AlertTarget {
var attachedWindow: AlertWindow? {
view.window as? AlertWindow
view.window as? AlertWindow ?? AppContext.current?.alertWindow
}
}

View File

@ -35,11 +35,11 @@ public class CapsuleConfiguration: CommonConfiguration {
override var cardMaxHeightByDefault: CGFloat { cardMaxHeight ?? 120 }
override var animateDurationForBuildInByDefault: CGFloat {
animateDurationForBuildIn ?? 0.8
animateDurationForBuildIn ?? 0.64
}
override var animateDurationForBuildOutByDefault: CGFloat {
animateDurationForBuildOut ?? 0.8
animateDurationForBuildOut ?? 0.32
}
var animateBuildIn: CustomAnimateHandler?

View File

@ -79,17 +79,6 @@ extension CapsuleTarget: DefaultLayout {
}
private func updateTimeoutDuration() {
// 使
if vm?.duration == nil {
vm?.duration = config.defaultDuration
}
//
vm?.timeoutHandler = DispatchWorkItem(block: { [weak self] in
self?.pop()
})
}
private func setupImageView() {
//
stopRotate(animateLayer)

View File

@ -11,17 +11,38 @@ extension CapsuleTarget {
@objc open func push() {
guard CapsuleConfiguration.isEnabled else { return }
guard let windowScene = preferredWindowScene ?? AppContext.windowScene else { return }
if windowScene != AppContext.windowScene {
AppContext.windowScene = windowScene
}
let isNew: Bool
let window: CapsuleWindow
let position = vm?.position ?? .top
if let w = AppContext.current?.capsuleWindows[position] {
isNew = false
window = w
} else {
window = CapsuleWindow(capsule: self)
isNew = true
if AppContext.capsuleWindows[windowScene] == nil {
AppContext.capsuleWindows[windowScene] = [:]
}
var windows = AppContext.capsuleWindows[windowScene] ?? [:]
if let w = windows[position], w.isHidden == false {
// capsule
if vm?.queuedPush == true {
//
self.preferredWindowScene = windowScene
AppContext.capsuleInQueue.append(self)
return
} else {
//
isNew = false
window = w
}
} else {
//
isNew = true
window = CapsuleWindow(capsule: self)
windows[position] = nil
}
// frame
let cardEdgeInsetsByDefault = config.cardEdgeInsetsByDefault
view.layoutIfNeeded()
@ -53,22 +74,22 @@ extension CapsuleTarget {
view.layer.cornerRadiusWithContinuous = config.cardCornerRadiusByDefault
window.rootViewController = self // toast.view.frame.sizewindow.frame.size
if let s = AppContext.windowScene {
if AppContext.capsuleWindows[s] == nil {
AppContext.capsuleWindows[s] = [:]
}
AppContext.capsuleWindows[s]?[position] = window
}
AppContext.capsuleWindows[windowScene]?[position] = window
navEvents[.onViewWillAppear]?(self)
// toast
ToastWindow.updateToastWindowsLayout()
if position == .top {
// toast
ToastWindow.updateToastWindowsLayout()
}
func completion() {
self.navEvents[.onViewDidAppear]?(self)
self.updateTimeoutDuration()
}
if isNew {
window.isHidden = false
func completion() {
self.navEvents[.onViewDidAppear]?(self)
}
if let animateBuildIn = config.animateBuildIn {
animateBuildIn(window, completion)
} else {
@ -82,16 +103,14 @@ extension CapsuleTarget {
completion()
}
case .middle:
let d0 = duration * 0.2
let d1 = duration
window.transform = .init(scaleX: 0.001, y: 0.001)
window.alpha = 0
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5) {
window.transform = .init(translationX: 0, y: 24)
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5) {
window.transform = .identity
} completion: { done in
completion()
}
UIView.animate(withDuration: duration * 0.4, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1) {
window.alpha = 0
UIView.animateLinear(duration: duration * 0.5) {
window.alpha = 1
}
case .bottom:
@ -103,8 +122,6 @@ extension CapsuleTarget {
completion()
}
}
}
} else {
view.layoutIfNeeded()
@ -112,7 +129,7 @@ extension CapsuleTarget {
window.frame = newFrame
window.layoutIfNeeded()
} completion: { done in
self.navEvents[.onViewDidAppear]?(self)
completion()
}
}
@ -120,11 +137,13 @@ extension CapsuleTarget {
@objc open func pop() {
guard let window = attachedWindow, let windowScene = windowScene else { return }
AppContext.capsuleWindows[windowScene]?[vm?.position ?? .top] = nil
let position = vm?.position ?? .top
AppContext.capsuleWindows[windowScene]?[position] = nil
navEvents[.onViewWillDisappear]?(self)
// toast
ToastWindow.updateToastWindowsLayout()
if position == .top {
// toast
ToastWindow.updateToastWindowsLayout()
}
func completion() {
window.isHidden = true
window.transform = .identity
@ -135,31 +154,37 @@ extension CapsuleTarget {
} else {
let duration = config.animateDurationForBuildOutByDefault
let oldFrame = window.frame
switch vm?.position {
case .top, .none:
UIView.animateEaseOut(duration: duration) {
switch position {
case .top:
UIView.animateEaseIn(duration: duration) {
window.transform = .init(translationX: 0, y: -oldFrame.maxY - 20)
} completion: { done in
completion()
}
case .middle:
UIView.animate(withDuration: duration * 0.6, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5) {
window.transform = .init(scaleX: 0.001, y: 0.001)
let duration = config.animateDurationForBuildInByDefault * 1
UIView.animateEaseIn(duration: duration) {
window.transform = .init(translationX: 0, y: -24)
} completion: { done in
completion()
}
UIView.animate(withDuration: duration * 0.4, delay: duration * 0.2, usingSpringWithDamping: 1, initialSpringVelocity: 0.5) {
UIView.animateLinear(duration: duration * 0.5, delay: duration * 0.3) {
window.alpha = 0
}
case .bottom:
let offsetY = AppContext.appBounds.height - oldFrame.maxY + 100
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0) {
UIView.animateEaseIn(duration: duration) {
window.transform = .init(translationX: 0, y: offsetY)
} completion: { done in
completion()
}
}
}
if let next = AppContext.capsuleInQueue.first(where: { $0.preferredWindowScene == windowScene && $0.vm?.position == position }) {
AppContext.capsuleInQueue.removeAll(where: { $0 == next })
DispatchQueue.main.asyncAfter(deadline: .now() + config.animateDurationForBuildOutByDefault * 0.8) {
next.push()
}
}
}
@ -174,4 +199,15 @@ extension CapsuleTarget {
}
}
func updateTimeoutDuration() {
// 使
if vm?.duration == nil {
vm?.duration = config.defaultDuration
}
//
vm?.timeoutHandler = DispatchWorkItem(block: { [weak self] in
self?.pop()
})
}
}

View File

@ -68,7 +68,9 @@ open class CapsuleProvider: HUDProvider<CapsuleViewModel, CapsuleTarget> {
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult public static func find(identifier: String, update handler: ((_ capsule: CapsuleTarget) -> Void)? = nil) -> [CapsuleTarget] {
let arr = AppContext.capsuleWindows.values.flatMap({ $0.values }).compactMap({ $0.capsule }).filter({ $0.identifier == identifier })
let allPositions = AppContext.capsuleWindows.values.flatMap({ $0.values })
let allCapsules = allPositions.compactMap({ $0.capsule })
let arr = (allCapsules + AppContext.capsuleInQueue).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}

View File

@ -17,24 +17,38 @@ import UIKit
@objc public var position: Position = .top
public func position(position: Position) -> Self {
// Capsule
// queuedPush: false
// queuedPush: true
@objc public var queuedPush: Bool = false
}
public extension CapsuleViewModel {
func position(_ position: Position) -> Self {
self.position = position
return self
}
public static var top: Self {
static var top: Self {
let obj = Self.init()
obj.position = .top
return obj
}
public static var middle: Self {
static var middle: Self {
let obj = Self.init()
obj.position = .middle
return obj
}
public static var bottom: Self {
static var bottom: Self {
let obj = Self.init()
obj.position = .bottom
return obj
}
func queuedPush(_ queuedPush: Bool) -> Self {
self.queuedPush = queuedPush
return self
}
}

View File

@ -27,7 +27,7 @@ class CapsuleWindow: Window {
windowLevel = .phCapsuleBottom
}
frame = .init(x: 0, y: 0, width: 128, height: 48)
isHidden = false
isHidden = true
}
required init?(coder: NSCoder) {

View File

@ -9,6 +9,9 @@ import UIKit
open class BaseController: UIViewController {
/// UIWindowScene
var preferredWindowScene: UIWindowScene?
/// ID
public var identifier = String(Date().timeIntervalSince1970)
@ -23,6 +26,7 @@ open class BaseController: UIViewController {
open var customView: UIView?
public internal(set) var isViewDisplayed = false
///
var buttonEvents = [UIView: () -> Void]()

View File

@ -32,9 +32,7 @@ open class HUDProvider<ViewModel: HUDViewModelType, Target: HUDTargetType>: NSOb
}
var t = Target()
initializer(t)
DispatchQueue.main.async {
t.push()
}
t.push()
}
}

View File

@ -37,6 +37,7 @@ public struct AppContext {
static var alertWindow: [UIWindowScene: AlertWindow] = [:]
static var sheetWindows: [UIWindowScene: [SheetWindow]] = [:]
static var capsuleWindows: [UIWindowScene: [CapsuleViewModel.Position: CapsuleWindow]] = [:]
static var capsuleInQueue: [CapsuleTarget] = []
static var current: AppContext? {
guard let windowScene = windowScene else { return nil }
@ -123,5 +124,8 @@ extension AppContext {
var capsuleWindows: [CapsuleViewModel.Position: CapsuleWindow] {
Self.capsuleWindows[windowScene] ?? [:]
}
var alertWindow: AlertWindow? {
Self.alertWindow[windowScene]
}
}

View File

@ -9,8 +9,14 @@ import UIKit
extension UIView {
static func animateLinear(duration: TimeInterval, delay: TimeInterval = 0, animations: @escaping () -> Void, completion: ((_ done: Bool) -> Void)? = nil) {
animate(withDuration: duration, delay: delay, options: [.allowUserInteraction], animations: animations, completion: completion)
}
static func animateEaseIn(duration: TimeInterval, animations: @escaping () -> Void, completion: ((_ done: Bool) -> Void)? = nil) {
animate(withDuration: duration, delay: 0, options: [.allowUserInteraction, .curveEaseIn], animations: animations, completion: completion)
}
static func animateEaseOut(duration: TimeInterval, animations: @escaping () -> Void, completion: ((_ done: Bool) -> Void)? = nil) {
animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.75, options: [.allowUserInteraction, .curveEaseOut], animations: animations, completion: completion)
animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: [.allowUserInteraction, .curveEaseOut], animations: animations, completion: completion)
}
}

View File

@ -51,11 +51,11 @@ public class SheetConfiguration: CommonConfiguration {
override var cardMaxHeightByDefault: CGFloat { cardMaxHeight ?? (AppContext.appBounds.height - 50) }
override var animateDurationForBuildInByDefault: CGFloat {
animateDurationForBuildIn ?? 0.5
animateDurationForBuildIn ?? 0.38
}
override var animateDurationForBuildOutByDefault: CGFloat {
animateDurationForBuildOut ?? 0.5
animateDurationForBuildOut ?? 0.24
}
override var cardCornerRadiusByDefault: CGFloat { cardCornerRadius ?? 32 }

View File

@ -44,18 +44,16 @@ extension SheetTarget: DefaultLayout {
// mask
loadContentMaskViewIfNeeded()
// layout
let windowWidth = AppContext.appBounds.width
let maxWidth = config.cardMaxWidthByDefault
var width = AppContext.appBounds.width - config.windowEdgeInset * 2
if width > maxWidth {
// landscape iPhone or iPad
width = maxWidth
}
let autoWidth = windowWidth - config.windowEdgeInset * 2
let width = min(autoWidth, maxWidth)
contentView.snp.remakeConstraints { make in
if config.isFullScreen {
make.edges.equalToSuperview()
} else {
make.centerX.equalToSuperview()
if UIDevice.current.userInterfaceIdiom == .pad && width >= maxWidth {
if UIDevice.current.userInterfaceIdiom == .pad && width < autoWidth - 40 {
// iPad
make.centerY.equalToSuperview()
} else {

View File

@ -27,6 +27,7 @@ extension SheetTarget {
setContextWindows(windows)
}
if isNew {
_translateOut()
navEvents[.onViewWillAppear]?(self)
window.sheet.translateIn { [weak self] in
guard let self = self else { return }
@ -89,7 +90,7 @@ extension SheetTarget {
}
func translateOut(completion: (() -> Void)?) {
UIView.animateEaseOut(duration: config.animateDurationForBuildOutByDefault) {
UIView.animateLinear(duration: config.animateDurationForBuildOutByDefault) {
self._translateOut()
if self.config.stackDepthEffect {
AppContext.appWindow?.transform = .identity

View File

@ -20,7 +20,6 @@ open class SheetTarget: BaseController, HUDTargetType {
public lazy var backgroundView: UIView = {
let v = UIView()
v.backgroundColor = .init(white: 0, alpha: 0.5)
v.alpha = 0
return v
}()
@ -64,8 +63,6 @@ open class SheetTarget: BaseController, HUDTargetType {
reloadData(animated: false)
_translateOut()
navEvents[.onViewDidLoad]?(self)
}

View File

@ -42,11 +42,11 @@ public class ToastConfiguration: CommonConfiguration {
}
override var animateDurationForBuildInByDefault: CGFloat {
animateDurationForBuildIn ?? 0.8
animateDurationForBuildIn ?? 0.64
}
override var animateDurationForBuildOutByDefault: CGFloat {
animateDurationForBuildIn ?? 0.8
animateDurationForBuildIn ?? 0.32
}
}

View File

@ -134,17 +134,6 @@ extension ToastTarget {
}
}
private func updateTimeoutDuration() {
// 使
if vm?.duration == nil {
vm?.duration = config.defaultDuration
}
//
vm?.timeoutHandler = DispatchWorkItem(block: { [weak self] in
self?.pop()
})
}
func setupImageView() {
//
stopRotate(animateLayer)

View File

@ -66,16 +66,21 @@ extension ToastTarget {
setContextWindows(windows)
}
ToastWindow.updateToastWindowsLayout(windows: windows)
func completion() {
self.navEvents[.onViewDidAppear]?(self)
self.updateTimeoutDuration()
}
if isNew {
window.transform = .init(translationX: 0, y: -window.frame.maxY)
UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) {
window.transform = .identity
} completion: { done in
self.navEvents[.onViewDidAppear]?(self)
completion()
}
} else {
view.layoutIfNeeded()
self.navEvents[.onViewDidAppear]?(self)
completion()
}
}
@ -94,7 +99,7 @@ extension ToastTarget {
}
vm?.duration = nil
setContextWindows(windows)
UIView.animateEaseOut(duration: config.animateDurationForBuildOutByDefault) {
UIView.animateLinear(duration: config.animateDurationForBuildOutByDefault) {
window.transform = .init(translationX: 0, y: 0-20-window.maxY)
} completion: { done in
self.view.removeFromSuperview()
@ -115,6 +120,17 @@ extension ToastTarget {
}
}
func updateTimeoutDuration() {
// 使
if vm?.duration == nil {
vm?.duration = config.defaultDuration
}
//
vm?.timeoutHandler = DispatchWorkItem(block: { [weak self] in
self?.pop()
})
}
}
// MARK: - layout