SwiftUI Overlay Container 是一个用于 SwiftUI 的视图容器组件。一个可定制、高效、快捷的视图管理器。

仅需简单装备,SwiftUI Overlay Container 即可帮你完结从视图安排、行列处理、转场、动画、交互到显现样式装备等基础作业,让开发者能够将精力更多地投入到应用程序视图的完结自身。

原文发表在我的博客wwww.fatbobman.com

欢迎订阅我的公共号:【肘子的Swift记事本】

前史

2020 年夏天,在为 健康笔记 增加侧向滑动菜单的过程中,我发现在开发中经常会碰到需要在一个视图的上方动态增加另一视图的场景,例如(提示信息、广告、浮动按钮、新手指南等等)。因而,我写了一个组件期望能够协助开发者在 SwiftUI 中快速完结上述需求。但受限于其时的技术才干,很多的主意都没有能够很好地完结。

近期我重写了该组件,除了完结了曾经没有支撑的功用外,更重要的是,以此查验一下自己这段时刻的才干是否有所提高。

我们能够从 这儿 获取最新的版别。

本文的内容直接搬运自项目的 README 文档。

设计动机

当我们需要在视图的上层显现新的内容(例如:弹出信息、侧边菜单、协助提示等)时,有很多优秀的第三方解决方案能够协助我们别离完结,但没有一个方案能够一起应对不同的场景需求。在 SwiftUI 中,描绘视图现已变得非常的简单,因而我们完全能够将上述场景中的显现逻辑提炼出来,创立出一个能够覆盖更多运用场景的库,协助开发者安排视图的显现风格和交互逻辑。

功用与特性

  • 支撑多个容器
  • 单一容器内支撑多个视图
  • 可在 SwiftUI 视图代码内或视图代码外向任意指定的容器推送视图
  • 能够动态修正容器的装备(除了行列类型)
  • 容器内的视图有多种摆放办法
  • 有多种行列类型以辅导容器如何显现视图

快速运用指南

更详细的信息,能够参看库中的演示以及源代码中的注释。

创立容器

在指定视图上层创立一个视图容器,此容器的尺度同其附着的视图尺度共同:

VStack{
    // your view
}
.overlayContainer("containerA", containerConfiguration: AConfiguration())

当无需视图容器附着在某个视图时:

ViewContainer("containerB", configuration: BConfiguration())

在容器中显现视图

在视图容器 containerA 显现视图 MessageView

.containerView(in: "containerA", configuration: MessageView(), isPresented: $show, content: ViewConfiguration())

或者运用视图管理器

struct ContentView1: View {
    @Environment(\.overlayContainerManager) var manager
    var body: some View {
        VStack {
            Button("push view in containerB") {
                manager.show(view: MessageView(), in: "containerB", using: ViewConfiguration())
            }
        }
    }
}

吊销指定容器内的一切视图

struct ContentView1: View {
    @Environment(\.overlayContainerManager) var manager
    var body: some View {
        VStack {
            Button("push view in containerB") {
                manager.dismissAllView(in: ["containerA","containerB"], animated: true)
            }
        }
    }
}

基础

容器

接纳并显现视图的组件。至少需要为容器设定:称号、视图显现类型、视图行列类型。

能够为容器设定默认的视图风格,关于视图未指定的风格特点,会运用容器的默认设置替代。

容器显现类型( Display type )

  • stacking

    当容器内一起显现多个视图时,视图沿 Z 轴摆放。其体现同 ZStack 相似。

    SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

  • horizontal

    当容器内一起显现多个视图时,视图沿 X 轴摆放。其体现同 HStack 相似。

    SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

  • vertical

    当容器内一起显现多个视图时,视图沿 Y 轴摆放。其体现与 VStack 相似。

    SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

视图行列类型( Queue Type )

  • multiple

    能够一起在容器内显现多个视图。当给定的视图数量超过了容器设定的最大视图数量时,超过的视图会暂存在等候行列中,并在已显现视图吊销后,逐个递补。

    SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

  • oneByOne

    同一时刻只能在容器中显现一个视图。新增加的视图将主动替换掉正在显现的视图。

    SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

  • oneByOneWaitFinish

    同一时刻能在容器中显现一个视图。只有当前正在显现的视图被吊销后,新的视图才干被显现。

    SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

装备容器

容器的装备至少要对以下特点进行设置:

struct MyContainerConfiguration:ContainerConfigurationProtocol{
    var displayType: ContainerViewDisplayType = .stacking
    var queueType: ContainerViewQueueType = .multiple
}

其他能够设置的特点还有:

  • delayForShowingNext

    主动递补下一个视图的时刻间隔

  • maximumNumberOfViewsInMultipleMode

    multiple 形式下,容器内可一起显现的最多视图数量

  • spacing

    vertical 、horizontal 形式下,视图之间的间隔

  • insets

    在 stacking 形式下,该值为视图的内嵌值。在 horizontal 和 vertical 形式下,该值为视图组的内嵌值。

  • 其他一切容器视图的装备(用作容器视图的默认值)

    概况参阅下方的装备容器视图

容器环境值

每个容器都为容器内的视图提供了一个环境值—— overlayContainer 。容器内的视图能够经过该值获取容器的信息(称号、尺度、显现类型、行列类型)并履行吊销显现的行为。

struct MessageView: View {
    @Environment(\.overlayContainer) var container
    var body: some View {
        RoundedRectangle(cornerRadius: 10)
            .frame(width: 300, height: 10)
            .overlay(
                HStack {
                    Text("container Name:\(container.containerName)")
                    Button("Dismiss me"){
                        container.dismiss()
                    }
                }
            )
    }
}

容器视图

一切的 SwiftUI 视图都能够在容器内显现。你能够为相似功用的视图创立同一个视图装备,或者让某个特定视图遵从 ContainerViewConfigurationProtocol 协议,单独进行设置。

装备容器视图

public protocol ContainerViewConfigurationProtocol {
    var alignment: Alignment? { get }
    var tapToDismiss: Bool? { get }
    var backgroundStyle: ContainerBackgroundStyle? { get }
    var backgroundTransitionStyle: ContainerBackgroundTransitionStyle { get }
    var shadowStyle: ContainerViewShadowStyle? { get }
    var dismissGesture: ContainerViewDismissGesture? { get }
    var transition: AnyTransition? { get }
    var autoDismiss: ContainerViewAutoDismiss? { get }
    var disappearAction: (() -> Void)? { get }
    var appearAction: (() -> Void)? { get }
    var animation: Animation? { get }
}
  • alignment

    设置视图或视图组在容器中的 alignment。stacking 形式下,能够为每个视图设置不同的 alignment,在 vertical 或 horizontal 形式下,一切视图(视图组)共用容器的 alignment 设置。

  • tapToDismiss

    在为视图设置了 backgroundStyle 的情况下,是否允许经过点击布景来吊销视图。

    概况参看项目演示代码

  • backgroundStyle

    为容器视图设置布景。现在支撑 color、blur、customView。

    部分版别的操作系统(iOS 14,watchOS )不支撑 blur 形式,如果想在这些版别中运用 blur,能够经过 customView 来包裹其他的 blur 代码。

    概况参看项目演示代码

SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

  • backgroundTransitionStyle

    布景的转场。默以为 opacity, 设置为 identity 可吊销转场。

  • shadowStyle

    为视图增加暗影

  • dismissGesture

    为视图增加吊销手势,现在支撑 单击、双击、长按、左划、右划、上划、下划、自定义。

    自定义手势需运用 eraseToAnyGestureForDismiss 对类型进行擦除。

  let gesture = LongPressGesture(minimumDuration: 1, maximumDistance: 5).eraseToAnyGestureForDismiss()

在 tvOS 下,仅长按被支撑

概况参看项目演示代码

SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

  • transition

    视图的转场

  • animation

    视图转场的 animation

  • autoDismiss

    是否支撑主动吊销。 .seconds(3) 表示 3 秒后视图会主动吊销。

    概况参看项目演示代码

  • disappearAction

    视图被吊销后履行的闭包

  • appearAction

    视图在容器中显现前履行的闭包

容器管理器

容器管理器是程序代码与容器之间的桥梁。运用者经过调用容器管理器的特定办法,让指定的容器履行显现视图、吊销视图等作业。

容器管理器的环境值

在 SwiftUI 中,视图代码经过环境值调用容器管理器。

struct ContentView1: View {
    @Environment(\.overlayContainerManager) var manager
    var body: some View {
        VStack {
            Button("push view in containerB") {
                manager.show(view: MessageView(), in: "containerB", using: ViewConfiguration())
            }
        }
    }
}

容器管理器现在提供的办法有:

  • show(view: Content, with ID: UUID?, in container: String, using configuration: ContainerViewConfigurationProtocol, animated: Bool) -> UUID?

    在指定的容器中显现视图,返回值为视图的 ID

  • dismiss(view id: UUID, in container: String, animated flag: Bool)

    在指定的容器中,吊销指定 ID 的视图

  • dismissAllView(notInclude excludeContainers: [String], onlyShowing: Bool, animated flag: Bool)

    吊销除了指定的容器外其他一切容器中的视图,当 onlyShow 为真时,仅吊销正在显现的视图。

  • dismissAllView(in containers: [String], onlyShowing: Bool, animated flag: Bool)

    吊销指定容器内的一切视图

可屏蔽动画

无论是直接调用容器管理器还是运用 View modifier,当将 animated 设为 false 时,均可强制吊销转场动画。

关于处理例如 Deep Link 之类的场景时非常有效。

SwiftUI Overlay Container 2 —— 可定制、高效、便捷的视图管理器

在 SwiftUI 视图外运用

如果想在 SwiftUI 视图之外调用容器管理器,能够直接调用 ContainerManager 的单例:

let manager = ContainerManager.share
manager.show(view: MessageView(), in: "containerB", using: ViewConfiguration())

系统需求

  • iOS 14+
  • macOS 11+
  • tvOS 14+
  • watchOS 7+

装置

装置 SwiftUIOverlayContainer 的首选办法是经过 Swift Package Manager。

dependencies: [
  .package(url: "https://github.com/fatbobman/SwiftUIOverlayContainer.git", from: "2.0.0")
]

版权

这个库是在 MIT 答应下发布的。详见 LICENSE。

协助与支撑

能够经过创立 Issues 来反馈你的定见或建议。也能够经过 Twitter @fatbobman 与我联络。

原文发表在我的博客wwww.fatbobman.com

欢迎订阅我的公共号:【肘子的Swift记事本】