Quantcast
Channel: FlexMonkey
Viewing all articles
Browse latest Browse all 257

A Marking Menu Component for iOS in Swift

$
0
0

My first exposure to marking menus was using Alias|Wavefront software for 3D modelling and animation many moons ago. Marking menus are an advanced form of radial menus whereby the user performs a continuous gesture to navigate through and select items from a hierarchical menu. After some use, the gesture itself becomes synonymous with a menu selection.

Alias|Wavefront's software has now evolved into Autodesk's Maya where marking menus are still used throughout the application. 

As iOS evolves into an operating system suited to richer applications for content creation and with rumours of a larger iPad continuing to rumble, I'm thinking more and more about more advanced user interface solutions. So, this got me wondering, if marking menus are a great solution for high-end desktop software, could they be just as good for iOS apps? 

Turns out, they work really well - at least for iPad.

I've spent some time creating FMMarkingMenu (FM for Flex Monkey) - an easy to implement marking menu component for iOS. FMMarkingMenu is an open source project written in Swift and comes bundled with a demo iPad app (above). The app allows the user to navigate through some Core Image filter categories and select a filter which is applied to a background image. 

The implementation is super easy. First of all, I created my menu structure. This is an array of FMMarkingMenuItem instances. Each instance has a label and, optionally, an array of sub items. For example, to create a menu with a top level item labelled No Filter and a sub-menu labelled Blur & Sharpen, the menu structure would look like:

    let noFilter = FMMarkingMenuItem(label: "No Filter")
    
    let blur = FMMarkingMenuItem(label: "Blur & Sharpen", subItems:[FMMarkingMenuItem(label: "CIGaussianBlur"), FMMarkingMenuItem(label: "CISharpenLuminance"), FMMarkingMenuItem(label: "CIUnsharpMask")])

    let markingMenuItems = [blur, noFilter]

Then, create an instance of FMMarkingMenu:

    var markingMenu: FMMarkingMenu!

...and, typically in viewDidLoad(), instantiate the instance with references to the target view controller, view and the menu structure:

    let markingMenuItems = [blur, colorEffect, distort, photoEffect, halftone, styleize, noFilter, deepMenu]
        

    markingMenu = FMMarkingMenu(viewController: self, view: view, markingMenuItems: markingMenuItems)

To react to changes, FMMarkingMenu has a delegate protocol, FMMarkingMenuDelegate which contains one function:

    func FMMarkingMenuItemSelected(markingMenu: FMMarkingMenu, markingMenuItem: FMMarkingMenuItem)

This is invoked whenever the user marks an executable menu item (i.e. one with no sub-items). In my demo application, the view controller is the delegate and its implementation of this method looks like this:

    func FMMarkingMenuItemSelected(markingMenu: FMMarkingMenu, markingMenuItem: FMMarkingMenuItem)
    {
        let filters = (CIFilter.filterNamesInCategories(nil) ?? [AnyObject]()).filter({ $0 as! String ==  markingMenuItem.label})
        
        if filters.count != 0
        {
            imageView.image = applyFilter(photo, filterName: markingMenuItem.label)
        }
        else
        {
            imageView.image = photo
        }
        
        currentFilterLabel.text = markingMenuItem.label
        currentFilterLabel.frame = CGRect(x: 5,
            y: view.frame.height - currentFilterLabel.intrinsicContentSize().height - 5,
            width: currentFilterLabel.intrinsicContentSize().width,
            height: currentFilterLabel.intrinsicContentSize().height)

    }

That's all there is to it. FMMarkingMenu attaches a gesture recogniser to the view that it's passed in its constructor and whenever the user touches that view, the menu pops up. 

The Swift 1.2 source code for FMMarkingMenu along with the demo app and references to articles about marking menus is available at my GitHub repository here.

Viewing all articles
Browse latest Browse all 257

Trending Articles