Placard

main

Placard is a small and easy to use package for presenting an animated message bar using SwiftUI
ccavnor/Placard

Placard logo

Placard

API documentation available here

Placard is a small and easy to use package for presenting an animated message bar using SwiftUI.

Message views can be displayed at the top, bottom, or center of the screen and can be offset from both the screen edges and the vertical placements using UIEdgeInsets.

There are interactive show, tap, and dismiss gestures - an array of animated themes to choose from (or no animation if you want).

Placard allows you to choose default message themes for things such as priority-based messages, but also offers customization via either parameters, a configuration object, or you can use your own SwiftUI view and let Placard control its animations and appearance. The Placard can be configured to display for any period of time (by default, it displays forever - or until a user taps on it). Further, all Placard messages can given an action to perform on user tap (but not if Placard dismisses itself via a timeout).

Placards automatically redraw themselves, adapting to device orientation changes:

Requirements

Placard is built and tested for iOS 17.2 and onward only.

Running Placard via the PlacardDemo project

The PlacardDemo app allows you to explore Placard, both the default options and by changing the configuration:

Download the zip of this repository and extract it. Run PlacardDemo.xcodeproj and choose either iphone or ipad as targets for the simulator (see Requirements section for required xcode builds).

The images of Placard in this documentation were all taken as screen grabs from the PlacardDemo project.

Installation of Placard

To play with Placard via the demo interface, see the section above. But if you want to use Placard in your own projects, download Placard either via the Swift Package Manager or manually:

Using Swift Package Manager:

Go to File | Swift Packages | Add Package Dependency... in Xcode and search for "Placard".

From the Swift Package Index:

Get Placard from the Swift Package Index

Usage

Using Placard is straight forward, but it helps to know that Placard is composed of three views that you can use:

  1. PlacardPriorityView: a simple, built-in way to display status messages based on priorities.
  2. PlacardView: Another built-in type, but more configurable than PlacardPriorityView and without priorities.
  3. PlacardCustomView: Placard will take your SwiftUI view and display it as a Placard!

Configuration

Placard types take a configuration of type PlacardConfig that you can use to alter the behavior, placement, and formatting of a Placard view. A configuration is not necessary, but allows you to customize your Placards.

The protocol for a Placard configuration is PlacardConfigP:

public protocol PlacardConfigP {
    var backgroundColor: UIColor? { get }
    var primaryFont: UIFont? { get }
    var secondaryFont: UIFont? { get }
    var accentColor: UIColor? { get }
    var titleTextColor: UIColor? { get }
    var placement: PlacardPlacement? { get }
    var insets: UIEdgeInsets? { get }
    var showAnimation: TransitionAnimation? { get }
    var hideAnimation: TransitionAnimation? { get }
    var tapAnimation: TapAnimation? { get }
    var fadeAnimation: Bool? { get }
}

Here is a description of those properties:

Configuration Property Description
backgroundColor Background color (as a UIColor) for the Placard view
primaryFont The font for the title
secondaryFont The font for the status message
accentColor Accent color (as a UIColor) for the Placard view (used for the status message foreground)
titleTextColor Color (as a UIColor) used for the Placard view title and systemImage foreground colors
placement Where to position the Placard view on the device screen
insets UIEdgeInsets used to offset a Placard view from its PlacardPlacement
showAnimation The animation to be used when the Placard view appears
hideAnimation The animation to be used when the Placard view disappears
tapAnimation The animation to be used when the Placard view is tapped by the user
fadeAnimation When true, the show and hide animations will fade in or out, respectively

In the example below, all available configuration options are being set:

let config = PlacardConfig(backgroundColor: .darkGray,
                            primaryFont: UIFont.systemFont(ofSize: 30.0, weight: .heavy),
                            secondaryFont: UIFont.systemFont(ofSize: 16.0, weight: .regular),
                            accentColor: .red,
                            titleTextColor: .yellow,
                            placement: .top,
                            insets: UIEdgeInsets(top: 50, left: 20, bottom: 0, right: 20),
                            showAnimation: .spin,
                            hideAnimation: .fade,
                            tapAnimation: .pulseIn,
                            fadeAnimation: true)

Two of these properties, Insets and Animations, require a bit more elaboration:

Insets

UIEdgeInsets used to offset a Placard view from its PlacardPlacement. Keep in mind that UIEdgeInsets.left and UIEdgeInsets.right act to "push" the Placard view away from the edges of the device screen (allowing the user to create a Placard that does not span the screen). Also, all values should be positive offsets - a value for UIEdgeInsets.top of 50 will push a Placard view 50 points from the top of the device (regardless of its orientation). A value for UIEdgeInsets.bottom of 50 will push a Placard view 50 points from the bottom of the device (toward the center).

Note that for:
- PlacardPlacement.top - UIEdgeInsets.bottom is ignored
- PlacardPlacement.bottom - UIEdgeInsets.top is ignored

Animations

Transition Animations

These are the types of the animated transitions that occur on show and hide of placard. The available options are:

public enum TransitionAnimation {
    case none, fade, rollUp, rollDown, floatUp, floatDown, floatLeft, floatRight, toX, toY, toPoint, spin, spinOnX, spinOnY
}
Examples of transition animations
Tap Animations

These are the animations that occur when a user taps on placard (follow by action completion and dismissal of the Placard). The available options are:

public enum TapAnimation {
    case none, pulseIn, pulseOut, zoomInWithEasing, zoomOutWithEasing
}
Examples of tap animations

Its a bit difficult to see the differences via animated gifs, but play with the PlacardDemo app to see these more clearly.

Zoom out, ease in:

Zoom in, ease out:

Pulse out:

Pulse in:


Another way to use a configuration - use an enumeration. This is basically the same as using a PlacardConfig instance, but you can define a configuration type (conforming to PlacardConfigP) and pass that in instead.

    enum Custom: PlacardConfigP {
        // the type we are defining
        case terminal

        var backgroundColor: UIColor? {
            switch self { case .terminal: return .lightGray }
        }

        var accentColor: UIColor? {
            switch self {
            case .terminal: return .purple
            }
        }

        var primaryFont: UIFont? {
            switch self {
            case .terminal: return UIFont(name: "HelveticaNeue-Light", size: 24.0)
            }
        }

        var secondaryFont: UIFont? {
            switch self {
            case .terminal: return UIFont(name: "HelveticaNeue-Light", size: 16.0)
            }
        }

        var titleTextColor: UIColor? {
            switch self { case .terminal: return .green }
        }

        var placement: PlacardPlacement? {
            switch self { default: return .center }
        }

        var insets: UIEdgeInsets? {
            switch self { default: return UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20) }
        }

        var showAnimation: TransitionAnimation? {
            switch self { default: return .spinOnX }
        }

        var hideAnimation: TransitionAnimation? {
            switch self { default: return .spinOnY }
        }

        var tapAnimation: TapAnimation? {
            switch self { default: return .zoomOutWithEasing }
        }

        var fadeAnimation: Bool? {
            switch self { default: return true }
        }
    }

It would be used like this:

    PlacardView(
        title: "You Dawg!",
        statusMessage: "Git that squeaky!",
        systemImageName: "pawprint",
        config: Custom.terminal
    )

PlacardPriorityView types are built-in Placards that are intended to be used for priority-based user status messages. You can alter the tile and body of the message, as well as the image via PlacardPriorityView's parameters. You can also pass in your own configuration to change a bunch more (see the configuration section above). But these are meant to be quick and easy representations of status.

You can alter any of the following parameters, but only title and statusMessage are required.

Parameter Type Description
title String Title of the Placard
statusMessage String Status message of the Placard
systemImageName String Name of the system image (SF Symbol) to use as an icon
config PlacardConfig A configuration file (see the section above)
duration Double Number of seconds for the Placard to display
action () -> Void An action to execute on Placard being tapped by user
priority PlacardPriority .success, .info, .warning, .error, or a .default priority

Here, we create a success message with our own title and status message:

PlacardPriorityView(title: "Success!", 
                    statusMessage: "Some status message", 
                    priority: .success)

The PlacardView type is similar to the PlacardPriorityView type, but has no priority associated with it. It can be customized in the same ways.

Its available set of parameters is:

Parameter Type Description
title String Title of the Placard
statusMessage String Status message of the Placard
systemImageName String Name of the system image (SF Symbol) to use as an icon
config PlacardConfig A configuration file (see the section above)
duration Double Number of seconds for the Placard to display
action () -> Void An action to execute on Placard being tapped by user

Here, we pass in our own systemImage to display:

    PlacardView(title: "Don't forget to smile!",
                statusMessage: "Teeth are like bats that hang from your gums.",
                systemImageName: "mouth.fill")

Placards take an action (of type () -> Void) to perform when tapped (ONLY if tapped - if you set a duration and the Placard expires before a user taps it, the action will not be fired).

PlacardView(title: "Don't forget to smile!",
            statusMessage: "Teeth are like bats that hang from your gums.",
            systemImageName: "face.smiling",
            action: { print("You tapped me!") })

When you want to provide your own SwiftUI views while using Placard's functionality, you will use the PlacardCustomView.

The set of available parameters for a PlacardCustomView is:

Parameter Type Description
title String Title of the Placard
statusMessage String Status message of the Placard
content UIView Your SwiftUI view
config PlacardConfig A configuration file (see the section above)
duration Double Number of seconds for the Placard to display
action () -> Void An action to execute on Placard being tapped by user

Define your own SwiftUI view to use as a Placard. Here is an example:

    struct ViewWithButton: View {
        @State var action: Bool

        var body: some View {
            var color: String {
                if action { return "red" }
                return "green"
            }

            VStack {
                Text("Make me see \\(color)")
                    .background(action ? .green : .red)
                Button(action: {
                    action.toggle()
                }) {
                    HStack {
                        Image(systemName: "face.dashed")
                            .font(.title)
                            .foregroundColor(action ? .green : .red)
                        Text("change me")
                            .fontWeight(.semibold)
                            .font(.title)
                    }
                    .padding()
                    .foregroundColor(.white)
                    .background(Color.black)
                    .cornerRadius(40)
                }
            }
            .frame(maxWidth: .infinity, minHeight: 200, alignment: .center)
            .background(Color(red: 155/255, green: 198/255, blue: 222/255))
        }
    }

Pass that view into a PlacardCustomView instance:

    PlacardCustomView(title: "some title", statusMessage: "some body", config: custom_config) {
        // SwiftUI view
        ViewWithButton(action: toggle)
    }

Description

  • Swift Tools 5.9.0
View More Packages from this Author

Dependencies

  • None
Last updated: Mon May 19 2025 13:08:32 GMT-0900 (Hawaii-Aleutian Daylight Time)