PopMenu

PopMenu is designed as a quick popup action menu, much like an action sheet in iOS. If you want an action sheet that looks great, you're in the right place!

popmenu_banner

PopMenu has the abilities of:

  • Automatically position menu on screen if you specify the source view, like a popup. (edge detection)

  • Full customization (icons, fonts, colors, background, styles, corners, height, status bar... you name it).

  • Pan gesture control. (like 3D touch shortcuts on apps in home screen)

  • Haptics enabled for selection or pan gesture.

? Demo / Example

Download or fork the repo and open the given Example Xcode project to try it out yourself!

What's a better way to know what PopMenu offers than some screenshots? Here's some to show you what you can do with PopMenu:

Demo1
Demo2
Demo3
Demo4

⚙️ Installation

For CocoaPods

Install PopMenu using CocoaPods, add it to your Podfile:

‼️ PopMenu was actually taken so let's call it NewPopMenu 'cause why not?

pod 'NewPopMenu'
Ruby

For Carthage

Install PopMenu using Carthage, add it to your Cartfile:

github "CaliCastle/PopMenu"
Ruby

⚠️ Requirements

  • Xcode 8.0 +
  • iOS 9.0 +
  • Swift 4.0 +

??‍? How to Use

Integrating PopMenu is extremely easy with a familiar workflow like presenting UIAlertController with UIAlertAction

Import Library

import PopMenu
Swift

Basic Usage

There are 2 ways to present the menu in your view controller:

  1. Use the default manager

  2. Use the PopMenuViewController class directly

You can, however, choose either way to have the same result, whichever works best for you.

Which Should I Use?

  1. Use the default manager if you want quick setup and present menu seamlessly.

  2. Use the PopMenuViewController class directly if you want to have more control.

If you don't want to scroll, click the link to jump forward:

Basic Usage - Using Manager

Basic Usage - Using Controller


Basic Usage - Using Manager

The quickest way would be to use PopMenuManager's default singleton with no additional setup required:

let manager = PopMenuManager.default
Swift

Add actions if you're using the manager:

manager.actions = [
    PopMenuDefaultAction(title: "Action Title 1"), // Text only action
    PopMenuDefaultAction(title: "Action Title 2", image: UIImage(named: "icon") // Text and image action
]
Swift

Or if you prefer the good ol' way similar to presenting a UIAlertController with UIAlertAction, you can add each action like that:

let action1 = PopMenuDefaultAction(title: "Action Title 1", image: UIImage(named: "icon"))
let action2 = PopMenuDefaultAction(title: "Action Title 2", image: UIImage(named: "icon"))

manager.addAction(action1)
manager.addAction(action2)
Swift

That's how you set the actions for the menu.

Now all you have to do is to simply call present() on the manager, either pass the view controller in the on argument or PopMenuManager will automatically fetch the current top view controller to present the menu on top:

// Show menu without specifying which controller
manager.present()

// Or you can specify the controller to present on
manager.present(on: self)
Swift

Both should work just fine, but still, using manager.present(on: ...) manually would be a safer way to go for presenting.


Basic Usage - Using Controller

If you are using PopMenuManager to handle PopMenu, you can skip this section.

Manually initialize the controller:

let menuViewController = PopMenuViewController()
Swift

Add actions inside the initializer:

let menuViewController = PopMenuViewController(actions: [
    PopMenuDefaultAction(title: "Action Title 1", image: UIImage(named: "icon"),
    PopMenuDefaultAction(title: "Action Title 2", image: UIImage(named: "icon")
])
Swift

Finally, to present the menu all you have to do is call present method in your ViewController like a normal view controller:

class ViewController: UIViewController {

...
    func presentMenu() {
        let menuViewController = PopMenuViewController(actions: [
            PopMenuDefaultAction(title: "Action Title 1", image: UIImage(named: "icon"),
            PopMenuDefaultAction(title: "Action Title 2", image: UIImage(named: "icon")
        ])

        present(menuViewController, animated: true, completion: nil)
    }
...

}
Swift

Source View

By default, PopMenu will present in the center of your screen. If you want it to display on the relative position of a view that the user tapped, you can pass the source view in like this:

class ViewController: UIViewController {

    @IBOutlet var aButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        aButton.addTarget()
    }

    @objc private func presentMenu() {
        // The manager way
        let manager = PopMenuManager.default
        manager.actions = [...]
        
        // Pass the UIView in present method
        manager.present(sourceView: aButton)


        // ===== or =====


        // The manual way
        let actions = [...]

        // Pass the UIView in init
        let menu = PopMenuViewController(sourceView: aButton, actions: actions)
        present(menu, animated: true, completion: nil)
    }

}
Swift

Selection Callback

In order to know which action button is tapped, there are two ways of doing that:

  • Action Handler
  • Delegate

Action Handler

Simply pass the handler when instanstiating the action:

let action1 = PopMenuDefaultAction(title: "Action 1", didSelect: { action in
    // action is a `PopMenuAction`, in this case it's a `PopMenuDefaultAction`

    // Print out: 'Action 1 is tapped'
    print("\(action.title) is tapped")
})
Swift

Delegate Method

You'll need to comform to PopMenuViewControllerDelegate protocol and then implement the method popMenuDidSelectItem(at index: Int) in your view controller:

class ViewController: UIViewController {
    
    // Use manager to present menu.
    func presentMenuUsingManager() {
        let manager = PopMenuManager.default

        // Set delegate for callback
        manager.popMenuDelegate = self

        manager.present(on: self)
    }

    // Or manually init:
    func presentMenuManually() {
        let menu = PopMenuViewController(actions: [...])

        // Set delegate for callback
        menu.delegate = self

        present(menu, animated: true, completion: nil)
    }

}

extension ViewController: PopMenuViewControllerDelegate {

    func popMenuDidSelectItem(_ popMenuViewController: PopMenuViewController, at index: Int) {
        // Do stuff here...
    }
    
}
Swift

Dismissal Callback

If you'd want more control to do additional steps when the menu is dismssed, you can do it like this:

// The manager way
manager.popMenuDidDismiss = { selected in
    // `selected` is a bool indicating if a selection has been made

    if !selected {
        // When the user tapped outside of the menu
    }
}
Swift

Configurations

By default, PopMenu has pan gesture enabled, you can toggle it here:

// The manager way
manager.popMenuShouldEnablePanGesture = false
// The manual way
menu.shouldEnablePanGesture = false
Swift

By default, PopMenu has haptics enabled, you can toggle it here:

// The manager way
manager.popMenuShouldEnableHaptics = false
// The manual way
menu.shouldEnableHaptics = false
Swift

That's basically it! Congrats!

If you're a customization lover like me, then read along:


?? Customization

Before moving on, customization should be applied before presenting the menu, and assume that you already have a:

variable of PopMenuManager.default called -> manager.

----- or -----

variable of PopMenuViewController called -> menu.


Action Dismissal // Default: true

If you don't want the menu to auto-dismiss once a selection has been performed, you can change the property:

// The manager way
manager.popMenuShouldDismissOnSelection = false

// The manual way
menu.shouldDismissOnSelection = false
Swift

Background styles // Default: .dimmed(color: .black, opacity: 0.4)

There are mainly 3 types of background styles:

  • Blurred (dark, light & extra Light)
  • Dimmed (color & opacity)
  • None

Simply set the popMenuBackgroundStyle on the appearance property using . notation:

// The manager way
manager.popMenuAppearance.popMenuBackgroundStyle = .blurred(.dark)
manager.popMenuAppearance.popMenuBackgroundStyle = .blurred(.light)
manager.popMenuAppearance.popMenuBackgroundStyle = .blurred(.extralight)
manager.popMenuAppearance.popMenuBackgroundStyle = .dimmed(color: .white, opacity: 0.6)
manager.popMenuAppearance.popMenuBackgroundStyle = .none()

// The manual way, same to the code above
menu.appearance.popMenuBackgroundStyle = .blurred(.dark)
Swift

Action Color // Default: white

To bulk set action colors is simple and straightforward:

// The manager way
manager.popMenuAppearance.popMenuColor.actionColor = UIColor.green // or use Color Literals if you're using Xcode 9

// The manual way
menu.appearance.popMenuColor.actionColor = UIColor.green
Swift

To set each action with different color, you'll have to specify in the color parameter initializer of action PopMenuDefaultAction:

let actions = [
    PopMenuDefaultAction(title: "Some Title", image: UIImage(named: "blah"), color: .gray),
    PopMenuDefaultAction(title: "Another Title", image: UIImage(named: "icon"), color: .yellow)
]
Swift

Background Color(s) // Default: flat black gradient

There are 2 types of background colors:

  • Solid fill (one color)
  • Gradient fill (two colors)

To set the background color(s) of the menu:

// The manager way
manager.popMenuAppearance.popMenuColor.backgroundColor = .solid(fill: .gray) // A solid gray background color
manager.popMenuAppearance.popMenuColor.backgroundColor = .gradient(fill: .yellow, .pink) // A gradient from yellow to pink

// The manual way
menu.appearance.popMenuColor.backgroundColor = ...
Swift

Action Font // Default: .systemFont(ofSize: 16, weight: .semiBold)

To set the font of all actions:

// The manager way
manager.popMenuAppearance.popMenuFont = UIFont(name: "AvenirNext-DemiBold", size: 14)!
manager.popMenuAppearance.popMenuFont = .systemFont(ofSize: 15, weight: .bold)

// The manual way
menu.appearance.popMenuFont = UIFont(name: "AvenirNext-DemiBold", size: 14)!
Swift

Corner Radius // Default: 24

To set corner radius of the menu container:

// The manager way
manager.popMenuAppearance.popMenuCornerRadius = 10

// The manual way
menu.appearance.popMenuCornerRadius = 10
Swift

Action Height // Default: 50

To set height of each action:

// The manager way
manager.popMenuAppearance.popMenuActionHeight = 65

// The manual way
menu.appearance.popMenuActionHeight = 65
Swift

Action Item Separator // Default: none

To set the action item separator:

// The manager way
manager.popMenuAppearance.popMenuItemSeparator = .none()
manager.popMenuAppearance.popMenuItemSeparator = .fill() // Default height of 0.5, white color with 0.5 opacity
manager.popMenuAppearance.popMenuItemSeparator = .fill(.yellow, height: 1) // Or set it yourself

// The manual way
menu.appearance.popMenuItemSeparator = ...
Swift

Status Bar Style // Default: automatic detection based on background color

If you don't want PopMenu to use automatic detection to set status bar style, you can override it:

manager.popMenuAppearance.popMenuStatusBarStyle = .default

// The manual way
menu.appearance.popMenuStatusBarStyle = .default
Swift

More customization coming, stay tuned...

GitHub

A fully customizable popup style menu for iOS 😎Read More

Latest commit to the master branch on 3-12-2024
Download as zip