SwiftUI Overlay Container is a view Container component for SwiftUI. A customizable, efficient, and convenient view manager.

With a simple configuration, SwiftUI Overlay Container takes care of the basics from view organization, queue processing, transitions, animation, interaction, and display style configuration, allowing developers to focus more on the implementation of the application’s view itself.

The original post was posted on my blog wwww.fatbobman.com

Welcome to subscribe my public account: [Elbow’s Swift Notepad]

history

In the summer of 2020, while adding side sliding menus to Health Note, I found that it was common to come across scenarios in development where you needed to dynamically add another view on top of one view, for example (prompts, ads, floating buttons, novice guides, etc.). Therefore, I have written a component that I hope will help developers accomplish this requirement quickly in SwiftUI. However, due to the limitations of the technology at that time, many of the ideas were not well implemented.

I recently rewrote the component to see if I had improved over time, in addition to implementing functionality that was not previously supported.

You can get the latest version here.

The content of this article is transported directly from the README document for the project.

The motivation

When we need to display new content on top of the view (e.g., pop-up messages, side menus, help hints, etc.), there are many excellent third-party solutions that can help us do this separately, but none of them can address the requirements of different scenarios at the same time. With SwiftUI, it has become so easy to describe views that it is possible to extract the display logic from the above scenarios to create a library that covers more usage scenarios and helps developers organize the display style and interaction logic of views.

Functions and Features

  • Support for multiple containers
  • Multiple views are supported within a single container
  • You can push views to any specified container within or outside the SwiftUI view code
  • Configuration of containers can be dynamically modified (except for queue types)
  • There are several ways to arrange views within a container
  • There are multiple queue types to instruct the container how to display the view

Quick Use Guide

For more information, see the library demo and comments in the source code.

Create a container

Creates a view container on top of the specified view with the size of the attached view:

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

When no view container is attached to a view:

ViewContainer("containerB", configuration: BConfiguration())
Copy the code

Display the view in the container

In the view container containerA displays the MessageView view

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

Or use the view manager

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()}}}}Copy the code

Destroys all views in the specified container

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

basis

The container

Components that receive and display views. At a minimum, you need to set the container’s name, view display type, and view queue type.

You can set a default view style for the container, and for style attributes not specified by the view, the container’s default Settings are used instead.

Display type

  • stacking

    When multiple views are displayed in a container, the views are arranged along the Z-axis. It behaves similarly to ZStack.

  • horizontal

    When multiple views are displayed in a container at the same time, the views are arranged along the X-axis. It behaves like HStack.

  • vertical

    When multiple views are displayed in a container, the views are arranged along the Y-axis. It behaves like VStack.

View Queue Type

  • multiple

    Multiple views can be displayed simultaneously within a container. When the number of views exceeds the maximum number set by the container, the exceeded views are temporarily stored in the waiting queue and replaced one by one after the displayed views are cancelled.

  • oneByOne

    Only one view can be displayed in the container at a time. The newly added view will automatically replace the view being displayed.

  • oneByOneWaitFinish

    One view can be displayed in the container at a time. A new view can only be displayed if the currently displayed view is destroyed.

Configuration of the container

Container configuration requires setting at least the following properties:

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

Other properties that can be set include:

  • delayForShowingNext

    Automatically fills the interval for the next view

  • maximumNumberOfViewsInMultipleMode

    In Multiple mode, the maximum number of views that can be displayed simultaneously in a container

  • spacing

    Indicates the interval between views in vertical and horizontal mode

  • insets

    In stacking mode, this value is an embedded value for the view. In horizontal and vertical modes, this value is an embedded value for the view group.

  • Configuration for all other container views (used as the default for container views)

    See the Configure Container view below for details

Container environment value

Each container provides an environment value — overlayContainer — for the view inside the container. The view inside the container can use this value to get information about the container (name, size, display type, queue type) and to undo the display.

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()
                    }
                }
            )
    }
}
Copy the code

Container view

All SwiftUI views can be displayed inside the container. You can configure for similar functionality to create the same views, or to a particular view follow ContainerViewConfigurationProtocol agreement, set separately.

Configuring the Container View

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}}Copy the code
  • alignment

    Example Set an alignment of a view or view group in a container. In stacking mode, different alignments can be set for each view. In vertical or horizontal mode, all views (view groups) share container alignments.

  • tapToDismiss

    Whether it is allowed to undo a view by clicking on the background when backgroundStyle is set for the view.

    See the project demo code for details

  • backgroundStyle

    Set the background for the container view. Currently supports color, Blur, and customView.

    Some versions of the operating system (iOS 14, watchOS) do not support Blur mode. If you want to use Blur in these versions, you can use customView to wrap the other Blur code.

    See the project demo code for details

  • backgroundTransitionStyle

    Background transitions. Setting opacity to identity cancels transitions.

  • shadowStyle

    Add a shadow to the view

  • dismissGesture

    Add and cancel gestures to view. Currently, you can click, double click, long press, left swipe, right swipe, up swipe, down swipe, and customize.

    Custom gestures to use eraseToAnyGestureForDismiss to erase type.

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

Under tvOS, only long press is supported

See the project demo code for details

  • transition

    Transitions of views

  • animation

    Animation for view transitions

  • autoDismiss

    Whether automatic undo is supported. .seconds(3) Indicates that the view will be automatically cancelled after 3 seconds.

    See the project demo code for details

  • disappearAction

    Closure that executes after the view is destroyed

  • appearAction

    The view displays the previously executed closure in the container

Container manager

The container manager is the bridge between the program code and the container. The consumer invokes specific methods of the container manager to make the specified container perform display views, undo views, and so on.

Container manager environment value

In SwiftUI, view code invokes the container manager with environment values.

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()}}}}Copy the code

The container manager currently provides the following methods:

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

    Displays the view in the specified container, returning the ID of the view

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

    In the specified container, undoes the view with the specified ID

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

    Destroys views in all containers except the one specified. When onlyShow is true, only the view being displayed is destroyed.

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

    Destroys all views in the specified container

Maskable animation

Either by calling the Container Manager directly or using the View Modifier, you can force the transition animation to be unanimated when animated is set to false.

This is useful when dealing with scenarios such as Deep Link.

Used outside the SwiftUI view

If you want to call the ContainerManager outside of the SwiftUI view, you can call the ContainerManager singleton directly:

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

System requirements

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

The installation

The preferred way to install SwiftUIOverlayContainer is through Swift Package Manager.

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

copyright

This library is distributed under license from MIT. See the LICENSE.

Help and Support

Create Issues to give your comments or suggestions. You can also reach me on Twitter @fatBobman.

The original post was posted on my blog wwww.fatbobman.com

Welcome to subscribe my public account: [Elbow’s Swift Notepad]