SkillAgentSearch skills...

LNPopupController

A framework for presenting view controllers as popups of other view controllers, much like the Apple Music and Podcasts apps.

Install / Use

/learn @LeoNatan/LNPopupController
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

LNPopupController

LNPopupController is a framework for presenting view controllers as popups of other view controllers, similar to the Apple Music and Podcasts mini-players.

For SwiftUI, check out the LNPopupUI library.

GitHub release GitHub stars GitHub license <span class="badge-paypal"><a href="https://paypal.me/LeoNatan25" title="Donate to this project using PayPal"><img src="https://img.shields.io/badge/paypal-donate-yellow.svg?style=flat" alt="PayPal Donation Button" /></a></span>

GitHub issues GitHub contributors Swift Package Manager compatible Carthage compatible

<p align="center"><img style="border: 1px solid #555555;" src="./Supplements/intro.gif"/></p>

Once a popup bar is presented with a content view controller, the user can swipe or tap the popup bar present the popup, interact with the popup content and dismiss the popup by either swiping down or tapping the popup close button.

The framework is intended to be very generic and work in most situations, so it is implemented as a category over UIViewController. Each view controller can present a popup bar, docked to a bottom view. For UITabBarController and its subclasses, the default docking view is the tab bar. For UINavigationController and its subclasses, the default docking view is the toolbar. For other view controllers, the popup bar is presented at the bottom of the screen. View controller subclasses can provide their own docking views.

The framework correctly maintains the safe area insets of the container controller’s view and its child controllers, as the popup bar is presented and dismissed.

The information displayed on the popup bar is provided dynamically with popup item objects (instances of the LNPopupItem class) associated with the popup content view controllers. To change this information, update the popup item of the view controller.

Generally, it is recommended to present the popup bar on the outermost container controller. So if you have a view controller contained in a navigation controller, which is in turn contained in a tab bar controller, it is recommended to present the popup bar on the tab bar controller.

Check the demo project for many common use cases of the framework in various scenarios. It contains examples in Swift and Objective C.

[!TIP] To run the example project, don't forget to update submodules by running: git submodule update --init --recursive

Features

  • Supports iOS 26 glass design, while maintaining an appropriate look and feel on previous iOS versions
  • Available for iOS 13 and later, as an SPM package for Swift and Objective C
  • Good citizen in modern UIKit world
  • For SwiftUI, check out the LNPopupUI library

Adding to Your Project and Using the Framework

Swift Package Manager

LNPopupController supports SPM versions 6.0 (Xcode 16) and later. In Xcode, click FileAdd Package Dependencies…, enter https://github.com/LeoNatan/LNPopupController. Select the version you’d like to use.

You can also manually add the package to your Package.swift file:

.package(url: "https://github.com/LeoNatan/LNPopupController.git", from: "4.0.0")

And the dependency in your target:

.target(name: "MyExampleApp", dependencies: ["LNPopupController"]),

Import the module in your source files:

import LNPopupController

Managing a Popup Presentation

A popup presentation consists of the following concepts:

  • Popup container controller —the UIViewController that hosts the popup presentation. Normally this is the outer-most tab bar or navigation controller, but can be any UIViewController, including a custom container with its own custom bottom bar.
  • Popup content controller—a UIViewController that represents the content, when the popup is open.
  • Popup bar—a bar, docked to the bottom of the container controller’s view, either above the container’s bottom bar or directly at the bottom of the screen, presenting at-a-glance information to the user and allows interaction by the user. Can be a default system popup bar style or a completely custom implementation.
  • Popup items—the source of data that is displayed on the popup bar at any given time.
  • Custom popup bar controller—optional, when presenting a custom popup bar
<picture> <source media="(prefers-color-scheme: dark)" srcset="./Supplements/overview-dark.png"> <source media="(prefers-color-scheme: light)" srcset="./Supplements/overview.png"> <img src="./Supplements/overview.png"> </picture>

To start a popup presentation, there are two modes of operation that you can choose: the first, content controller as popup item source, is simpler and easier to implement, but does not allow popup item paging; the second, developer-provided popup item data source, is more robust, allows popup item paging, but requires more tought in how to route information in your app.

Mode 1: Content Controllers as Popup Item Source (Default, Easier)

In this mode, your content controller is the source of the popup item to display on the popup bar. Create a content controller, update its popup item and present the bar using presentPopupBar(with:animated:completion:).

class PopupContentViewController: UIViewController {
  init() {
    // ...
    
    popupItem.title = "Hello Title"
    popupItem.subtitle = "And a Subtitle!"
    popupItem.progress = 0.34
    popupItem.barButtonItems = [/* ... */]
  }
}

func presentPopupBar() {
  let contentVC = PopupContentViewController()
  tabBarController?.presentPopupBar(with: contentVC)
}

Each popup content controller manages its own popup item and is responsible to keep its information up to date. Updates to popup items are tracked, and the popup bar is automatically updated with the latest information. You can present a new content controller while the popup bar is presented or even when the popup itself is open; the popup bar will update its content with the new content controller's popup item and the content view will update with the new controller's view hierarchy.

Mode 2: Popup Item Data Source (Advanced)

In this mode, you provide a data source to the popup bar, which can provide one or more popup items. This decouples the popup item from the content controller and allows for more advanced scenarios, such as popup item paging. You activate this mode by setting popup bar's usesContentControllersAsDataSource to false.

Before presenting a content controller, you must either provide an initial popup item or set the popup bar's data source and implement the data source protocol's initialPopupItem(for:) optional method. The system will use this popup item for popup bar presentation. Updates to popup items are tracked, and the popup bar is automatically updated with the latest information.

At any point, you can set the popup bar's popupItem with a new popup item. Whenever a popup bar's popup item changes, the UIViewController.popupItemDidChange(_:) method is called to let the content controller know its popup item has changed.

class PopupContentViewController: UIViewController {
  // ...

  override func popupItemDidChange(_ previousPopupItem: LNPopupItem?) {
    // Handle updating the content view hierarchy with the new popup item
    // or update self.popupItem as needed.
  }
}

class PopupContainerController: UIViewController {
  // ...

  func presentPopupBar() {
    tabBarController?.popupBar.usesContentControllersAsDataSource = false
    
    let initialPopupItem = LNPopupItem()
    initialPopupItem.title = "Hello Title"
    initialPopupItem.subtitle = "And a Subtitle!"
    initialPopupItem.progress = 0.34
    initialPopupItem.barButtonItems = [/* ... */]
    
    tabBarController?.popupBar.popupItem = initialPopupItem
    
    let contentVC = PopupContentViewController()
    tabBarController?.presentPopupBar(with: contentVC)
  }
}

Popup Item Paging

In this mode, the popup bar allows the user to page between different popup items by swiping on the title views.

<p align="center"><img style="border: 1px solid #555555;" src="./Supplements/floating_paging.gif" width="414"/></p>

To implement, you must set the popup bar's data source, and in it, implement both popupBar(_:popupItemBefore:) and popupBar(_:popupItemAfter:) data source protocol methods. Optionally, you can also set a popup bar delegate and implement popupBar(_:didDisplay:previous:) to be notified when a new popup item is displayed (in addition to the popup content controller's UIViewController.popupItemDidChange(_:) call).

func presentPopupBar() {
  // ...
  tabBarController?.popupBar.dataSource = self.model
  tabBarController?.popupBar.delegate = self
  // ...
}

// MARK: LNPopupDataSource

func popupBar(_ popupBar: LNPopupBar, popupItemBefore popupItem: LNPopupItem) -> LNPopupItem? {
  // Return a popop item representing the content before `popupItem` or `nil`
}

func popupBar(_ popupBar: LNPopupBar, popupItemAfter popupItem:

Related Skills

View on GitHub
GitHub Stars3.1k
CategoryDevelopment
Updated10h ago
Forks340

Languages

Objective-C++

Security Score

100/100

Audited on Mar 31, 2026

No findings