kevin-lyn
STPopup
Objective-C

STPopup provides STPopupController, which works just like UINavigationController in popup style, for both iPhone and iPad. It's written in Objective-C and compatible with Swift.

Last updated Jun 27, 2026
2.6k
Stars
344
Forks
68
Issues
0
Stars/day
Attention Score
72
Language breakdown
No language data available.
โ–ธ Files click to expand
README

STPopup CI Status Version License

STPopup provides STPopupController, which works just like UINavigationController in popup style, for both iPhone and iPad. It's written in Objective-C and compatible with Swift.

Features:

  • Push/Pop view controller into/out of STPopupController just like UINavigationController.
  • Set navigation items through self.navigationItem just like using a UINavigationController.
  • Support both "Form Sheet" and "Bottom Sheet" style.
  • Work well with storyboard(including segue).
  • Customize UI by using UIAppearance.
  • Customizable popup transition style.
  • Auto-reposition of popup view when keyboard shows up, make sure your UITextField/UITextView won't be covered by the keyboard.
  • Drag navigation bar to dismiss popup view.
  • Support both portrait and landscape orientation in iPhone and iPad.
  • iOS 7+.
  • Compatible with Swift.

Use Cases

Use Cases

Get Started

CocoaPods
pod 'STPopup'
Carthage
github "kevin0571/STPopup"
Import header file Objective-C
#import <STPopup/STPopup.h>
Swift
import STPopup

Initialize and present STPopupController Objective-C

STPopupController *popupController = [[STPopupController alloc] initWithRootViewController:viewController]; [popupController presentInViewController:self];
Swift
let popupController = STPopupController(rootViewController: viewController) popupController.present(in: self)

Set content size in view controller Objective-C

@implementation ViewController

  • (instancetype)init
{ if (self = [super init]) { self.title = @"View Controller"; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Next" style:UIBarButtonItemStylePlain target:self action:@selector(nextBtnDidTap)]; // It's required to set content size of popup. self.contentSizeInPopup = CGSizeMake(300, 400); self.landscapeContentSizeInPopup = CGSizeMake(400, 200); } return self; }

@end

Swift
class ViewController: UIViewController {     override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {         super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)         title = "View Controller"         navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(nextBtnDidTap))         // It's required to set content size of popup.         contentSizeInPopup = CGSize(width: 300, height: 400)         landscapeContentSizeInPopup = CGSize(width: 400, height: 200)     } }
Set content size of view controller which is loaded from Storyboard Set content size in storyboard or in awakeFromNib. Storyboard

Push, pop and dismiss view controllers Objective-C

[self.popupController pushViewController:[ViewController new] animated:YES]; [self.popupController popViewControllerAnimated:YES]; // Popup will be dismissed if there is only one view controller in the popup view controller stack [self.popupController dismiss];
Swift
popupController?.push(viewController, animated: true) popupController?.popViewController(animated: true) // Popup will be dismissed if there is only one view controller in the popup view controller stack popupController?.dismiss()

Push & Pop

Bottom sheet style Objective-C

STPopupController *popupController = [[STPopupController alloc] initWithRootViewController:[ViewController new]]; popupController.style = STPopupStyleBottomSheet; [popupController presentInViewController:self];
Swift
let popupController = STPopupController(rootViewController: viewController) popupController.style = .bottomSheet popupController.present(in: self)
Bottom Sheet

Customize popup transition style Objective-C

#pragma mark - STPopupControllerTransitioning

  • (NSTimeInterval)popupControllerTransitionDuration:(STPopupControllerTransitioningContext *)context
{ return context.action == STPopupControllerTransitioningActionPresent ? 0.5 : 0.35; }
  • (void)popupControllerAnimateTransition:(STPopupControllerTransitioningContext *)context completion:(void (^)())completion
{ // Popup will be presented with an animation sliding from right to left. UIView *containerView = context.containerView; if (context.action == STPopupControllerTransitioningActionPresent) { containerView.transform = CGAffineTransformMakeTranslation(containerView.superview.bounds.size.width - containerView.frame.origin.x, 0); [UIView animateWithDuration:[self popupControllerTransitionDuration:context] delay:0 usingSpringWithDamping:1 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{ context.containerView.transform = CGAffineTransformIdentity; } completion:^(BOOL finished) { completion(); }]; } else { [UIView animateWithDuration:[self popupControllerTransitionDuration:context] delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ containerView.transform = CGAffineTransformMakeTranslation(- 2 * (containerView.superview.bounds.size.width - containerView.frame.origin.x), 0); } completion:^(BOOL finished) { containerView.transform = CGAffineTransformIdentity; completion(); }]; } }

// Use custom transitioning in popup controller STPopupController *popupController = [[STPopupController alloc] initWithRootViewController:viewController]; popupController.transitionStyle = STPopupTransitionStyleCustom; popupController.transitioning = self; [popupController presentInViewController:self];

Swift
// MARK: STPopupControllerTransitioning

func popupControllerTransitionDuration(_ context: STPopupControllerTransitioningContext) -> TimeInterval { return context.action == .present ? 0.5 : 0.35 }

func popupControllerAnimateTransition(_ context: STPopupControllerTransitioningContext, completion: @escaping () -> Void) { // Popup will be presented with an animation sliding from right to left. let containerView = context.containerView if context.action == .present { containerView.transform = CGAffineTransform(translationX: containerView.superview!.bounds.size.width - containerView.frame.origin.x, y: 0) UIView.animate(withDuration: popupControllerTransitionDuration(context), delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseInOut, animations: { containerView.transform = .identity }, completion: { _ in completion() }); } else { UIView.animate(withDuration: popupControllerTransitionDuration(context), delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseInOut, animations: { containerView.transform = CGAffineTransform(translationX: -2 * (containerView.superview!.bounds.size.width - containerView.frame.origin.x), y: 0) }, completion: { _ in containerView.transform = .identity completion() }); } }

// Use custom transitioning in popup controller let popupController = let popupController = STPopupController(rootViewController: viewController) popupController.transitionStyle = .custom popupController.transitioning = self popupController.present(in: self)

Blur background Objective-C

STPopupController *popupController = [[STPopupController alloc] initWithRootViewController:[PopupViewController1 new]]; if (NSClassFromString(@"UIBlurEffect")) {     UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];     popupController.backgroundView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; }
Swift
let popupController = let popupController = STPopupController(rootViewController: viewController) if NSClassFromString("UIBlurEffect") != nil {     let blurEffect = UIBlurEffect(style: .dark)     popupController.backgroundView = UIVisualEffectView(effect: blurEffect) }

Action of tapping on area outside of popup Objective-C

[popupController.backgroundView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(backgroundViewDidTap)]];
Swift
popupController.backgroundView?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(backgroundViewDidTap)))

Customize UI Objective-C

[STPopupNavigationBar appearance].barTintColor = [UIColor colorWithRed:0.20 green:0.60 blue:0.86 alpha:1.0]; [STPopupNavigationBar appearance].tintColor = [UIColor whiteColor]; [STPopupNavigationBar appearance].barStyle = UIBarStyleDefault; [STPopupNavigationBar appearance].titleTextAttributes = @{ NSFontAttributeName: [UIFont fontWithName:@"Cochin" size:18], NSForegroundColorAttributeName: [UIColor whiteColor] };      [[UIBarButtonItem appearanceWhenContainedIn:[STPopupNavigationBar class], nil] setTitleTextAttributes:@{ NSFontAttributeName:[UIFont fontWithName:@"Cochin" size:17] } forState:UIControlStateNormal];
Swift
STPopupNavigationBar.appearance().barTintColor = UIColor(red: 0.2, green: 0.6, blue: 0.86, alpha: 1) STPopupNavigationBar.appearance().tintColor = .white STPopupNavigationBar.appearance().barStyle = .default STPopupNavigationBar.appearance().titleTextAttributes = [     .font: UIFont(name: "Cochin", size: 18) ?? .systemFont(ofSize: 18),     .foregroundColor: UIColor.white, ] UIBarButtonItem     .appearance(whenContainedInInstancesOf: [STPopupNavigationBar.self])     .setTitleTextAttributes([         .font: UIFont(name: "Cochin", size: 18) ?? .systemFont(ofSize: 18),         ], for: .normal)
Customize UI

Auto-reposition when keyboard is showing up This is default behavior. Auto-reposition

Drag to dismiss This is default behavior. Drag to dismiss

Handle orientation change This is default behavior. Orientation change

Please checkout the example project for more details.

ยฉ 2026 GitRepoTrend ยท kevin-lyn/STPopup ยท Updated daily from GitHub