Showing posts with label UI. Show all posts
Showing posts with label UI. Show all posts

Thursday, October 18, 2018

UIKit protocol of the month: StoryboardInstantiatableViewController

Github Gist.

I want to share this little invention with the community. I use it for the last month and find it notably helpful: protocol StoryboardInstantiatableViewController { static var storyboardId: String { get } } extension StoryboardInstantiatableViewController where Self: UIViewController { static func instantiate(from storyboard: UIStoryboard?) -> Self? { return storyboard?.instantiateViewController(withIdentifier: Self.storyboardId) as? Self } }
This protocol along with the extension provides some syntactic sugar and solves two common problems:
  • Shortens the instantiation
  • Answers, where to store the storyboard id

Usage example:

// Declaration: class TaskViewController: UIViewController, StoryboardInstantiatableViewController { // The same id as specified in Identity inspector static let storyboardId: String = "task" // ... } // Initializing from Storyboard: // ... guard let taskVC = TaskViewController.instantiate(from: storyboard) else { return } navigationController?.pushViewController(taskVC, animated: true)

Update:

Surprisingly, I bumped into another similar protocol, named StoryboardInstantiatable. The main difference that it's designed for use with NSViewController and Cocoa instead of Cocoa Touch. The fact is, that the gist was posted 5 months earlier than this blog post. So Satori Maru is the first one who invented the idea, although I came to it independently.

Saturday, June 30, 2018

Handling background touches: UIControl instead of UITapGestureRecognizer

Usually, to handle background touches on a View Controller we add a UITapGestureRecognizer. The setup requires a few lines of code, but there is a way, you can handle background touches even more easy!

What you need to do is just to change the root view type from UIView to UIControl and attach an action. With Storyboard:
  1. Select the root view.
  2. In the Identity inspector simply change the type to UIControl. (Serious type change isn't required.)
  3. Finally, connect an action to the Touch Down event using Connections inspector.
Then the action can be utilized, for example, to hide a keyboard: @IBAction func backgroundTouched(_ sender: Any) { // Hide keyboard view.endEditing(true) }
If any child control interrupts a touch, it wouldn't be delivered to the background control! This is the main pro and con of this method. Sometimes it's exactly the desired behaviour to ignore touches on buttons. But other times you need to handle all the touches anywhere in the View Controller, like if you have a large UITextView and you want to hide the keyboard by tap.

How to Record Calls on iPhone