SkillAgentSearch skills...

SwiftMessages

A very flexible message bar for UIKit and SwiftUI.

Install / Use

/learn @SwiftKickMobile/SwiftMessages
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

SwiftMessages

Twitter: @TimothyMoose Version License Platform Carthage compatible

<p align="center"> <img src="./Design/swiftmessages.png" /> </p>

Overview

🔥🔥🔥 UPDATE SwiftUI support in in Xcode 26 requries 10.0.2!

SwiftMessages is a very flexible view and view controller presentation library for UIKit and SwiftUI.

Message views and view controllers can be displayed at the top, bottom, or center of the screen, or behind navigation bars and tab bars. There are interactive dismiss gestures including a fun, physics-based one. Multiple background dimming modes. And a lot more!

In addition to the numerous configuration options, SwiftMessages provides several good-looking layouts and themes. But SwiftMessages is also designer-friendly, which means you can fully and easily customize the view:

  • Copy one of the included nib files into your project and change it.
  • Subclass MessageView and add elements, etc.
  • Or just supply an arbitrary instance of View or UIView.
<p align="center"> <img src="./Demo/demo.png" /> </p>

Installation

Swift Package Manager

Go to File | Swift Packages | Add Package Dependency... in Xcode and search for "SwiftMessages". If multiple results are found, select the one owned by SwiftKick Mobile.

CocoaPods

Add the following line to your Podfile:

pod 'SwiftMessages'

Carthage

Add the following line to your Cartfile:

github "SwiftKickMobile/SwiftMessages"

If the Carthage build fails, try using the script.

Manual

  1. Put SwiftMessages repo somewhere in your project directory.
  2. In Xcode, add SwiftMessages.xcodeproj to your project.
  3. On your app's target, add the SwiftMessages framework:
    1. as an embedded binary on the General tab.
    2. as a target dependency on the Build Phases tab.

Usage

Basics

SwiftMessages.show(view: myView)

Although you can show any instance of UIView, SwiftMessages provides a MessageView class and assortment of nib-based layouts that should handle most cases:

// Instantiate a message view from the provided card view layout. SwiftMessages searches for nib
// files in the main bundle first, so you can easily copy them into your project and make changes.
let view = MessageView.viewFromNib(layout: .cardView)

// Theme message elements with the warning style.
view.configureTheme(.warning)

// Add a drop shadow.
view.configureDropShadow()

// Set message title, body, and icon. Here, we're overriding the default warning
// image with an emoji character.
let iconText = ["🤔", "😳", "🙄", "😶"].randomElement()!
view.configureContent(title: "Warning", body: "Consider yourself warned.", iconText: iconText)

// Increase the external margin around the card. In general, the effect of this setting
// depends on how the given layout is constrained to the layout margins.
view.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)

// Reduce the corner radius (applicable to layouts featuring rounded corners).
(view.backgroundView as? CornerRoundingView)?.cornerRadius = 10

// Show the message.
SwiftMessages.show(view: view)

You may wish to use the view provider variant show(viewProvider:) to ensure that your UIKit code is executed on the main queue:

SwiftMessages.show {
    let view = MessageView.viewFromNib(layout: .cardView)
    // ... configure the view
    return view
}

The SwiftMessages.Config struct provides numerous configuration options that can be passed to show():

var config = SwiftMessages.Config()

// Slide up from the bottom.
config.presentationStyle = .bottom

// Display in a window at the specified window level.
config.presentationContext = .window(windowLevel: .statusBar)

Note that, as of iOS 13, it is no longer possible to cover the status bar
regardless of the window level. A workaround is to hide the status bar instead.
config.prefersStatusBarHidden = true

// Disable the default auto-hiding behavior.
config.duration = .forever

// Dim the background like a popover view. Hide when the background is tapped.
config.dimMode = .gray(interactive: true)

// Disable the interactive pan-to-hide gesture.
config.interactiveHide = false

// Specify haptic feedback (see also MessageView/configureTheme)
config.haptic = .success

// Specify a status bar style to if the message is displayed directly under the status bar.
config.preferredStatusBarStyle = .lightContent

// Specify one or more event listeners to respond to show and hide events.
config.eventListeners.append() { event in
    if case .didHide = event {
        print("yep id=\(String(describing: event.id)")
    }
}

SwiftMessages.show(config: config, view: view)

Specify default configuration options:

SwiftMessages.defaultConfig.presentationStyle = .bottom

// Show message with default config.
SwiftMessages.show(view: view)

// Customize config using the default as a base.
var config = SwiftMessages.defaultConfig
config.duration = .forever
SwiftMessages.show(config: config, view: view)

View Controllers

SwiftMessages can present view controllers using the SwiftMessagesSegue custom modal segue!

<p align="center"> <img src="./Design/SwiftMessagesSegue.gif" /> </p>

SwiftMessagesSegue is a subclass of UIStoryboardSegue that integrates directly into Interface Builder as a custom modal segue, enabling view controllers to take advantage of SwiftMessages layouts, animations and more. SwiftMessagesSegue works with any UIKIt project — storyboards are not required. Refer to the View Controllers readme below for more information.

View Controllers Readme

And check out our blog post Elegant Custom UIViewController Transitioning to learn a great technique you can use to build your own custom segues that utilize UIViewControllerTransitioningDelegate and UIViewControllerAnimatedTransitioning.

SwiftUI

Any of the built-in SwiftMessages views can be displayed by calling the SwiftMessages APIs from within observable object, a button action closure, etc. However, SwiftMessages can also display your custom SwiftUI views.

Presentation

Take the following message view and companion data model:

struct DemoMessage: Identifiable {
    let title: String
    let body: String

    var id: String { title + body }
}

struct DemoMessageView: View {

    let message: DemoMessage

    var body: some View {
        VStack(alignment: .leading) {
            Text(message.title).font(.system(size: 20, weight: .bold))
            Text(message.body)
        }
        .multilineTextAlignment(.leading)
        .padding(30)
        // This makes the message width greedy
        .frame(maxWidth: .infinity)
        .background(.gray)
        // This makes a tab-style view where the bottom corners are rounded and
        // the view's background extends to the top edge.
        .mask(
            UnevenRoundedRectangle(bottomLeadingRadius: 15, bottomTrailingRadius: 15)
            // This causes the background to extend into the safe area to the screen edge.
            .edgesIgnoringSafeArea(.top)
        )
    }
}

You can show it from a button action, view model or other similar context like:

struct DemoView: View {
    var body: some View {
        Button("Show message") {
            let message = DemoMessage(title: "Demo", body: "SwiftUI forever!")
            let messageView = MessageHostingView(id: message.id, content: DemoMessageView(message: message)
            SwiftMessages.show(view: messageView)
        }
    }
}

But you may also use a state-based approach using the swiftMessage() view modifier:

struct DemoView: View {

    @State var message: DemoMessage?

    var body: some View {
        Button("Show message") {
            message = DemoMessage(title: "Demo", body: "SwiftUI forever!")
        }
        .swiftMessage(message: $message) { message in
            DemoMessageView(message: message)
        }
    }
}

This is very similar to the .sheet() modifier. However, it doesn't expose all of the features of SwiftMessages, such as explicitly hiding messages by ID. It is totally reasonable to use a combination of both approaches.

If your message views are purely data-driven and don't require delegates, callbacks, etc., there is a slightly simplified variation on swiftMessage() that doesn't require a view builder. Instead, your data model should conform to MessageViewConvertible.

extension DemoMessage: MessageViewConvertible {
    func asMessageView() -> DemoMessageView {
        DemoMessageView(message: self)
    }
}

Then you can drop the view builder when calling swiftMessage():

struct DemoView: View {

    @State var message: DemoMessage?

    var body: some View {
        Button("Show message") {
            message = DemoMessage(title: "Demo", body: "SwiftUI forever!")
        }
        .swiftMessage(message: $message)
    }
}

Dismissal

SwiftMessages provides several approaches for dismissing messages from within SwiftUI views.

For messages shown using the `swiftMessage(

View on GitHub
GitHub Stars7.6k
CategoryDevelopment
Updated1d ago
Forks763

Languages

Swift

Security Score

100/100

Audited on Mar 27, 2026

No findings