AlertPresenter



Cocoapods

已在 Swift Package Index 上列出,最初发布在我的 博客 上。

在特定的视图控制器上处理警报的显示可能很棘手,尤其是当过渡动画或当前在该视图控制器上显示的其他内容可能会静默地阻止警报的显示时。

AlertPresenter 通过消除指定应在哪个视图控制器上显示警报的需求,简化了该过程。 它还可以让您将警报排队,以便不会错过任何需要在短时间内显示的警报。

支持的平台

AlertPresenter 可以很容易地从 Swift 和 Objective-C 中使用。 虽然它基于 UIKit,但它同样可以轻松地从 SwiftUI 中使用。

Alert Presenter 可能不适合超出简单应用的任何内容,因为您可能需要更好地控制警报的显示以及其他导航。 但对于测试应用或其他简单应用,它可能非常有用。

鸣谢

此软件包基于 William Boles 的文章,因此大部分功劳归功于他的原始解决方案。 我只是稍微现代化了一下,支持了 tvOS 和 iOS 12,将其打包并添加了一些其他功能和测试。

添加到您的项目

Swift Package

按照 Apple 的指南 将该软件包添加到您的项目中。

Cocoapod

按照 cocoapods 页面上的指南将 AlertPresenter pod 添加到您的项目中,或从头开始设置 cocoapods。

用法

基本用法

只需创建 AlertPresenter 的一个实例,并将警报连同应在其中显示的 windowScene 一起排队(如果正在使用 SceneDelegate 或 SwiftUI 的 App,则 xOS 13+ 需要)。

import AlertPresenter

let alertPresenter = AlertPresenter()

func showAlert() {
    let alert = UIAlertController(title: "title",
                                message: "message",
                                preferredStyle: .alert)
    // also works with .actionSheet or a custom UIViewController alert
    let scene = UIApplication.shared.windows.first?.windowScene
    alertPresenter.enqueue(alert: alert, 
                           windowScene: scene)
}

UIWindow.Level

如果需要,您可以使用 UIWindow.Level 初始化 AlertPresenter,并且可以使用多个实例来处理您可能需要在已显示的警报之上显示的具有不同优先级的警报。

自定义警报

为了确保 AlertPresenter 收到自定义警报已解除的消息,它应该像这样自行解除

presentingViewController?.dismiss(animated: true)

Popover presentations (弹出窗口显示)

在 iPad 上,需要告诉操作表应该出现在屏幕上的哪个位置,因为它以弹出窗口的形式显示,而不是像在 iOS 上那样以底部表单的形式显示。 AlertPresenter 的默认行为是在屏幕中心显示弹出窗口,没有箭头指向其源矩形。

您可以通过在排队警报时传递 PopoverPresentation 来覆盖默认行为

func showAlert() {
    // The closure to be called when the alert is presented
    let presentation = { [weak self] alert in
        guard let self = self else {
            // If we've been deinitalised before presentation return some default
            // details to present the alert centered on the screen
            return PopoverPresentation(sourceRect: .zero,
                                        delegate: nil)
        }
        
        // Calculate the rect to present the alert from, such as the frame of the button
        // in window coordinates
        let rect = button.superview?.convert(button.frame, to: self.view) ?? .zero
        return PopoverPresentation(sourceRect: rect,
                                    delegate: self)
    }
            
    let scene = view.window?.windowScene
    alertPresenter.enqueue(alert: alert,
                           windowScene: scene,
                           popoverPresentation: popoverPresentation)
}

delegate 参数是一个 PopoverDelegate。 在 iOS 上,它符合 UIPopoverPresentationControllerDelegate,如果您想强制您的自定义警报在 iPhone 上作为弹出窗口显示,这将非常有用

extension MyClass: PopoverDelegate {
    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        // forces the popover presentation style to be honoured on iPhone
        return .none
    }
}

测试应用

SimpleExamples 文件夹中有一个最小的 iOS 13+、UIKit 示例。

TestApps 文件夹中有各种更复杂的测试应用,它们演示了自定义警报、iPad 操作表显示自定义、弹出窗口自定义、iOS/tvOS 12 和 SwiftUI

贡献

如果您希望为此项目做出任何贡献,请随意创建一个 fork,然后提交一个 pull request,其中包含您提出的更改/添加。

确保任何更改或添加都包含单元/UI 测试,并根据需要更新测试应用。

请记住,应尽可能避免重大更改!

重大变更监控

我的 PublicAPIMonitoringExample 中的脚本作为构建阶段包含在内。 它们以 Swift 和 ObjC 两种语言将公共 API 输出到文件中,以便可以在提交中监控任何重大更改的引入。

SwiftLint

该项目使用 SwiftLint 进行设置,以稍微检查代码质量。 它由项目根目录中的 .swiftlint.yml 文件配置。

使用以下命令在项目根目录中运行扫描:swiftlint

SwiftLint 执行也包含在自动化测试中。

Jazzy 文档

可以使用 Jazzy 生成 API 文档。 虽然这没有发布,但它对于指出 API 中未正确记录的部分非常有用(在生成文档后检查 undocumented.json 文件中的任何警告),因此您可以确保 Xcode 中提供的 API 文档是正确的,对用户有用。 .jazzy.yaml 包含配置。

使用以下命令在项目根目录中生成文档:jazzy

Jazzy 执行也包含在自动化测试中。

运行自动化测试

Fastlane 用于自动化地在一个命令(或单独地)运行所有测试,使用带有 Bundler 的推荐设置,有关 Fastlane 网站的更多信息

在项目的根目录中运行 bundle exec fastlane <lane>,并具有以下 lane 选项

注意: 如果您有一台 M1 Mac,除非您已将其设置为使用 Rosetta 打开,否则 Jazzy(用于在 checkDocsallTests lanes 中生成文档)在终端中不起作用。