by Louis D'hauwe
Who?
Louis D'hauwe
Est. 1995
iOS Developer @ Next Apps
College dropout !
#TeamTabs
@LouisDhauwe
Demo
A UI framework enabling floating and
pinned panels on iOS.
A UI framework enabling floating and
pinned panels on iPad.
Why?
Photoshop Fix
Photoshop Fix
Photoshop CC
"real" Photoshop
We can do better!
Performance
Performance
CPU
iPad Pro 

(12.9-inch, 2015)
MacBook Air 

(13-inch, 2015)
0 1500 3000 4500 6000
Single-Core Multi-Core
4.157
5.238
2.439
3.083
Source: Geekbench
Hardware is not the issue
Software is
How?
Panels Panel Manager
View Hierarchy
UINavigationController
Root View Controller
Content Wrapper View
Content View
UINavigationController
Root View Controller
Content Wrapper View
Content View
Content View Panel
UINavigationController
Root View Controller
Content Wrapper View
Content View
Panel
Technical
v0.8
open class PanelContentViewController: UIViewController {
...
open var preferredPanelContentSize: CGSize {
fatalError("Preferred panel content size not implemented")
}
...
}
v0.8
open class PanelContentViewController: UIViewController {
...
open var preferredPanelContentSize: CGSize {
fatalError("Preferred panel content size not implemented")
}
...
}
class FooPanelContentViewController: PanelContentViewController {
override var preferredPanelContentSize: CGSize {
return CGSize(width: 320, height: 500)
}
}
v0.8
open class PanelContentViewController: UIViewController {
...
open var preferredPanelContentSize: CGSize {
fatalError("Preferred panel content size not implemented")
}
...
}
class FooPanelContentViewController: PanelContentViewController {
override var preferredPanelContentSize: CGSize {
return CGSize(width: 320, height: 500)
}
}
Need to implement,
otherwise runtime crash!
v0.8
Why fatalError?
open class PanelContentViewController: UIViewController {
...
open var preferredPanelContentSize: CGSize {
fatalError("Preferred panel content size not implemented")
}
...
}
v0.8
Why fatalError?
Swift has no abstract modifier
open class PanelContentViewController: UIViewController {
...
open var preferredPanelContentSize: CGSize {
fatalError("Preferred panel content size not implemented")
}
...
}
v0.8
Why fatalError?
Swift has no abstract modifier
open class PanelContentViewController: UIViewController {
...
open var preferredPanelContentSize: CGSize {
fatalError("Preferred panel content size not implemented")
}
...
}
No default value
v0.8
v1.0
Protocol-oriented
Protocol-oriented
interface
contract
open class PanelContentViewController: UIViewController {
...
open var preferredPanelContentSize: CGSize {
fatalError("Preferred panel content size not implemented")
}
...
}
Protocol-oriented
public protocol PanelContentDelegate {
...
var preferredPanelContentSize: CGSize { get }
...
}
Protocol-oriented
class FooPanelContentViewController: UIViewController, PanelContentDelegate {
}
Protocol-oriented
class FooPanelContentViewController: UIViewController, PanelContentDelegate {
}
Protocol-oriented
class FooPanelContentViewController: UIViewController, PanelContentDelegate {
var preferredPanelContentSize: CGSize {
return CGSize(width: 320, height: 500)
}
}
Protocol-oriented
class FooPanelContentViewController: UIViewController, PanelContentDelegate {
let preferredPanelContentSize = CGSize(width: 320, height: 500)
}
Protocol-oriented
Protocol-oriented
public class PanelViewController: UIViewController,
UIAdaptivePresentationControllerDelegate {
public init(with contentViewController: UIViewController,
contentDelegate: PanelContentDelegate,
in panelManager: PanelManager) {
...
}
...
}
Protocol-oriented
public class PanelViewController: UIViewController,
UIAdaptivePresentationControllerDelegate {
public init(with contentViewController: UIViewController,
contentDelegate: PanelContentDelegate,
in panelManager: PanelManager) {
...
}
...
}
public protocol PanelManager {
/// The ```UIViewController``` that manages the panels and contains
/// ```panelContentWrapperView``` and ```panelContentView```.
var managerViewController: UIViewController { get }
/// The panels to be managed.
var panels: [PanelViewController] { get }
/// The view in which the panels may be dragged around.
var panelContentWrapperView: UIView { get }
/// The content view, which will be moved/resized when panels pin.
var panelContentView: UIView { get }
...
}
Protocol-oriented
public extension PanelManager where Self: UIViewController {
var managerViewController: UIViewController {
return self
}
}
Protocol-oriented
class ManagerViewController: UIViewController, PanelManager {
var panelContentWrapperView: UIView {
return contentWrapperView
}
var panelContentView: UIView {
return contentView
}
var panels: [PanelViewController] {
return [fooPanelVC, barPanelVC]
}
}
Protocol-oriented
Layout
Autoresizing
Autoresizing
Struts & Springs
Auto Layout
Auto Layout
• UIKit's anchor API
Auto Layout
• UIKit's anchor API
panelNavigationController.view.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 1.0).isActive = true
panelNavigationController.view.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1.0).isActive = true
panelNavigationController.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
panelNavigationController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
Auto Layout
• UIKit's anchor API
• Don't forget isActive = true
panelNavigationController.view.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 1.0).isActive = true
panelNavigationController.view.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1.0).isActive = true
panelNavigationController.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
panelNavigationController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
Auto Layout
• UIKit's anchor API
• Don't forget isActive = true
• Always creates new constraint instance
panelNavigationController.view.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 1.0).isActive = true
panelNavigationController.view.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1.0).isActive = true
panelNavigationController.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
panelNavigationController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
Auto Layout
• UIKit's anchor API
• Don't forget isActive = true
• Always creates new constraint instance
• Requires iOS 9.0+
panelNavigationController.view.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 1.0).isActive = true
panelNavigationController.view.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1.0).isActive = true
panelNavigationController.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
panelNavigationController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
Open Source
Open Source
• github.com/louisdh/panelkit
Open Source
• github.com/louisdh/panelkit
• Pull requests appreciated!
Open Source
• github.com/louisdh/panelkit
• Pull requests appreciated!
• Complete history available
Open Source
• github.com/louisdh/panelkit
• Pull requests appreciated!
• Complete history available
• Versions are tagged
Open Source
• github.com/louisdh/panelkit
• Pull requests appreciated!
• Complete history available
• Versions are tagged
• MIT license
Open Source Services
Travis CI
• travis-ci.org
Travis CI
• travis-ci.org
• Build on every commit & PR
Travis CI
• travis-ci.org
• Build on every commit & PR
• Run tests for every build
Travis CI
• travis-ci.org
• Build on every commit & PR
• Run tests for every build
• Result shown in GitHub UI
Travis CI
• travis-ci.org
• Build on every commit & PR
• Run tests for every build
• Result shown in GitHub UI
• Free for open source projects!
Code Climate
• codeclimate.com
Code Climate
• codeclimate.com
• Runs linter on every commit & PR
Code Climate
• codeclimate.com
• Runs linter on every commit & PR
• Result shown in GitHub UI
Code Climate
• codeclimate.com
• Runs linter on every commit & PR
• Result shown in GitHub UI
• Free for open source projects!
Code Coverage
• codecov.io
Code Coverage
• codecov.io
• Shows coverage of unit tests
Code Coverage
• codecov.io
• Shows coverage of unit tests
• Gets results from Travis CI
Code Coverage
• codecov.io
• Shows coverage of unit tests
• Gets results from Travis CI
• Free for open source projects!
Open Source
Distribution
Open Source Distribution
Source
Open Source Distribution
Source CocoaPods
Open Source Distribution
Source CocoaPods Carthage
Open Source Distribution
Source CocoaPods Carthage SPM
SPM
Swift Package Manager
• Official dependency manager
Swift Package Manager
• Official dependency manager
• Included in Xcode
Swift Package Manager
• Official dependency manager
• Included in Xcode
• Only for macOS currently
Swift Package Manager
• Official dependency manager
• Included in Xcode
• Only for macOS currently
• Open source
Swift Package Manager
• Official dependency manager
• Included in Xcode
• Only for macOS currently
• Open source
• Written in Swift
Launch
Launch
Community response
Community response
Press
– John Gruber, Daring Fireball
“It caught my eye a few weeks ago on Twitter,
and now that I can play with it in an actual
app, I’m even more impressed with the
ingenuity.”
– Federico Viticci, MacStories
“The best part, in my opinion, is that panels can
be converted back to sidebars by snapping them
to the edge of the display, which is a fantastic use
of the iPad Pro's large screen.”
Other projects
Colorcube
Colorcube featured
App Store. July 22, 2016
Colorcube featured
Apple Special Event. September 7, 2016.
Other projects
Colorcube
Other projects
Colorcube Pixure
Other projects
Colorcube Pixure Leet Keyboard
Other projects
Colorcube Pixure Leet Keyboard
Universal
Apple Watch
Quick Actions
iCloud
PanelKit
Spotlight SearchLayers
Blend modes
Split View
Slide Over
Keyboard shortcuts
iTunes File Sharing
Photo Filter
Bucket Fill
Document import
Document export
Adobe Send to Desktop
3D-Touch
Peek & Pop
Share Sheet
200x Zoom
Universal
Apple Watch
Quick Actions
iCloud
PanelKit
Spotlight SearchLayers
Blend modes
Split View
Slide Over
Keyboard shortcuts
iTunes File Sharing
Photo Filter
Bucket Fill
Document import
Document export
Adobe Send to Desktop
3D-Touch
Peek & Pop
Share Sheet
200x Zoom
Demo
What does Apple think
of all this?
App Store. April 1, 2017
Featured!
Pixure stats from 26 March to 6 April 2017
Summary
• More powerful iPad UIs
Summary
• More powerful iPad UIs
• Written in Swift
Summary
• More powerful iPad UIs
• Written in Swift
• Open source
Summary
• More powerful iPad UIs
• Written in Swift
• Open source
• Ready for production
Summary
• More powerful iPad UIs
• Written in Swift
• Open source
• Ready for production
• Featured by Apple
Contact
Louis D'hauwe
louis@nextapps.be
@LouisDhauwe
Questions?

Introducing PanelKit