Today we'll check out a library called Shoyu that aims to make setting up UITableViews a breeze. Let's dive in:
Shoyu works as a sort of DSL. It adds a source property on to UITableView, then gives as a few functions like createSection and createRow to fill the table view with content. Let's see what it takes to add a section and a row:
Today we'll tackle a common question from those beginning to learn iOS development:
"UICollectionView and UITableView seem to overlap in terms of functionality in many ways. When should I use one or the other?"
The practical answer is actually a common idiom when building software: What's the simplest possible solution?
Let's look at the basics of table and collection views, then we'll circle back and learn how we apply that answer to our question.
UITableViews are all about vertically scrolling lists of content. They expect us to use them to display rows of content inside sections. We get a ton of conventional "iOS-native" feeling functionality for free such as group-style table views that look like iOS's settings app or system-standard accessory views.
In short: UITableViews give us a lot for free, but they expect us to think in their terms.
UICollectionViews are infinitely more customizable than Table Views. We can completely customize a collection view'slayout, even animate between layouts.
UICollectionViews don't provide anywhere near as much functionality out of the box, but they offer an incredible amount of power and capability.
In many ways, Collection Views are the more-capable big sister to Table Views. They aren't constrained by "rows" or "accessory views". They are great for simple grids, all the way up to incrediblycomplexlayouts.
Back to our original answer: What's the simplest possible solution?
We can now answer our question by rephrasing it: Given what I'd like to build, will a UITableView or a UICollectionView help me get there faster, with less (or at least simpler) code?
Building a Settings screen or vertical list of social media posts? A UITableView is probably the way to go.
Building a photo gallery, or perhaps a screen that needs to scroll content horizontally? We'll need a UICollectionView for those.
In either case, if we ever start to feel like we're fighting against UIKit, that's a good time to step back and re-evaluate.
It's quite common to need to display short status messages or notifications inside our apps. Today we'll look at a library called Whisper that is absolutely packed with features that make displaying these types of messages both simple and beautiful. Let's dive in.
Whisper provides 3 different types of display styles. All allow for extensive customization including colors, fonts, etc.
First up is "Whispering" a Message:
letmessage=Message(title:"🚨 Imperial Troops Have Entered the Base!",color:.redColor())Whisper(message,to:navigationController,action:.Present)Silent(navigationController,after:3)
We call the Silentfunction right after we present the Whisper, this will dismiss the message after 3 seconds.
Next, let's try "Shouting" an Announcement.
This one's great for longer text, and looks great with an image. We can also pass in an closure to run when the user taps the banner.
letannouncement=Announcement(title:"Han Solo Says:",subtitle:"Who's scruffy lookin'?!",image:UIImage(named:"avatar"))Shout(announcement,to:self)
Lastly, we can "Whistle" a Murmur to display a subtle, classy message in the status bar:
letmurmur=Murmur(title:"The last transport... is away! 🚀",backgroundColor:murmurColor)Whistle(murmur)
Today we're looking at another great library from Hyper called Pages. It's essentially a convenience wrapper on top of UIPageViewController (previously covered in Bite #55). It makes working with paged view controllers a bit more friendly. Let's begin:
We'll start by composing a PagesController. This will be the view controller that contains the other view controllers:
We use a few properties to configure the look and feel and behavior we want, then we can use the view controller like normal.
Pages has some awesome convenience functions for programmatically scrolling to pages:
pagesVC.goTo(1)// go to page at index 1pagesVC.next()// go forward 1 pagepagesVC.previous()// go back 1 page
We can also easily add view controller pages on the fly:
pagesVC.add([resistanceBasesVC,jediTemplesVC])
Last but not least, Pages is quite configurable offering properties for customizing not only the look and feel, but also behaviors such as whether or not changing view controllers affects the title shown in navigation bar of the navigation controller containing the pages.
More info about Pages can be found at git.io/pages
We can get those awesome "swipe-to-reveal" actions from Mail.app in our own table views. We just need to implement one delegate function and return an array of UITableViewRowActions.
overridefunctableView(tableView:UITableView,editActionsForRowAtIndexPathindexPath:NSIndexPath)->[UITableViewRowAction]?{letdeployAction=UITableViewRowAction(style:.Default,title:"Deploy"){(action,indexPath)in// TODO: Deploy the troop at this indexPath.row}return[deployAction]}
Adjusting to State Transitions
We can override the willTransitionToState(state:) and didTransitionToState(state:)functions in our UITableViewCellsubclasses to run code when the cell begins or finishes showing the edit control or delete confirmation:
Today we'll begin looking at some lesser-known functionality inside UIKit. Some of these may be old news, but hopefully not all are.
We'll start with UIView. Let's flip it over and see what kind of b-side treasures we can find:
Subview Callbacks
We can override functions like didAddSubview(subview:) and willRemoveSubview(subview:) in our UIView subclasses. With this, we can take some action when subviews are added/removed.
An oldie, but a goodie. We can use the endEditing(force:)function to ask (or force) a view or any text fields inside it to resign as the first responder:
view.endEditing(true)
Custom Layer Class
We can specify a custom CALayer subclass for our UIView subclasses by overriding the layerClassfunction. This is great if our view needs to use CATiledLayer to scroll lots of content, or when building a camera preview view:
Let's draw some strings! There's plenty of text-drawing capabilities in iOS and OS X, with full frameworks like Text Kit (or the lower-level Core Text) dedicated to the task. Today, we'll start looking at these capabilities by using Core Graphics and UIKit to draw a multiline string.
Sometimes we need to draw text ourselves, “manually”. This can be helpful when optimizing for scrolling performance, or when complete customization is necessary.
First we'll need a view to draw into, we'll make a new UIView, and override drawRect.
Next, we'll start implementing our drawRectfunction with a few variables. We'll choose a font, then setup a paragraph style to make our text multiline, with some tall lines.
We'll also setup some drawing options to tell the system we want multiline text:
Attributed strings are a fantastic way to work with styled text on iOS and OS X. NSAttributedString is an incredibly full-featured API, but because of this, simple tasks sometimes require a fair amount of boilerplate code. Today we'll look at BonMot, a library from Raizlabs that simplifies the process of composing attributed strings.
BonMot takes the form of a set of chainable functions that we can use to compose attributed strings:
letfancyQuote="Traveling through hyperspace ain't"+"like dusting crops, farm boy.\n"+" — Han Solo"quoteLabel.attributedText=BONChain().fontNameAndSize("AmericanTypewriter",17.0).lineHeightMultiple(1.8).string(fancyQuote).attributedString
BonMot will do all the heavy lifting of applying attributes and return a fully-formed NSAttributedString ready for use wherever we need.
We can use BonMot to concatenate multiple composed attributed strings:
BonMot even supports the NSTextAttachment parts of the NSAttributedString API. We can generate an “image next to a label” like this:
chain.appendLink(BONChain().image(ackbar))chain.appendLink(BONChain().fontNameAndSize("Futura-MediumItalic",17.0).string("It's a trap!"),separator:" ")
We've only scratched the surface here, BonMot has a ton of features to offer. More info about BonMot can be found at git.io/bonmot
Interface Builder is awesome. Assembling our interfaces in it can be a great way to work. Sometimes though, we want to create custom views that we draw and manage ourselves in code. It'd be nice if these custom views could work just as well inside Interface Builder as they do in our code. Today we'll look at two awesome features that debuted with Xcode 6 called @IBInspectable and @IBDesignable. Let's dive in:
When crafting a custom view, we can make a property “inspectable” in Interface Builder by prefixing its definition with @IBInspectable. Now, when we drag an instance of our custom view onto the canvas in Interface Builder we'll be able to change our properties with native controls!
This technique even works with extensions! Tired of not being able to configure things like a UIButton's borders in IB? Let's add a tiny extension to UIButton to make it more inspectable:
This is great so far, but what we really want is to be able to see the effects of our property edits live in the IBcanvas. We can prefix any view's definition with @IBDesignable to tell IB to render the view, live, right on the canvas.
When we combine the two techniques we unlock a much more intuitive (and fast) way to build custom views. We can even implement a special function called prepareForInterfaceBuilder() on our view where we can configure it with example data that will be drawn only when it's rendered in IB.
If anything goes wrong, we can debug our view by setting a breakpoint like normal, then choosing Editor > Debug Selected Views from Xcode's menu.