一个高度可定制的 SwiftUI 视图容器组件
SwiftUI Overlay Container 是一个 SwiftUI 视图容器组件。它是一个可定制、高效且方便的视图管理器。
只需简单的配置,SwiftUI Overlay Container 就可以为您完成视图组织、队列处理、过渡、动画、交互、显示样式配置等基本工作,让开发者可以将更多精力投入到应用程序视图本身的实现上。
当我们需要在视图的上层显示新内容时(例如:弹出信息、侧边菜单、帮助提示等),有很多优秀的第三方解决方案可以帮助我们单独实现它,但是没有解决方案可以同时处理不同的情况。
在 SwiftUI 中,描述视图变得非常容易,因此我们可以完全提取上述场景中的显示逻辑,创建一个可以覆盖更多使用场景的库,并帮助开发者组织视图的显示样式和交互逻辑。
queue type
和 clipped
)更多详情,请参阅库中的示例和源代码中的注释。
在指定视图的顶部创建一个与它尺寸相同的视图容器。
VStack{
// your view
}
.overlayContainer("containerA", containerConfiguration: AConfiguration())
当不需要附加到视图的视图容器时。
ViewContainer("containerB", configuration: BConfiguration())
在视图容器 containerA
中显示视图 MessageView
.containerView(in: "containerA", configuration: ViewConfiguration(), isPresented: $show, content: MessageView())
使用容器管理器
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)
}
}
}
}
接收和显示视图的组件。至少对于容器,您需要设置:名称、视图显示类型、视图队列类型。
您可以为容器设置默认视图样式,对于视图未指定的样式属性,将使用容器的默认设置。
堆叠 (stacking)
当多个视图同时显示在容器中时,这些视图沿 Z 轴排列。 它的行为类似于 ZStack
。
水平 (horizontal)
当多个视图同时显示在容器中时,这些视图沿 X 轴排列。 它的行为类似于 HStack
。
垂直 (vertical)
当多个视图同时显示在容器中时,这些视图沿 Y 轴排列。 它的行为类似于 VStack
。
多个 (multiple)
多个视图可以同时显示在容器中。当给定的视图数量超过容器设置的最大视图数量时,多余的视图将暂时存储在等待队列中,并在显示的视图被关闭后逐一补充。
逐个 (oneByOne)
一次只能在容器中显示一个视图。 新添加的视图将自动替换正在显示的视图。
逐个等待完成 (oneByOneWaitFinish)
一次只能在容器中显示一个视图。 只有在当前显示的视图被关闭后,才能显示新视图。
容器的配置必须至少设置以下属性
struct MyContainerConfiguration:ContainerConfigurationProtocol{
var displayType: ContainerViewDisplayType = .stacking
var queueType: ContainerViewQueueType = .multiple
}
其他属性
delayForShowingNext
补充下一个视图的时间间隔
maximumNumberOfViewsInMultipleMode
在 multiple 模式下,容器中可以同时显示的最大视图数量
spacing
垂直和水平模式下视图之间的间距
insets
在堆叠模式下,该值是视图的 insets 值。 在水平和垂直模式下,该值是视图组的 insets 值
clipped
裁剪容器,当您想要限制视图过渡的边界时,设置为 true
ignoresSafeArea
将容器扩展到其安全区域之外。 默认值为 .disable
(不忽略),.all
(忽略所有安全区域) 和 .custom
(自定义区域和边缘)
queueControlOperator
仅在指定的timeInterval过去后才执行窗口操作,默认值为none
,即不启用
它仅适用于特殊需求场景,例如使用OverallContainer代替Sheet。在List中,单击每一行都会弹出一个窗口。 在这种情况下,如果用户不小心使用多个手指点击,则会打开多个窗口条件。为容器启用防抖功能,容器将在短时间内仅保留一个有效操作。 通常只需将duetime设置为0.1秒(.debounce(seconds: 0.1)
)
所有其他容器视图的配置(用作容器视图的默认值)
有关详细信息,请参见下面的配置容器视图
每个容器都为容器内部的视图提供了一个环境值 - 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
设置容器内视图或视图组的对齐方式。 在堆叠模式下,您可以为每个视图设置不同的对齐方式,在垂直或水平模式下,所有视图(视图组)共享容器的对齐方式设置。
tapToDismiss
如果为视图设置了 backgroundStyle,是否允许通过单击背景来关闭视图。
有关详细信息,请参见项目示例代码
backgroundStyle
为容器视图设置背景。 当前支持颜色、模糊、customView。
某些版本的操作系统(iOS 14,watchOS)不支持模糊模式。 如果您想在这些版本中使用模糊,可以通过 customView 包装其他模糊代码。
有关详细信息,请参见项目示例代码
backgroundTransitionStyle
背景过渡。 默认值为 opacity,设置为 identity 以取消过渡。
shadowStyle
为视图添加阴影
dismissGesture
为视图添加取消手势,当前支持单点点击、双点点击、长按、左滑、右滑、上滑、下滑和自定义手势。
使用 eraseToAnyGestureForDismiss
在使用自定义手势时擦除类型。
let gesture = LongPressGesture(minimumDuration: 1, maximumDistance: 5).eraseToAnyGestureForDismiss()
在 tvOS 下,仅支持长按
有关详细信息,请参见项目示例代码
transition
视图的过渡效果
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
为 true 时,仅关闭正在显示的视图。
dismissAllView(in containers: [String], onlyShowing: Bool, animated flag: Bool)
关闭指定容器中的所有视图
dismissTopmostView(in containers: [String], animated flag: Bool)
关闭指定容器中的最顶层视图
当 animated
设置为 false 时,可以通过直接调用容器管理器或使用 View 修饰符来强制取消过渡动画。
这在处理诸如 Deep Link 之类的场景时很有用。
如果要在 SwiftUI 视图之外调用容器管理器,可以直接调用 ContainerManager 单例
let manager = ContainerManager.share
manager.show(view: MessageView(), in: "containerB", using: ViewConfiguration())
安装 SwiftUIOverlayContainer 的首选方法是通过 Swift Package Manager。
dependencies: [
.package(url: "https://github.com/fatbobman/SwiftUIOverlayContainer.git", from: "2.0.0")
]
该库是在 MIT 许可下发布的。 有关详细信息,请参见 LICENSE。
您可以通过创建 Issues 来提供您的反馈或建议。 您也可以在 Twitter 上联系我 @fatbobman。