├── .gitignore
├── CHANGELOG.md
├── Example
├── Podfile
├── Podfile.lock
├── UIEmptyStateExample.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── UIEmptyStateExample.xcworkspace
│ └── contents.xcworkspacedata
└── UIEmptyStateExample
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── buttonBg.imageset
│ │ ├── Contents.json
│ │ ├── minus-button-1.png
│ │ ├── minus-button-2.png
│ │ └── minus-button.png
│ ├── emptyPokemon.imageset
│ │ ├── Contents.json
│ │ ├── open-pokeball-1.png
│ │ ├── open-pokeball-2.png
│ │ └── open-pokeball.png
│ └── pokeball.imageset
│ │ ├── Contents.json
│ │ ├── pokeball-1.png
│ │ ├── pokeball-2.png
│ │ └── pokeball.png
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── EmptyStateCollectionViewCell.swift
│ ├── EmptyStateCollectionViewController.swift
│ ├── EmptyStateTableViewController.swift
│ └── Info.plist
├── GitHubAssets
├── banner.jpg
├── screen1.jpg
├── screen2.jpg
└── screen3.jpg
├── LICENSE
├── README.md
├── UIEmptyState.podspec
├── docs
├── Classes.html
├── Classes
│ └── UIEmptyStateView.html
├── Extensions.html
├── Extensions
│ ├── UICollectionViewController.html
│ ├── UITableViewController.html
│ └── UIViewController.html
├── Protocols.html
├── Protocols
│ ├── UIEmptyStateDataSource.html
│ └── UIEmptyStateDelegate.html
├── badge.svg
├── css
│ ├── highlight.css
│ └── jazzy.css
├── docsets
│ ├── UIEmptyState.docset
│ │ └── Contents
│ │ │ ├── Info.plist
│ │ │ └── Resources
│ │ │ ├── Documents
│ │ │ ├── Classes.html
│ │ │ ├── Classes
│ │ │ │ └── UIEmptyStateView.html
│ │ │ ├── Extensions.html
│ │ │ ├── Extensions
│ │ │ │ ├── UICollectionViewController.html
│ │ │ │ ├── UITableViewController.html
│ │ │ │ └── UIViewController.html
│ │ │ ├── Protocols.html
│ │ │ ├── Protocols
│ │ │ │ ├── UIEmptyStateDataSource.html
│ │ │ │ └── UIEmptyStateDelegate.html
│ │ │ ├── css
│ │ │ │ ├── highlight.css
│ │ │ │ └── jazzy.css
│ │ │ ├── img
│ │ │ │ ├── carat.png
│ │ │ │ ├── dash.png
│ │ │ │ ├── gh.png
│ │ │ │ └── spinner.gif
│ │ │ ├── index.html
│ │ │ ├── js
│ │ │ │ ├── jazzy.js
│ │ │ │ ├── jazzy.search.js
│ │ │ │ ├── jquery.min.js
│ │ │ │ ├── lunr.min.js
│ │ │ │ └── typeahead.jquery.js
│ │ │ └── search.json
│ │ │ └── docSet.dsidx
│ └── UIEmptyState.tgz
├── img
│ ├── carat.png
│ ├── dash.png
│ ├── gh.png
│ └── spinner.gif
├── index.html
├── js
│ ├── jazzy.js
│ ├── jazzy.search.js
│ ├── jquery.min.js
│ ├── lunr.min.js
│ └── typeahead.jquery.js
├── search.json
└── undocumented.json
├── run-jazzy.sh
└── src
├── UIEmptyState.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── UIEmptyState.xcscheme
├── UIEmptyState
├── Info.plist
├── UIEmptyState.h
├── UIEmptyStateDataSource.swift
├── UIEmptyStateDelegate.swift
├── UIEmptyStateView.swift
└── UIViewController+UIEmptyState.swift
└── UIEmptyStateTests
├── Info.plist
└── UIEmptyStateTests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | ## OS X Finder
2 | .DS_Store
3 |
4 | ## Build generated
5 | build/
6 | DerivedData
7 |
8 | ## Various settings
9 | *.pbxuser
10 | !default.pbxuser
11 | *.mode1v3
12 | !default.mode1v3
13 | *.mode2v3
14 | !default.mode2v3
15 | *.perspectivev3
16 | !default.perspectivev3
17 | xcuserdata
18 |
19 | ## Other
20 | *.xccheckout
21 | *.moved-aside
22 | *.xcuserstate
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 |
29 | # Swift Package Manager
30 | .build/
31 |
32 | # Carthage
33 | Carthage/Build
34 |
35 | # Ignore pods
36 | Example/Pods/
37 | UIEmptyState.framework.zip
38 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # UIEmptyState CHANGELOG
2 |
3 | ## Version 4.0.1
4 |
5 | - Fix memory leak due to retain cycle
6 |
7 | ## Version 4.0.0
8 |
9 | - Swift 4.2 support
10 |
11 | ## Version 3.2.0
12 |
13 | - Fix bug where the empty view was not centered properly on
14 | non `UITableViewController` or `UICollectionViewController` types.
15 | - Fix bug where empty view did not account for table header view height
16 | thus was not truly centered in the visible area of the table view
17 |
18 | ## Version 3.1.2
19 |
20 | - Build with Swift 4.1.2
21 |
22 | ## Version 3.1.1
23 |
24 | - Buid with Swift 4.1
25 |
26 | ## Version 3.1.0
27 |
28 | - Added new `emptyStateImageViewTintColor`, which allows applying a tint color to the default `UIEmptyStateView`'s image view.
29 | - Added new `emptyStateViewCenterYOffset`, which allows offsetting the vertical center position for the empty state view.
30 | - Example project now uses local `UIEmptyState` pod, to allow for local development and easier testing.
31 |
32 | Changes made by: [gabmarfer](https://github.com/gabmarfer), thanks!
33 |
34 | ## Version 3.0.0
35 |
36 | - Fixed bug where `UIEmptyStateDataSource.emptyStateView` computed property and the the `UIViewController+UIEmptyState.emptyStateView` properties conflicted thus not allowing creation of custom view.
37 | - Custom views now work as intended, you can return a `UIView` subclass in the `UIEmptyStateDataSource.emptyStateView` computed property. Make sure to set any needed constraints, etc.
38 |
39 | **Breaking API changes:**
40 |
41 | Remove `emptyStateView` from view controller extension. This was never intended to be accessible outside of the extension. Use the `emptyStateView` computed property in `UIEmptyStateDataSource` to create a custom view instead.
42 |
43 | ## Version 2.0.2
44 |
45 | Bug fix for retain cycle between delegate, datasource, and the view controller.
46 | Thanks to [@piotrzuzel](https://github.com/piotrzuzel) for the fix.
47 |
48 | ## Version 2.0.1
49 |
50 | Add shared scheme, fixed thanks to [@piotrzuzel](https://github.com/piotrzuzel).
51 |
52 | ## Version 2.0.0
53 |
54 | #### Breaking API Changes:
55 |
56 | - Renamed `reloadEmptyState(for: tableView)` to `reloadEmptyStateForTableView(_:)` __and__ `reloadEmptyState(for: collectionView)` to `reloadEmptyStateForCollectionView(_:)`. This fixes an issue where error is thrown for duplicate function declaration with Objective-C selector on Swift versions lower than 4.0.
57 |
58 |
59 | - Renamed the `shouldShowEmptyStateView(for:)` datasource method to `emptyStateViewShouldShow(for:)`. This was done to be more consistent with the rest of the API.
60 |
61 |
62 | - Renamed `titleView` to `titleLabel` __and__ `detailView` to `detailLabel`. This makes it more clear exactly what these views actually are.
63 |
64 | #### Improvements and Fixes
65 |
66 | - Fix a bug where constraints for the `UIEmptyStateView` would be added whenever the view appeared thus causing a warning to be thrown by Xcode for duplicate and breaking constraints. Constraints for the view are now only added on initial showing of view.
67 |
68 | - Fix bug where `UIEmptyStateView.detailLabel` would not resize and fit the screen correctly on iOS versions lower than 11.0. `detailLabel` now calculates it's width properly and constraints are added accordingly.
69 |
70 | - Change `emptyStateViewAnimatesEverytime` from `true` to `false`. This seems like a more reasonable default value as it animations can get annoying when repeated multiple times without change.
71 |
72 | ## Versin 1.0.2
73 |
74 | - Fix issue with `UIEmptyStateView` and it's subviews not being accessible.
75 |
76 | ## Version 1.0.1
77 |
78 | - Fix access modifier in default implementation of `emptyStateViewWillHide(view: UIView)`
79 |
80 | ## Version 1.0.0 - Stable Release
81 |
82 | - Add Swift version check to allow support for Swift 3 --> Swift 4.
83 | - Refactor public API to make it less verbose and more Swift-like.
84 | * All methods which had the format `methodName(forSomething:)` have been refactored to simply `methodName(for:)`.
85 | * Due to this renaming, if using Swift 3.2 or lower, you may get an error
86 | about a `@objc` method having already been declared, this is due to Swift 3 inferring an `@objc` attribute when it is not in fact `@objc`. If using Xcode 9 +, you will need to set `Swift 3 @objc Inference` in the `Optimization Level` of this projects `Build Settings` to `Off`. I know this is a hassle, but I want to keep the API clean and stable, no point in changing it at a later date when Swift 4 is fully released and breaking more code.
87 | - Add two new delegate methods to the `UIEmptyStateDelegate`
88 | * `emptyStateViewWillShow(view: UIView)` which is called before the view is shown, given you time to do any additional work.
89 | * `emptyStateViewWillHide(view: UIView)` which is called right before the view will be hidden from the screen.
90 | - Fix some broken documentation/updated docs
91 |
92 | After this release the API should not change that often, thus I wont be breaking your code as much 😅
93 |
94 | Thanks for using `UIEmptyState`
95 |
96 |
97 | ## Version 0.8.3
98 |
99 | - Fix bug where data source was not reverting `edgesForExtendedLayout` to default values after it was done presenting the view
100 |
101 | ## Version 0.8.2
102 |
103 | - Fix issue with constraints not being set properly for Empty state view
104 |
105 | ## Version 0.8.1
106 |
107 | - Make sure `.swift-version` is included in pod to fix warnings in Xcode 9
108 |
109 | ## Version 0.8.0
110 |
111 | - Updated for Swift 4 and Xcode 9
112 | - Now uses `safeAreaLayoutGuide` to adjust centering of empty state view, if on iOS 11 when `shouldAdjustToFitBars` returns `true`.
113 | - Updated project to recommended settings in Xcode 9, set language to Swift 4 and `@objc inference` to `default`.
114 |
115 | ## Version 0.7.0
116 |
117 | - Update constraints for labels so that they do not extend past the edges of the view
118 | - Add private extension to help calculate the the height of labels
119 |
120 | ## Version 0.6.0
121 |
122 | - Fix bug where title for UIEmptyState was not being updated when reloading
123 | - Made sure to assign all datasource properties when creating, and updating the view
124 |
125 |
126 | ## Version 0.5.0
127 |
128 | - Refactored API methods for `UIEmptyStateDataSource` into computed properties to be more "swift-like"
129 | - Add new delegate method to get notified when the view has been shown, here you can bring subviews to front that may have been covered by the UIEmptyState
130 | - Add new property to determine whether the viewcontroller using UIEmptyState should adjust it's frame to take into account navigation bars/tab bars
131 | - Refactored a lot of code and comments
132 |
133 | #### Breaking API Changes in 0.5.0
134 |
135 | Basically, everything... Sorry!
136 | Due to the change from methods to properties, the way you interact with the data source has changed. [Please read the documentation](https://htmlpreview.github.io/?https://raw.githubusercontent.com/luispadron/UIEmptyState/master/docs/Protocols/UIEmptyStateDataSource.html). Most methods have been convereted into computed properties. This will be the design going forward unless it's not possible, i.e requires parameters or would be better in a method.
137 |
138 | ## Version 0.4.0
139 |
140 | - Add ability to animate the empty state view
141 | - Removed returning a detail message in the default implementation as this caused an annoying problem in that you would need to implement that method and return nil if you didn't want to use a detail message
142 |
143 | ## Version 0.3.0
144 |
145 | - Add fixes for views not being updated
146 | - Add fix to constraints becoming wonky after readding views
147 | - Add convenience extenions to `UITableViewController` and `UICollectionViewController`
148 |
149 | You can now do this:
150 |
151 | ```swift
152 | // If a tableview or collectionview controller subclass
153 | // This will default the tableView/collectionView to self.tableView/collectionView
154 | self.reloadEmptyState()
155 | ```
156 | - Refactoring of UIEmptyStateView
157 | - Rerun Jazzy for documentation
158 |
159 | ## Version 0.2.1
160 |
161 | - Add fix for updating view, titles can now be changed on the fly using data source methods
162 | - Some small amount of refactoring
163 |
164 | ## Version 0.2.0
165 |
166 | - Now works with any UIViewController subclass
167 | - Update example project to contain a `UITableViewController` example as well a `UICollectionViewController` exmaple
168 | - Refactor some uneeded code
169 | - Rerun Jazzy for code documentation
170 |
171 | ##### Breaking API CHanges:
172 |
173 | - Call for reloading of empty state view has changed
174 |
175 | _Before_
176 |
177 | ```swift
178 | // Called whenever data has changed, only worked for table views
179 | self.reloadTableViewEmptyState()
180 | ```
181 |
182 | _Now_
183 |
184 | ```swift
185 | // Called whenever data has changed, now works with collectionview or tableview
186 | // If tableView controller, or controller with tableView property
187 | self.reloadEmptyState(forTableView: self.tableView)
188 | // OR if collectionview controller, or controller with collectionView property
189 | self.reloadEmptyState(forCollectionView: self.collectionView)
190 | ```
191 |
192 | ## Version 0.1.1
193 |
194 | - Initial of the initial release (messed up the spec in 0.1.0 oops)
195 | - Currently only works with `UITableViewController`
196 | - iOS required of 9.0 +
197 |
198 | ## Version 0.1.0
199 |
200 | - Initial release
201 | - Currently only works with `UITableViewController`
202 | - iOS required of 9.0 +
203 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'UIEmptyStateExample' do
5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for UIEmptyStateExample
9 | pod 'UIEmptyState', :path => '../'
10 | end
11 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - UIEmptyState (4.0.0)
3 |
4 | DEPENDENCIES:
5 | - UIEmptyState (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | UIEmptyState:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | UIEmptyState: a299e655ecb6fc077dfb503c375ef9a023103240
13 |
14 | PODFILE CHECKSUM: 2410e5e41e5d4570ddd34538c5ba93d5d35ce08c
15 |
16 | COCOAPODS: 1.5.3
17 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // UIEmptyStateExample
4 | //
5 | // Created by Luis Padron on 2/3/17.
6 | // Copyright © 2017 Luis Padron. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/buttonBg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "minus-button.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "minus-button-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "minus-button-2.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/buttonBg.imageset/minus-button-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/buttonBg.imageset/minus-button-1.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/buttonBg.imageset/minus-button-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/buttonBg.imageset/minus-button-2.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/buttonBg.imageset/minus-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/buttonBg.imageset/minus-button.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/emptyPokemon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "open-pokeball.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "open-pokeball-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "open-pokeball-2.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/emptyPokemon.imageset/open-pokeball-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/emptyPokemon.imageset/open-pokeball-1.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/emptyPokemon.imageset/open-pokeball-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/emptyPokemon.imageset/open-pokeball-2.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/emptyPokemon.imageset/open-pokeball.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/emptyPokemon.imageset/open-pokeball.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/pokeball.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "pokeball.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "pokeball-2.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "pokeball-1.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/pokeball.imageset/pokeball-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/pokeball.imageset/pokeball-1.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/pokeball.imageset/pokeball-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/pokeball.imageset/pokeball-2.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Assets.xcassets/pokeball.imageset/pokeball.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/Example/UIEmptyStateExample/Assets.xcassets/pokeball.imageset/pokeball.png
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/EmptyStateCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmptyStateCollectionViewCell.swift
3 | // UIEmptyStateExample
4 | //
5 | // Created by Luis Padron on 2/5/17.
6 | // Copyright © 2017 Luis Padron. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class EmptyStateCollectionViewCell: UICollectionViewCell {
12 | @IBOutlet weak var pokemonLabel: UILabel!
13 |
14 | override func awakeFromNib() {
15 | super.awakeFromNib()
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/EmptyStateCollectionViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmptyStateCollectionViewController.swift
3 | // UIEmptyStateExample
4 | //
5 | // Created by Luis Padron on 2/5/17.
6 | // Copyright © 2017 Luis Padron. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import UIEmptyState
11 |
12 | private let reuseIdentifier = "collectionViewCell"
13 |
14 | class EmptyStateCollectionViewController: UICollectionViewController, UIEmptyStateDelegate, UIEmptyStateDataSource {
15 |
16 | var caughtPokemon = [String]()
17 |
18 | override func viewDidLoad() {
19 | self.title = "CollectionView Example"
20 | super.viewDidLoad()
21 |
22 | // Set delegate and data source
23 | self.emptyStateDelegate = self
24 | self.emptyStateDataSource = self
25 | // Set the inital state of the collectionview
26 | self.reloadEmptyState()
27 | }
28 |
29 | override func didReceiveMemoryWarning() {
30 | super.didReceiveMemoryWarning()
31 | }
32 |
33 | // MARK: UICollectionViewDataSource
34 |
35 | override func numberOfSections(in collectionView: UICollectionView) -> Int {
36 | // #warning Incomplete implementation, return the number of sections
37 | return 1
38 | }
39 |
40 |
41 | override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
42 | // #warning Incomplete implementation, return the number of items
43 | return caughtPokemon.count
44 | }
45 |
46 | override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
47 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! EmptyStateCollectionViewCell
48 | cell.pokemonLabel.text = caughtPokemon[indexPath.row]
49 | return cell
50 | }
51 |
52 | // MARK: UICollectionViewDelegate
53 |
54 | // MARK: - Helper Methods
55 |
56 | @IBAction func addButtonTapped(_ sender: UIBarButtonItem) {
57 | // Add pokemon
58 | let row = caughtPokemon.count == 0 ? 0 : caughtPokemon.count - 1
59 | addPokemon(at: IndexPath(row: row, section: 0))
60 | }
61 |
62 | // MARK: - Helper Methods
63 |
64 | let pokemon = ["Pikachu", "Charizard", "Charmander", "Caterpie", "Butterfree", "Mew", "MewTwo", "Growlithe", "Squirtle"]
65 |
66 | func randomPokemon() -> String {
67 | let index = arc4random_uniform(UInt32(pokemon.count))
68 | return pokemon[Int(index)]
69 | }
70 |
71 | func addPokemon(at path: IndexPath) {
72 | let newPokemon = randomPokemon()
73 | caughtPokemon.append(newPokemon)
74 | self.collectionView?.reloadData()
75 | // Remember to call this to reload the empty state view after every data change
76 | self.reloadEmptyState()
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/EmptyStateTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // UIEmptyStateExample
4 | //
5 | // Created by Luis Padron on 2/3/17.
6 | // Copyright © 2017 Luis Padron. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import UIEmptyState
11 |
12 | class EmptyStateTableViewController: UITableViewController, UIEmptyStateDelegate, UIEmptyStateDataSource {
13 |
14 | var caughtPokemon = [String]()
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | self.title = "TableView Example"
19 | // Set the data source and delegate to self
20 | self.emptyStateDataSource = self
21 | self.emptyStateDelegate = self
22 | // Remove seperator lines from empty cells
23 | self.tableView.tableFooterView = UIView(frame: CGRect.zero)
24 | // Initially call the reloadTableViewState to get the initial state
25 | self.reloadEmptyState()
26 | self.view.backgroundColor = UIColor(red: 0.518, green: 0.576, blue: 0.604, alpha: 1.00)
27 | }
28 |
29 | // MARK: - Empty State Data Source
30 |
31 | var emptyStateImage: UIImage? {
32 | return #imageLiteral(resourceName: "emptyPokemon")
33 | }
34 |
35 | var emptyStateTitle: NSAttributedString {
36 | let attrs = [NSAttributedString.Key.foregroundColor: UIColor(red: 0.882, green: 0.890, blue: 0.859, alpha: 1.00),
37 | NSAttributedString.Key.font: UIFont.systemFont(ofSize: 22)]
38 | return NSAttributedString(string: "No Pokemon caught!", attributes: attrs)
39 | }
40 |
41 | var emptyStateButtonTitle: NSAttributedString? {
42 | let attrs = [NSAttributedString.Key.foregroundColor: UIColor.white,
43 | NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)]
44 | return NSAttributedString(string: "Catch'em All", attributes: attrs)
45 | }
46 |
47 | var emptyStateButtonSize: CGSize? {
48 | return CGSize(width: 100, height: 40)
49 | }
50 |
51 |
52 | // MARK: - Empty State Delegate
53 |
54 | func emptyStateViewWillShow(view: UIView) {
55 | guard let emptyView = view as? UIEmptyStateView else { return }
56 | // Some custom button stuff
57 | emptyView.button.layer.cornerRadius = 5
58 | emptyView.button.layer.borderWidth = 1
59 | emptyView.button.layer.borderColor = UIColor.red.cgColor
60 | emptyView.button.layer.backgroundColor = UIColor.red.cgColor
61 | }
62 |
63 | func emptyStatebuttonWasTapped(button: UIButton) {
64 | // Add a pokemon
65 | let row = caughtPokemon.count == 0 ? 0 : caughtPokemon.count - 1
66 | addPokemon(at: IndexPath(row: row, section: 0))
67 | }
68 |
69 | // MARK: - TableView Delegation
70 |
71 | override func numberOfSections(in tableView: UITableView) -> Int {
72 | return 1
73 | }
74 |
75 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
76 | return caughtPokemon.count
77 | }
78 |
79 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
80 | let cell = tableView.dequeueReusableCell(withIdentifier: "exampleCell")!
81 | let pokemon = caughtPokemon[indexPath.row]
82 | cell.textLabel?.text = "Pokemon caught: \(pokemon)"
83 | return cell
84 | }
85 |
86 | override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
87 | if editingStyle == .delete {
88 | // Delete the row
89 | tableView.beginUpdates()
90 | caughtPokemon.remove(at: indexPath.row)
91 | tableView.deleteRows(at: [indexPath], with: .automatic)
92 | tableView.endUpdates()
93 | // Call reload of empty state
94 | self.reloadEmptyState()
95 | }
96 | }
97 |
98 | @IBAction func addButtonTapped(_ sender: UIBarButtonItem) {
99 | // Add pokemon
100 | let row = caughtPokemon.count == 0 ? 0 : caughtPokemon.count - 1
101 | addPokemon(at: IndexPath(row: row, section: 0))
102 | }
103 |
104 | // MARK: - Helper Methods
105 |
106 | let pokemon = ["Pikachu", "Charizard", "Charmander", "Caterpie", "Butterfree", "Mew", "MewTwo", "Growlithe", "Squirtle"]
107 |
108 | func randomPokemon() -> String {
109 | let index = arc4random_uniform(UInt32(pokemon.count))
110 | return pokemon[Int(index)]
111 | }
112 |
113 | func addPokemon(at path: IndexPath) {
114 | let newPokemon = randomPokemon()
115 | caughtPokemon.append(newPokemon)
116 | tableView.beginUpdates()
117 | tableView.insertRows(at: [path], with: .automatic)
118 | tableView.endUpdates()
119 | self.reloadEmptyState()
120 | }
121 | }
122 |
123 |
--------------------------------------------------------------------------------
/Example/UIEmptyStateExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/GitHubAssets/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/GitHubAssets/banner.jpg
--------------------------------------------------------------------------------
/GitHubAssets/screen1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/GitHubAssets/screen1.jpg
--------------------------------------------------------------------------------
/GitHubAssets/screen2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/GitHubAssets/screen2.jpg
--------------------------------------------------------------------------------
/GitHubAssets/screen3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/GitHubAssets/screen3.jpg
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Luis Padron
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
4 |
5 |
6 |
7 | ## Requirements
8 |
9 | - Xcode 9.0 +
10 | - iOS 9.0 or greater
11 |
12 |
13 | ## Installation
14 |
15 | ### CocoaPods
16 |
17 | 1. Install [CocoaPods](http://cocoapods.org)
18 | 2. Add this repo to your `Podfile`
19 |
20 | ```ruby
21 | target 'Example' do
22 | use_frameworks!
23 |
24 | pod 'UIEmptyState'
25 | end
26 | ```
27 |
28 | 3. Run `pod install`
29 | 4. Open up the new `.xcworkspace` that CocoaPods generated
30 | 5. Whenever you want to use the library: `import UIEmptyState`
31 |
32 | ### Carthage
33 |
34 | 1. Make sure Carthage is install
35 |
36 | `brew install carthage`
37 | 2. Add this repo to your Cartfile
38 |
39 | `github "luispadron/UIEmptyState"`
40 |
41 |
42 | ### Manually
43 |
44 | 1. Simply download the `UIEmptyState` source files and import them into your project.
45 |
46 |
47 | ## Usage
48 |
49 | As long as you are using a `UIViewController` subclass you will get default conformance as well as the `reloadEmptyState` method.
50 |
51 | ```swift
52 | // No subclassing required, simply conform to the two protocols
53 | class ViewController: UITableViewController, UIEmptyStateDataSource, UIEmptyStateDelegate {
54 |
55 | override func viewDidLoad() {
56 | super.viewDidLoad()
57 | // Set the data source and delegate
58 | self.emptyStateDataSource = self
59 | self.emptyStateDelegate = self
60 | // Optionally remove seperator lines from empty cells
61 | self.tableView.tableFooterView = UIView(frame: CGRect.zero)
62 | }
63 |
64 | override func viewDidAppear(_ animated: Bool) {
65 | super.viewDidAppear(animated)
66 | // Set the initial state of the tableview, called here because cells should be done loading by now
67 | // Number of cells are used to determine if the view should be shown or not
68 | self.reloadEmptyState()
69 | }
70 | }
71 | ```
72 |
73 | Whenever you need to reload the empty state view for example, on data changes to your table view source, make sure to call `self.reloadEmptyState()` if inside a `UITableViewController` or `UICollectionViewController`. If inside a regular `UIViewController` make sure to call the appropriate `reloadEmptyStateForTableView(_:)` or `reloadEmptyStateForCollectionView(_:)` methods.
74 |
75 | Example:
76 |
77 | ```swift
78 | // Inside a UITableViewController subclass
79 |
80 | func foo() {
81 | // My data has changed here, I want to my tableview,
82 | // and in case I no longer have data (user deleted, etc) also reload empty view
83 | self.tableView.reloadData()
84 | // Reload empty view as well
85 | self.reloadEmptyState()
86 | }
87 |
88 | func deleteFoo() {
89 | // This works too, just call after end updates
90 | tableView.beginUpdates()
91 | fooSource.remove(at: indexPath.row)
92 | tableView.deleteRows(at: [indexPath], with: .automatic)
93 | tableView.endUpdates()
94 | // Call reload of empty state
95 | self.reloadEmptyState()
96 | }
97 | ```
98 |
99 | If you need more help take a look at the example project here (Pokemon nerds, will like it): [Example](https://github.com/luispadron/UIEmptyState/tree/master/UIEmptyStateExample)
100 |
101 | ## Documentation
102 |
103 |
104 | #### [Read the full documentation here](http://htmlpreview.github.io/?https://github.com/luispadron/UIEmptyState/blob/master/docs/index.html)
105 |
106 | ## Example Project
107 |
108 | 1. Clone this repo
109 | 2. Change directory into `Example`
110 | 3. Run `pod install`
111 |
112 |
113 | ## License (MIT)
114 |
115 | ```
116 | Copyright (c) 2017 Luis Padron
117 |
118 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
119 |
120 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
121 |
122 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
123 | ```
124 |
--------------------------------------------------------------------------------
/UIEmptyState.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 |
4 | s.name = "UIEmptyState"
5 | s.version = "5.0.0"
6 | s.summary = "An empty state control to give visually appealing context when building iOS applications."
7 | s.description = <<-DESC
8 | Empty state control which gives context with either a message, image, and buttons to the user when ever there is a reason the state is empty.
9 | Easily conform to the protocol to provide a visually appealing view to an empty table view controller.
10 | DESC
11 | s.homepage = "https://github.com/luispadron/UIEmptyState"
12 | s.screenshots = "https://raw.githubusercontent.com/luispadron/UIEmptyState/master/GitHubAssets/screen1.jpg", "https://raw.githubusercontent.com/luispadron/UIEmptyState/master/GitHubAssets/screen2.jpg", "https://raw.githubusercontent.com/luispadron/UIEmptyState/master/GitHubAssets/screen3.jpg"
13 | s.license = { :type => "MIT", :file => "LICENSE" }
14 | s.author = { "Luis Padron" => "luis@luispadron.com" }
15 | s.social_media_url = "https://luispadron.com"
16 | s.platform = :ios, "12.0"
17 | s.swift_version = '5.3'
18 | s.source = { :git => "https://github.com/luispadron/UIEmptyState.git", :tag => "v#{s.version}" }
19 | s.source_files = "src/UIEmptyState", "src/UIEmptyState/**/*.{h,m}"
20 | end
21 |
22 |
--------------------------------------------------------------------------------
/docs/Classes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Classes Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | UIEmptyState Reference
45 |
46 | Classes Reference
47 |
48 |
49 |
50 |
51 |
86 |
87 |
88 |
89 |
90 |
91 |
Classes
92 |
The following classes are available globally.
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
109 |
110 |
111 |
112 |
113 |
114 |
A UIView which has a stack view and inside the stackview are 1-4 other views
115 | This view is used as the default view for the emptyStateView
in the UIEmptyStateDataSource
116 |
117 |
See more
118 |
119 |
120 |
Declaration
121 |
122 |
Swift
123 |
open class UIEmptyStateView : UIView
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/docs/Extensions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Extensions Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | UIEmptyState Reference
45 |
46 | Extensions Reference
47 |
48 |
49 |
50 |
51 |
86 |
87 |
88 |
89 |
90 |
91 |
Extensions
92 |
The following extensions are available globally.
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
109 |
110 |
111 |
112 |
113 |
114 |
Extension on UIViewController which adds method and computed properties in order to allow empty view creation
115 |
116 |
See more
117 |
118 |
119 |
120 |
121 |
122 |
129 |
130 |
131 |
132 |
133 |
134 |
A convenience extension for UITableViewController which defaults the tableView
135 |
136 |
See more
137 |
138 |
139 |
140 |
141 |
142 |
149 |
150 |
151 |
152 |
153 |
154 |
A convenience extension for UICollectionViewController which defaults the collectionView
155 |
156 |
See more
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/docs/Extensions/UICollectionViewController.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UICollectionViewController Extension Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | UIEmptyState Reference
46 |
47 | UICollectionViewController Extension Reference
48 |
49 |
50 |
51 |
52 |
87 |
88 |
89 |
90 |
91 |
92 |
UICollectionViewController
93 |
A convenience extension for UICollectionViewController which defaults the collectionView
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
110 |
111 |
112 |
113 |
114 |
115 |
Reloads the empty state, defaults the collectionView to self.collectionView
116 |
117 |
118 |
119 |
Declaration
120 |
121 |
Swift
122 |
public func reloadEmptyState ()
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/docs/Extensions/UITableViewController.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UITableViewController Extension Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | UIEmptyState Reference
46 |
47 | UITableViewController Extension Reference
48 |
49 |
50 |
51 |
52 |
87 |
88 |
89 |
90 |
91 |
92 |
UITableViewController
93 |
A convenience extension for UITableViewController which defaults the tableView
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
110 |
111 |
112 |
113 |
114 |
115 |
Reloads the empty state, defaults the tableView to self.tableView
116 |
117 |
118 |
119 |
Declaration
120 |
121 |
Swift
122 |
public func reloadEmptyState ()
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/docs/Extensions/UIViewController.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UIViewController Extension Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | UIEmptyState Reference
46 |
47 | UIViewController Extension Reference
48 |
49 |
50 |
51 |
52 |
87 |
88 |
89 |
90 |
91 |
92 |
UIViewController
93 |
Extension on UIViewController which adds method and computed properties in order to allow empty view creation
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
110 |
111 |
112 |
113 |
114 |
115 |
The data source for the Empty View
116 |
117 |
Default conformance for UIViewController is provided,
118 | however feel free to implement these methods to customize your view.
119 |
120 |
121 |
122 |
Declaration
123 |
128 |
129 |
130 |
131 |
132 |
133 |
140 |
141 |
142 |
143 |
144 |
145 |
The delegate for UIEmptyStateView
146 |
147 |
Important: this delegate and its functions are only used when using UIEmptyStateView.
148 | If you will provide a custom view in the UIEmptyStateDataSource you must handle how this delegate operates
149 |
150 |
151 |
152 |
Declaration
153 |
158 |
159 |
160 |
161 |
162 |
163 |
170 |
171 |
172 |
173 |
174 |
175 |
The method responsible for show and hiding the UIEmptyStateDataSource.viewForEmptyState
view
176 |
177 |
Important:
178 | This should be called whenever changes are made to the tableView data source or after reloading the tableview
179 |
180 |
Do NOT override this method/implement it unless you need custom behavior and know what you are doing.
181 |
182 |
183 |
184 |
Declaration
185 |
186 |
Swift
187 |
public func reloadEmptyStateForTableView ( _ tableView : UITableView )
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
202 |
203 |
204 |
205 |
206 |
207 |
The method responsible for show and hiding the UIEmptyStateDataSource.viewForEmptyState
view
208 |
209 |
Important:
210 | This should be called whenever changes are made to the collection view data source or after reloading the collection view.
211 |
212 |
Do NOT override this method/implement it unless you need custom behavior and know what you are doing.
213 |
214 |
215 |
216 |
Declaration
217 |
218 |
Swift
219 |
public func reloadEmptyStateForCollectionView ( _ collectionView : UICollectionView )
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
237 |
238 |
239 |
240 |
--------------------------------------------------------------------------------
/docs/Protocols.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Protocols Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | UIEmptyState Reference
45 |
46 | Protocols Reference
47 |
48 |
49 |
50 |
51 |
86 |
87 |
88 |
89 |
90 |
91 |
Protocols
92 |
The following protocols are available globally.
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
109 |
110 |
111 |
112 |
113 |
114 |
The data source for the Empty View
115 |
116 |
Default conformance for UIViewContoller is provided,
117 | however feel free to implement these methods to customize your view.
118 |
119 |
See more
120 |
121 |
122 |
Declaration
123 |
124 |
Swift
125 |
public protocol UIEmptyStateDataSource : class
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
144 |
145 |
146 |
147 |
148 |
149 |
The delegate for UIEmptyStateView
150 |
151 |
Important:
152 | This delegate and its functions are only used when using UIEmptyStateView
.
153 | If you will provide a custom view in the UIEmptyStateDataSource
viewForEmptyState
154 | you must handle how this delegate operates
155 |
156 |
See more
157 |
158 |
159 |
Declaration
160 |
161 |
Swift
162 |
public protocol UIEmptyStateDelegate : class
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
180 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/docs/badge.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | documentation
17 |
18 |
19 | documentation
20 |
21 |
22 | 100%
23 |
24 |
25 | 100%
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docs/css/highlight.css:
--------------------------------------------------------------------------------
1 | /* Credit to https://gist.github.com/wataru420/2048287 */
2 | .highlight {
3 | /* Comment */
4 | /* Error */
5 | /* Keyword */
6 | /* Operator */
7 | /* Comment.Multiline */
8 | /* Comment.Preproc */
9 | /* Comment.Single */
10 | /* Comment.Special */
11 | /* Generic.Deleted */
12 | /* Generic.Deleted.Specific */
13 | /* Generic.Emph */
14 | /* Generic.Error */
15 | /* Generic.Heading */
16 | /* Generic.Inserted */
17 | /* Generic.Inserted.Specific */
18 | /* Generic.Output */
19 | /* Generic.Prompt */
20 | /* Generic.Strong */
21 | /* Generic.Subheading */
22 | /* Generic.Traceback */
23 | /* Keyword.Constant */
24 | /* Keyword.Declaration */
25 | /* Keyword.Pseudo */
26 | /* Keyword.Reserved */
27 | /* Keyword.Type */
28 | /* Literal.Number */
29 | /* Literal.String */
30 | /* Name.Attribute */
31 | /* Name.Builtin */
32 | /* Name.Class */
33 | /* Name.Constant */
34 | /* Name.Entity */
35 | /* Name.Exception */
36 | /* Name.Function */
37 | /* Name.Namespace */
38 | /* Name.Tag */
39 | /* Name.Variable */
40 | /* Operator.Word */
41 | /* Text.Whitespace */
42 | /* Literal.Number.Float */
43 | /* Literal.Number.Hex */
44 | /* Literal.Number.Integer */
45 | /* Literal.Number.Oct */
46 | /* Literal.String.Backtick */
47 | /* Literal.String.Char */
48 | /* Literal.String.Doc */
49 | /* Literal.String.Double */
50 | /* Literal.String.Escape */
51 | /* Literal.String.Heredoc */
52 | /* Literal.String.Interpol */
53 | /* Literal.String.Other */
54 | /* Literal.String.Regex */
55 | /* Literal.String.Single */
56 | /* Literal.String.Symbol */
57 | /* Name.Builtin.Pseudo */
58 | /* Name.Variable.Class */
59 | /* Name.Variable.Global */
60 | /* Name.Variable.Instance */
61 | /* Literal.Number.Integer.Long */ }
62 | .highlight .c {
63 | color: #999988;
64 | font-style: italic; }
65 | .highlight .err {
66 | color: #a61717;
67 | background-color: #e3d2d2; }
68 | .highlight .k {
69 | color: #000000;
70 | font-weight: bold; }
71 | .highlight .o {
72 | color: #000000;
73 | font-weight: bold; }
74 | .highlight .cm {
75 | color: #999988;
76 | font-style: italic; }
77 | .highlight .cp {
78 | color: #999999;
79 | font-weight: bold; }
80 | .highlight .c1 {
81 | color: #999988;
82 | font-style: italic; }
83 | .highlight .cs {
84 | color: #999999;
85 | font-weight: bold;
86 | font-style: italic; }
87 | .highlight .gd {
88 | color: #000000;
89 | background-color: #ffdddd; }
90 | .highlight .gd .x {
91 | color: #000000;
92 | background-color: #ffaaaa; }
93 | .highlight .ge {
94 | color: #000000;
95 | font-style: italic; }
96 | .highlight .gr {
97 | color: #aa0000; }
98 | .highlight .gh {
99 | color: #999999; }
100 | .highlight .gi {
101 | color: #000000;
102 | background-color: #ddffdd; }
103 | .highlight .gi .x {
104 | color: #000000;
105 | background-color: #aaffaa; }
106 | .highlight .go {
107 | color: #888888; }
108 | .highlight .gp {
109 | color: #555555; }
110 | .highlight .gs {
111 | font-weight: bold; }
112 | .highlight .gu {
113 | color: #aaaaaa; }
114 | .highlight .gt {
115 | color: #aa0000; }
116 | .highlight .kc {
117 | color: #000000;
118 | font-weight: bold; }
119 | .highlight .kd {
120 | color: #000000;
121 | font-weight: bold; }
122 | .highlight .kp {
123 | color: #000000;
124 | font-weight: bold; }
125 | .highlight .kr {
126 | color: #000000;
127 | font-weight: bold; }
128 | .highlight .kt {
129 | color: #445588; }
130 | .highlight .m {
131 | color: #009999; }
132 | .highlight .s {
133 | color: #d14; }
134 | .highlight .na {
135 | color: #008080; }
136 | .highlight .nb {
137 | color: #0086B3; }
138 | .highlight .nc {
139 | color: #445588;
140 | font-weight: bold; }
141 | .highlight .no {
142 | color: #008080; }
143 | .highlight .ni {
144 | color: #800080; }
145 | .highlight .ne {
146 | color: #990000;
147 | font-weight: bold; }
148 | .highlight .nf {
149 | color: #990000; }
150 | .highlight .nn {
151 | color: #555555; }
152 | .highlight .nt {
153 | color: #000080; }
154 | .highlight .nv {
155 | color: #008080; }
156 | .highlight .ow {
157 | color: #000000;
158 | font-weight: bold; }
159 | .highlight .w {
160 | color: #bbbbbb; }
161 | .highlight .mf {
162 | color: #009999; }
163 | .highlight .mh {
164 | color: #009999; }
165 | .highlight .mi {
166 | color: #009999; }
167 | .highlight .mo {
168 | color: #009999; }
169 | .highlight .sb {
170 | color: #d14; }
171 | .highlight .sc {
172 | color: #d14; }
173 | .highlight .sd {
174 | color: #d14; }
175 | .highlight .s2 {
176 | color: #d14; }
177 | .highlight .se {
178 | color: #d14; }
179 | .highlight .sh {
180 | color: #d14; }
181 | .highlight .si {
182 | color: #d14; }
183 | .highlight .sx {
184 | color: #d14; }
185 | .highlight .sr {
186 | color: #009926; }
187 | .highlight .s1 {
188 | color: #d14; }
189 | .highlight .ss {
190 | color: #990073; }
191 | .highlight .bp {
192 | color: #999999; }
193 | .highlight .vc {
194 | color: #008080; }
195 | .highlight .vg {
196 | color: #008080; }
197 | .highlight .vi {
198 | color: #008080; }
199 | .highlight .il {
200 | color: #009999; }
201 |
--------------------------------------------------------------------------------
/docs/css/jazzy.css:
--------------------------------------------------------------------------------
1 | *, *:before, *:after {
2 | box-sizing: inherit; }
3 |
4 | body {
5 | margin: 0;
6 | background: #fff;
7 | color: #333;
8 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
9 | letter-spacing: .2px;
10 | -webkit-font-smoothing: antialiased;
11 | box-sizing: border-box; }
12 |
13 | h1 {
14 | font-size: 2rem;
15 | font-weight: 700;
16 | margin: 1.275em 0 0.6em; }
17 |
18 | h2 {
19 | font-size: 1.75rem;
20 | font-weight: 700;
21 | margin: 1.275em 0 0.3em; }
22 |
23 | h3 {
24 | font-size: 1.5rem;
25 | font-weight: 700;
26 | margin: 1em 0 0.3em; }
27 |
28 | h4 {
29 | font-size: 1.25rem;
30 | font-weight: 700;
31 | margin: 1.275em 0 0.85em; }
32 |
33 | h5 {
34 | font-size: 1rem;
35 | font-weight: 700;
36 | margin: 1.275em 0 0.85em; }
37 |
38 | h6 {
39 | font-size: 1rem;
40 | font-weight: 700;
41 | margin: 1.275em 0 0.85em;
42 | color: #777; }
43 |
44 | p {
45 | margin: 0 0 1em; }
46 |
47 | ul, ol {
48 | padding: 0 0 0 2em;
49 | margin: 0 0 0.85em; }
50 |
51 | blockquote {
52 | margin: 0 0 0.85em;
53 | padding: 0 15px;
54 | color: #858585;
55 | border-left: 4px solid #e5e5e5; }
56 |
57 | img {
58 | max-width: 100%; }
59 |
60 | a {
61 | color: #4183c4;
62 | text-decoration: none; }
63 | a:hover, a:focus {
64 | outline: 0;
65 | text-decoration: underline; }
66 |
67 | table {
68 | background: #fff;
69 | width: 100%;
70 | border-collapse: collapse;
71 | border-spacing: 0;
72 | overflow: auto;
73 | margin: 0 0 0.85em; }
74 |
75 | tr:nth-child(2n) {
76 | background-color: #fbfbfb; }
77 |
78 | th, td {
79 | padding: 6px 13px;
80 | border: 1px solid #ddd; }
81 |
82 | pre {
83 | margin: 0 0 1.275em;
84 | padding: .85em 1em;
85 | overflow: auto;
86 | background: #f7f7f7;
87 | font-size: .85em;
88 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
89 |
90 | code {
91 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
92 |
93 | p > code, li > code {
94 | background: #f7f7f7;
95 | padding: .2em; }
96 | p > code:before, p > code:after, li > code:before, li > code:after {
97 | letter-spacing: -.2em;
98 | content: "\00a0"; }
99 |
100 | pre code {
101 | padding: 0;
102 | white-space: pre; }
103 |
104 | .content-wrapper {
105 | display: flex;
106 | flex-direction: column; }
107 | @media (min-width: 768px) {
108 | .content-wrapper {
109 | flex-direction: row; } }
110 |
111 | .header {
112 | display: flex;
113 | padding: 8px;
114 | font-size: 0.875em;
115 | background: #444;
116 | color: #999; }
117 |
118 | .header-col {
119 | margin: 0;
120 | padding: 0 8px; }
121 |
122 | .header-col--primary {
123 | flex: 1; }
124 |
125 | .header-link {
126 | color: #fff; }
127 |
128 | .header-icon {
129 | padding-right: 6px;
130 | vertical-align: -4px;
131 | height: 16px; }
132 |
133 | .breadcrumbs {
134 | font-size: 0.875em;
135 | padding: 8px 16px;
136 | margin: 0;
137 | background: #fbfbfb;
138 | border-bottom: 1px solid #ddd; }
139 |
140 | .carat {
141 | height: 10px;
142 | margin: 0 5px; }
143 |
144 | .navigation {
145 | order: 2; }
146 | @media (min-width: 768px) {
147 | .navigation {
148 | order: 1;
149 | width: 25%;
150 | max-width: 300px;
151 | padding-bottom: 64px;
152 | overflow: hidden;
153 | word-wrap: normal;
154 | background: #fbfbfb;
155 | border-right: 1px solid #ddd; } }
156 |
157 | .nav-groups {
158 | list-style-type: none;
159 | padding-left: 0; }
160 |
161 | .nav-group-name {
162 | border-bottom: 1px solid #ddd;
163 | padding: 8px 0 8px 16px; }
164 |
165 | .nav-group-name-link {
166 | color: #333; }
167 |
168 | .nav-group-tasks {
169 | margin: 8px 0;
170 | padding: 0 0 0 8px; }
171 |
172 | .nav-group-task {
173 | font-size: 1em;
174 | list-style-type: none;
175 | white-space: nowrap; }
176 |
177 | .nav-group-task-link {
178 | color: #808080; }
179 |
180 | .main-content {
181 | order: 1; }
182 | @media (min-width: 768px) {
183 | .main-content {
184 | order: 2;
185 | flex: 1;
186 | padding-bottom: 60px; } }
187 |
188 | .section {
189 | padding: 0 32px;
190 | border-bottom: 1px solid #ddd; }
191 |
192 | .section-content {
193 | max-width: 834px;
194 | margin: 0 auto;
195 | padding: 16px 0; }
196 |
197 | .section-name {
198 | color: #666;
199 | display: block; }
200 |
201 | .declaration .highlight {
202 | overflow-x: initial;
203 | padding: 8px 0;
204 | margin: 0;
205 | background-color: transparent;
206 | border: none; }
207 |
208 | .task-group-section {
209 | border-top: 1px solid #ddd; }
210 |
211 | .task-group {
212 | padding-top: 0px; }
213 |
214 | .task-name-container a[name]:before {
215 | content: "";
216 | display: block; }
217 |
218 | .item-container {
219 | padding: 0; }
220 |
221 | .item {
222 | padding-top: 8px;
223 | width: 100%;
224 | list-style-type: none; }
225 | .item a[name]:before {
226 | content: "";
227 | display: block; }
228 | .item .token {
229 | padding-left: 3px;
230 | margin-left: 0px;
231 | font-size: 1rem; }
232 | .item .declaration-note {
233 | font-size: .85em;
234 | color: #808080;
235 | font-style: italic; }
236 |
237 | .pointer-container {
238 | border-bottom: 1px solid #ddd;
239 | left: -23px;
240 | padding-bottom: 13px;
241 | position: relative;
242 | width: 110%; }
243 |
244 | .pointer {
245 | left: 21px;
246 | top: 7px;
247 | display: block;
248 | position: absolute;
249 | width: 12px;
250 | height: 12px;
251 | border-left: 1px solid #ddd;
252 | border-top: 1px solid #ddd;
253 | background: #fff;
254 | transform: rotate(45deg); }
255 |
256 | .height-container {
257 | display: none;
258 | position: relative;
259 | width: 100%;
260 | overflow: hidden; }
261 | .height-container .section {
262 | background: #fff;
263 | border: 1px solid #ddd;
264 | border-top-width: 0;
265 | padding-top: 10px;
266 | padding-bottom: 5px;
267 | padding: 8px 16px; }
268 |
269 | .aside, .language {
270 | padding: 6px 12px;
271 | margin: 12px 0;
272 | border-left: 5px solid #dddddd;
273 | overflow-y: hidden; }
274 | .aside .aside-title, .language .aside-title {
275 | font-size: 9px;
276 | letter-spacing: 2px;
277 | text-transform: uppercase;
278 | padding-bottom: 0;
279 | margin: 0;
280 | color: #aaa;
281 | -webkit-user-select: none; }
282 | .aside p:last-child, .language p:last-child {
283 | margin-bottom: 0; }
284 |
285 | .language {
286 | border-left: 5px solid #cde9f4; }
287 | .language .aside-title {
288 | color: #4183c4; }
289 |
290 | .aside-warning {
291 | border-left: 5px solid #ff6666; }
292 | .aside-warning .aside-title {
293 | color: #ff0000; }
294 |
295 | .graybox {
296 | border-collapse: collapse;
297 | width: 100%; }
298 | .graybox p {
299 | margin: 0;
300 | word-break: break-word;
301 | min-width: 50px; }
302 | .graybox td {
303 | border: 1px solid #ddd;
304 | padding: 5px 25px 5px 10px;
305 | vertical-align: middle; }
306 | .graybox tr td:first-of-type {
307 | text-align: right;
308 | padding: 7px;
309 | vertical-align: top;
310 | word-break: normal;
311 | width: 40px; }
312 |
313 | .slightly-smaller {
314 | font-size: 0.9em; }
315 |
316 | .footer {
317 | padding: 8px 16px;
318 | background: #444;
319 | color: #ddd;
320 | font-size: 0.8em; }
321 | .footer p {
322 | margin: 8px 0; }
323 | .footer a {
324 | color: #fff; }
325 |
326 | html.dash .header, html.dash .breadcrumbs, html.dash .navigation {
327 | display: none; }
328 | html.dash .height-container {
329 | display: block; }
330 |
331 | form[role=search] input {
332 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
333 | font-size: 14px;
334 | line-height: 24px;
335 | padding: 0 10px;
336 | margin: 0;
337 | border: none;
338 | border-radius: 1em; }
339 | .loading form[role=search] input {
340 | background: white url(../img/spinner.gif) center right 4px no-repeat; }
341 | form[role=search] .tt-menu {
342 | margin: 0;
343 | min-width: 300px;
344 | background: #fbfbfb;
345 | color: #333;
346 | border: 1px solid #ddd; }
347 | form[role=search] .tt-highlight {
348 | font-weight: bold; }
349 | form[role=search] .tt-suggestion {
350 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
351 | padding: 0 8px; }
352 | form[role=search] .tt-suggestion span {
353 | display: table-cell;
354 | white-space: nowrap; }
355 | form[role=search] .tt-suggestion .doc-parent-name {
356 | width: 100%;
357 | text-align: right;
358 | font-weight: normal;
359 | font-size: 0.9em;
360 | padding-left: 16px; }
361 | form[role=search] .tt-suggestion:hover,
362 | form[role=search] .tt-suggestion.tt-cursor {
363 | cursor: pointer;
364 | background-color: #4183c4;
365 | color: #fff; }
366 | form[role=search] .tt-suggestion:hover .doc-parent-name,
367 | form[role=search] .tt-suggestion.tt-cursor .doc-parent-name {
368 | color: #fff; }
369 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | com.jazzy.uiemptystate
7 | CFBundleName
8 | UIEmptyState
9 | DocSetPlatformFamily
10 | uiemptystate
11 | isDashDocset
12 |
13 | dashIndexFilePath
14 | index.html
15 | isJavaScriptEnabled
16 |
17 | DashDocSetFamily
18 | dashtoc
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/Classes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Classes Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | UIEmptyState Reference
45 |
46 | Classes Reference
47 |
48 |
49 |
50 |
51 |
86 |
87 |
88 |
89 |
90 |
91 |
Classes
92 |
The following classes are available globally.
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
109 |
110 |
111 |
112 |
113 |
114 |
A UIView which has a stack view and inside the stackview are 1-4 other views
115 | This view is used as the default view for the emptyStateView
in the UIEmptyStateDataSource
116 |
117 |
See more
118 |
119 |
120 |
Declaration
121 |
122 |
Swift
123 |
open class UIEmptyStateView : UIView
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/Extensions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Extensions Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | UIEmptyState Reference
45 |
46 | Extensions Reference
47 |
48 |
49 |
50 |
51 |
86 |
87 |
88 |
89 |
90 |
91 |
Extensions
92 |
The following extensions are available globally.
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
109 |
110 |
111 |
112 |
113 |
114 |
Extension on UIViewController which adds method and computed properties in order to allow empty view creation
115 |
116 |
See more
117 |
118 |
119 |
120 |
121 |
122 |
129 |
130 |
131 |
132 |
133 |
134 |
A convenience extension for UITableViewController which defaults the tableView
135 |
136 |
See more
137 |
138 |
139 |
140 |
141 |
142 |
149 |
150 |
151 |
152 |
153 |
154 |
A convenience extension for UICollectionViewController which defaults the collectionView
155 |
156 |
See more
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/Extensions/UICollectionViewController.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UICollectionViewController Extension Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | UIEmptyState Reference
46 |
47 | UICollectionViewController Extension Reference
48 |
49 |
50 |
51 |
52 |
87 |
88 |
89 |
90 |
91 |
92 |
UICollectionViewController
93 |
A convenience extension for UICollectionViewController which defaults the collectionView
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
110 |
111 |
112 |
113 |
114 |
115 |
Reloads the empty state, defaults the collectionView to self.collectionView
116 |
117 |
118 |
119 |
Declaration
120 |
121 |
Swift
122 |
public func reloadEmptyState ()
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/Extensions/UITableViewController.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UITableViewController Extension Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | UIEmptyState Reference
46 |
47 | UITableViewController Extension Reference
48 |
49 |
50 |
51 |
52 |
87 |
88 |
89 |
90 |
91 |
92 |
UITableViewController
93 |
A convenience extension for UITableViewController which defaults the tableView
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
110 |
111 |
112 |
113 |
114 |
115 |
Reloads the empty state, defaults the tableView to self.tableView
116 |
117 |
118 |
119 |
Declaration
120 |
121 |
Swift
122 |
public func reloadEmptyState ()
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/Extensions/UIViewController.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UIViewController Extension Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | UIEmptyState Reference
46 |
47 | UIViewController Extension Reference
48 |
49 |
50 |
51 |
52 |
87 |
88 |
89 |
90 |
91 |
92 |
UIViewController
93 |
Extension on UIViewController which adds method and computed properties in order to allow empty view creation
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
110 |
111 |
112 |
113 |
114 |
115 |
The data source for the Empty View
116 |
117 |
Default conformance for UIViewController is provided,
118 | however feel free to implement these methods to customize your view.
119 |
120 |
121 |
122 |
Declaration
123 |
128 |
129 |
130 |
131 |
132 |
133 |
140 |
141 |
142 |
143 |
144 |
145 |
The delegate for UIEmptyStateView
146 |
147 |
Important: this delegate and its functions are only used when using UIEmptyStateView.
148 | If you will provide a custom view in the UIEmptyStateDataSource you must handle how this delegate operates
149 |
150 |
151 |
152 |
Declaration
153 |
158 |
159 |
160 |
161 |
162 |
163 |
170 |
171 |
172 |
173 |
174 |
175 |
The method responsible for show and hiding the UIEmptyStateDataSource.viewForEmptyState
view
176 |
177 |
Important:
178 | This should be called whenever changes are made to the tableView data source or after reloading the tableview
179 |
180 |
Do NOT override this method/implement it unless you need custom behavior and know what you are doing.
181 |
182 |
183 |
184 |
Declaration
185 |
186 |
Swift
187 |
public func reloadEmptyStateForTableView ( _ tableView : UITableView )
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
202 |
203 |
204 |
205 |
206 |
207 |
The method responsible for show and hiding the UIEmptyStateDataSource.viewForEmptyState
view
208 |
209 |
Important:
210 | This should be called whenever changes are made to the collection view data source or after reloading the collection view.
211 |
212 |
Do NOT override this method/implement it unless you need custom behavior and know what you are doing.
213 |
214 |
215 |
216 |
Declaration
217 |
218 |
Swift
219 |
public func reloadEmptyStateForCollectionView ( _ collectionView : UICollectionView )
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
237 |
238 |
239 |
240 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/Protocols.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Protocols Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | UIEmptyState Reference
45 |
46 | Protocols Reference
47 |
48 |
49 |
50 |
51 |
86 |
87 |
88 |
89 |
90 |
91 |
Protocols
92 |
The following protocols are available globally.
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
109 |
110 |
111 |
112 |
113 |
114 |
The data source for the Empty View
115 |
116 |
Default conformance for UIViewContoller is provided,
117 | however feel free to implement these methods to customize your view.
118 |
119 |
See more
120 |
121 |
122 |
Declaration
123 |
124 |
Swift
125 |
public protocol UIEmptyStateDataSource : class
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
144 |
145 |
146 |
147 |
148 |
149 |
The delegate for UIEmptyStateView
150 |
151 |
Important:
152 | This delegate and its functions are only used when using UIEmptyStateView
.
153 | If you will provide a custom view in the UIEmptyStateDataSource
viewForEmptyState
154 | you must handle how this delegate operates
155 |
156 |
See more
157 |
158 |
159 |
Declaration
160 |
161 |
Swift
162 |
public protocol UIEmptyStateDelegate : class
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
180 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/css/highlight.css:
--------------------------------------------------------------------------------
1 | /* Credit to https://gist.github.com/wataru420/2048287 */
2 | .highlight {
3 | /* Comment */
4 | /* Error */
5 | /* Keyword */
6 | /* Operator */
7 | /* Comment.Multiline */
8 | /* Comment.Preproc */
9 | /* Comment.Single */
10 | /* Comment.Special */
11 | /* Generic.Deleted */
12 | /* Generic.Deleted.Specific */
13 | /* Generic.Emph */
14 | /* Generic.Error */
15 | /* Generic.Heading */
16 | /* Generic.Inserted */
17 | /* Generic.Inserted.Specific */
18 | /* Generic.Output */
19 | /* Generic.Prompt */
20 | /* Generic.Strong */
21 | /* Generic.Subheading */
22 | /* Generic.Traceback */
23 | /* Keyword.Constant */
24 | /* Keyword.Declaration */
25 | /* Keyword.Pseudo */
26 | /* Keyword.Reserved */
27 | /* Keyword.Type */
28 | /* Literal.Number */
29 | /* Literal.String */
30 | /* Name.Attribute */
31 | /* Name.Builtin */
32 | /* Name.Class */
33 | /* Name.Constant */
34 | /* Name.Entity */
35 | /* Name.Exception */
36 | /* Name.Function */
37 | /* Name.Namespace */
38 | /* Name.Tag */
39 | /* Name.Variable */
40 | /* Operator.Word */
41 | /* Text.Whitespace */
42 | /* Literal.Number.Float */
43 | /* Literal.Number.Hex */
44 | /* Literal.Number.Integer */
45 | /* Literal.Number.Oct */
46 | /* Literal.String.Backtick */
47 | /* Literal.String.Char */
48 | /* Literal.String.Doc */
49 | /* Literal.String.Double */
50 | /* Literal.String.Escape */
51 | /* Literal.String.Heredoc */
52 | /* Literal.String.Interpol */
53 | /* Literal.String.Other */
54 | /* Literal.String.Regex */
55 | /* Literal.String.Single */
56 | /* Literal.String.Symbol */
57 | /* Name.Builtin.Pseudo */
58 | /* Name.Variable.Class */
59 | /* Name.Variable.Global */
60 | /* Name.Variable.Instance */
61 | /* Literal.Number.Integer.Long */ }
62 | .highlight .c {
63 | color: #999988;
64 | font-style: italic; }
65 | .highlight .err {
66 | color: #a61717;
67 | background-color: #e3d2d2; }
68 | .highlight .k {
69 | color: #000000;
70 | font-weight: bold; }
71 | .highlight .o {
72 | color: #000000;
73 | font-weight: bold; }
74 | .highlight .cm {
75 | color: #999988;
76 | font-style: italic; }
77 | .highlight .cp {
78 | color: #999999;
79 | font-weight: bold; }
80 | .highlight .c1 {
81 | color: #999988;
82 | font-style: italic; }
83 | .highlight .cs {
84 | color: #999999;
85 | font-weight: bold;
86 | font-style: italic; }
87 | .highlight .gd {
88 | color: #000000;
89 | background-color: #ffdddd; }
90 | .highlight .gd .x {
91 | color: #000000;
92 | background-color: #ffaaaa; }
93 | .highlight .ge {
94 | color: #000000;
95 | font-style: italic; }
96 | .highlight .gr {
97 | color: #aa0000; }
98 | .highlight .gh {
99 | color: #999999; }
100 | .highlight .gi {
101 | color: #000000;
102 | background-color: #ddffdd; }
103 | .highlight .gi .x {
104 | color: #000000;
105 | background-color: #aaffaa; }
106 | .highlight .go {
107 | color: #888888; }
108 | .highlight .gp {
109 | color: #555555; }
110 | .highlight .gs {
111 | font-weight: bold; }
112 | .highlight .gu {
113 | color: #aaaaaa; }
114 | .highlight .gt {
115 | color: #aa0000; }
116 | .highlight .kc {
117 | color: #000000;
118 | font-weight: bold; }
119 | .highlight .kd {
120 | color: #000000;
121 | font-weight: bold; }
122 | .highlight .kp {
123 | color: #000000;
124 | font-weight: bold; }
125 | .highlight .kr {
126 | color: #000000;
127 | font-weight: bold; }
128 | .highlight .kt {
129 | color: #445588; }
130 | .highlight .m {
131 | color: #009999; }
132 | .highlight .s {
133 | color: #d14; }
134 | .highlight .na {
135 | color: #008080; }
136 | .highlight .nb {
137 | color: #0086B3; }
138 | .highlight .nc {
139 | color: #445588;
140 | font-weight: bold; }
141 | .highlight .no {
142 | color: #008080; }
143 | .highlight .ni {
144 | color: #800080; }
145 | .highlight .ne {
146 | color: #990000;
147 | font-weight: bold; }
148 | .highlight .nf {
149 | color: #990000; }
150 | .highlight .nn {
151 | color: #555555; }
152 | .highlight .nt {
153 | color: #000080; }
154 | .highlight .nv {
155 | color: #008080; }
156 | .highlight .ow {
157 | color: #000000;
158 | font-weight: bold; }
159 | .highlight .w {
160 | color: #bbbbbb; }
161 | .highlight .mf {
162 | color: #009999; }
163 | .highlight .mh {
164 | color: #009999; }
165 | .highlight .mi {
166 | color: #009999; }
167 | .highlight .mo {
168 | color: #009999; }
169 | .highlight .sb {
170 | color: #d14; }
171 | .highlight .sc {
172 | color: #d14; }
173 | .highlight .sd {
174 | color: #d14; }
175 | .highlight .s2 {
176 | color: #d14; }
177 | .highlight .se {
178 | color: #d14; }
179 | .highlight .sh {
180 | color: #d14; }
181 | .highlight .si {
182 | color: #d14; }
183 | .highlight .sx {
184 | color: #d14; }
185 | .highlight .sr {
186 | color: #009926; }
187 | .highlight .s1 {
188 | color: #d14; }
189 | .highlight .ss {
190 | color: #990073; }
191 | .highlight .bp {
192 | color: #999999; }
193 | .highlight .vc {
194 | color: #008080; }
195 | .highlight .vg {
196 | color: #008080; }
197 | .highlight .vi {
198 | color: #008080; }
199 | .highlight .il {
200 | color: #009999; }
201 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/css/jazzy.css:
--------------------------------------------------------------------------------
1 | *, *:before, *:after {
2 | box-sizing: inherit; }
3 |
4 | body {
5 | margin: 0;
6 | background: #fff;
7 | color: #333;
8 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
9 | letter-spacing: .2px;
10 | -webkit-font-smoothing: antialiased;
11 | box-sizing: border-box; }
12 |
13 | h1 {
14 | font-size: 2rem;
15 | font-weight: 700;
16 | margin: 1.275em 0 0.6em; }
17 |
18 | h2 {
19 | font-size: 1.75rem;
20 | font-weight: 700;
21 | margin: 1.275em 0 0.3em; }
22 |
23 | h3 {
24 | font-size: 1.5rem;
25 | font-weight: 700;
26 | margin: 1em 0 0.3em; }
27 |
28 | h4 {
29 | font-size: 1.25rem;
30 | font-weight: 700;
31 | margin: 1.275em 0 0.85em; }
32 |
33 | h5 {
34 | font-size: 1rem;
35 | font-weight: 700;
36 | margin: 1.275em 0 0.85em; }
37 |
38 | h6 {
39 | font-size: 1rem;
40 | font-weight: 700;
41 | margin: 1.275em 0 0.85em;
42 | color: #777; }
43 |
44 | p {
45 | margin: 0 0 1em; }
46 |
47 | ul, ol {
48 | padding: 0 0 0 2em;
49 | margin: 0 0 0.85em; }
50 |
51 | blockquote {
52 | margin: 0 0 0.85em;
53 | padding: 0 15px;
54 | color: #858585;
55 | border-left: 4px solid #e5e5e5; }
56 |
57 | img {
58 | max-width: 100%; }
59 |
60 | a {
61 | color: #4183c4;
62 | text-decoration: none; }
63 | a:hover, a:focus {
64 | outline: 0;
65 | text-decoration: underline; }
66 |
67 | table {
68 | background: #fff;
69 | width: 100%;
70 | border-collapse: collapse;
71 | border-spacing: 0;
72 | overflow: auto;
73 | margin: 0 0 0.85em; }
74 |
75 | tr:nth-child(2n) {
76 | background-color: #fbfbfb; }
77 |
78 | th, td {
79 | padding: 6px 13px;
80 | border: 1px solid #ddd; }
81 |
82 | pre {
83 | margin: 0 0 1.275em;
84 | padding: .85em 1em;
85 | overflow: auto;
86 | background: #f7f7f7;
87 | font-size: .85em;
88 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
89 |
90 | code {
91 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
92 |
93 | p > code, li > code {
94 | background: #f7f7f7;
95 | padding: .2em; }
96 | p > code:before, p > code:after, li > code:before, li > code:after {
97 | letter-spacing: -.2em;
98 | content: "\00a0"; }
99 |
100 | pre code {
101 | padding: 0;
102 | white-space: pre; }
103 |
104 | .content-wrapper {
105 | display: flex;
106 | flex-direction: column; }
107 | @media (min-width: 768px) {
108 | .content-wrapper {
109 | flex-direction: row; } }
110 |
111 | .header {
112 | display: flex;
113 | padding: 8px;
114 | font-size: 0.875em;
115 | background: #444;
116 | color: #999; }
117 |
118 | .header-col {
119 | margin: 0;
120 | padding: 0 8px; }
121 |
122 | .header-col--primary {
123 | flex: 1; }
124 |
125 | .header-link {
126 | color: #fff; }
127 |
128 | .header-icon {
129 | padding-right: 6px;
130 | vertical-align: -4px;
131 | height: 16px; }
132 |
133 | .breadcrumbs {
134 | font-size: 0.875em;
135 | padding: 8px 16px;
136 | margin: 0;
137 | background: #fbfbfb;
138 | border-bottom: 1px solid #ddd; }
139 |
140 | .carat {
141 | height: 10px;
142 | margin: 0 5px; }
143 |
144 | .navigation {
145 | order: 2; }
146 | @media (min-width: 768px) {
147 | .navigation {
148 | order: 1;
149 | width: 25%;
150 | max-width: 300px;
151 | padding-bottom: 64px;
152 | overflow: hidden;
153 | word-wrap: normal;
154 | background: #fbfbfb;
155 | border-right: 1px solid #ddd; } }
156 |
157 | .nav-groups {
158 | list-style-type: none;
159 | padding-left: 0; }
160 |
161 | .nav-group-name {
162 | border-bottom: 1px solid #ddd;
163 | padding: 8px 0 8px 16px; }
164 |
165 | .nav-group-name-link {
166 | color: #333; }
167 |
168 | .nav-group-tasks {
169 | margin: 8px 0;
170 | padding: 0 0 0 8px; }
171 |
172 | .nav-group-task {
173 | font-size: 1em;
174 | list-style-type: none;
175 | white-space: nowrap; }
176 |
177 | .nav-group-task-link {
178 | color: #808080; }
179 |
180 | .main-content {
181 | order: 1; }
182 | @media (min-width: 768px) {
183 | .main-content {
184 | order: 2;
185 | flex: 1;
186 | padding-bottom: 60px; } }
187 |
188 | .section {
189 | padding: 0 32px;
190 | border-bottom: 1px solid #ddd; }
191 |
192 | .section-content {
193 | max-width: 834px;
194 | margin: 0 auto;
195 | padding: 16px 0; }
196 |
197 | .section-name {
198 | color: #666;
199 | display: block; }
200 |
201 | .declaration .highlight {
202 | overflow-x: initial;
203 | padding: 8px 0;
204 | margin: 0;
205 | background-color: transparent;
206 | border: none; }
207 |
208 | .task-group-section {
209 | border-top: 1px solid #ddd; }
210 |
211 | .task-group {
212 | padding-top: 0px; }
213 |
214 | .task-name-container a[name]:before {
215 | content: "";
216 | display: block; }
217 |
218 | .item-container {
219 | padding: 0; }
220 |
221 | .item {
222 | padding-top: 8px;
223 | width: 100%;
224 | list-style-type: none; }
225 | .item a[name]:before {
226 | content: "";
227 | display: block; }
228 | .item .token {
229 | padding-left: 3px;
230 | margin-left: 0px;
231 | font-size: 1rem; }
232 | .item .declaration-note {
233 | font-size: .85em;
234 | color: #808080;
235 | font-style: italic; }
236 |
237 | .pointer-container {
238 | border-bottom: 1px solid #ddd;
239 | left: -23px;
240 | padding-bottom: 13px;
241 | position: relative;
242 | width: 110%; }
243 |
244 | .pointer {
245 | left: 21px;
246 | top: 7px;
247 | display: block;
248 | position: absolute;
249 | width: 12px;
250 | height: 12px;
251 | border-left: 1px solid #ddd;
252 | border-top: 1px solid #ddd;
253 | background: #fff;
254 | transform: rotate(45deg); }
255 |
256 | .height-container {
257 | display: none;
258 | position: relative;
259 | width: 100%;
260 | overflow: hidden; }
261 | .height-container .section {
262 | background: #fff;
263 | border: 1px solid #ddd;
264 | border-top-width: 0;
265 | padding-top: 10px;
266 | padding-bottom: 5px;
267 | padding: 8px 16px; }
268 |
269 | .aside, .language {
270 | padding: 6px 12px;
271 | margin: 12px 0;
272 | border-left: 5px solid #dddddd;
273 | overflow-y: hidden; }
274 | .aside .aside-title, .language .aside-title {
275 | font-size: 9px;
276 | letter-spacing: 2px;
277 | text-transform: uppercase;
278 | padding-bottom: 0;
279 | margin: 0;
280 | color: #aaa;
281 | -webkit-user-select: none; }
282 | .aside p:last-child, .language p:last-child {
283 | margin-bottom: 0; }
284 |
285 | .language {
286 | border-left: 5px solid #cde9f4; }
287 | .language .aside-title {
288 | color: #4183c4; }
289 |
290 | .aside-warning {
291 | border-left: 5px solid #ff6666; }
292 | .aside-warning .aside-title {
293 | color: #ff0000; }
294 |
295 | .graybox {
296 | border-collapse: collapse;
297 | width: 100%; }
298 | .graybox p {
299 | margin: 0;
300 | word-break: break-word;
301 | min-width: 50px; }
302 | .graybox td {
303 | border: 1px solid #ddd;
304 | padding: 5px 25px 5px 10px;
305 | vertical-align: middle; }
306 | .graybox tr td:first-of-type {
307 | text-align: right;
308 | padding: 7px;
309 | vertical-align: top;
310 | word-break: normal;
311 | width: 40px; }
312 |
313 | .slightly-smaller {
314 | font-size: 0.9em; }
315 |
316 | .footer {
317 | padding: 8px 16px;
318 | background: #444;
319 | color: #ddd;
320 | font-size: 0.8em; }
321 | .footer p {
322 | margin: 8px 0; }
323 | .footer a {
324 | color: #fff; }
325 |
326 | html.dash .header, html.dash .breadcrumbs, html.dash .navigation {
327 | display: none; }
328 | html.dash .height-container {
329 | display: block; }
330 |
331 | form[role=search] input {
332 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
333 | font-size: 14px;
334 | line-height: 24px;
335 | padding: 0 10px;
336 | margin: 0;
337 | border: none;
338 | border-radius: 1em; }
339 | .loading form[role=search] input {
340 | background: white url(../img/spinner.gif) center right 4px no-repeat; }
341 | form[role=search] .tt-menu {
342 | margin: 0;
343 | min-width: 300px;
344 | background: #fbfbfb;
345 | color: #333;
346 | border: 1px solid #ddd; }
347 | form[role=search] .tt-highlight {
348 | font-weight: bold; }
349 | form[role=search] .tt-suggestion {
350 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
351 | padding: 0 8px; }
352 | form[role=search] .tt-suggestion span {
353 | display: table-cell;
354 | white-space: nowrap; }
355 | form[role=search] .tt-suggestion .doc-parent-name {
356 | width: 100%;
357 | text-align: right;
358 | font-weight: normal;
359 | font-size: 0.9em;
360 | padding-left: 16px; }
361 | form[role=search] .tt-suggestion:hover,
362 | form[role=search] .tt-suggestion.tt-cursor {
363 | cursor: pointer;
364 | background-color: #4183c4;
365 | color: #fff; }
366 | form[role=search] .tt-suggestion:hover .doc-parent-name,
367 | form[role=search] .tt-suggestion.tt-cursor .doc-parent-name {
368 | color: #fff; }
369 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/img/carat.png
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/img/dash.png
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/img/gh.png
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/img/spinner.gif
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | $content = link.parent().parent().next();
27 | $content.slideToggle(animationDuration);
28 |
29 | // Keeps the document from jumping to the hash.
30 | var href = $(this).attr('href');
31 | if (history.pushState) {
32 | history.pushState({}, '', href);
33 | } else {
34 | location.hash = href;
35 | }
36 | event.preventDefault();
37 | });
38 |
39 | // Dumb down quotes within code blocks that delimit strings instead of quotations
40 | // https://github.com/realm/jazzy/issues/714
41 | $("code q").replaceWith(function () {
42 | return ["\"", $(this).contents(), "\""];
43 | });
44 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/Documents/js/jazzy.search.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | var searchIndex = lunr(function() {
3 | this.ref('url');
4 | this.field('name');
5 | });
6 |
7 | var $typeahead = $('[data-typeahead]');
8 | var $form = $typeahead.parents('form');
9 | var searchURL = $form.attr('action');
10 |
11 | function displayTemplate(result) {
12 | return result.name;
13 | }
14 |
15 | function suggestionTemplate(result) {
16 | var t = '';
17 | t += '' + result.name + ' ';
18 | if (result.parent_name) {
19 | t += '' + result.parent_name + ' ';
20 | }
21 | t += '
';
22 | return t;
23 | }
24 |
25 | $typeahead.one('focus', function() {
26 | $form.addClass('loading');
27 |
28 | $.getJSON(searchURL).then(function(searchData) {
29 | $.each(searchData, function (url, doc) {
30 | searchIndex.add({url: url, name: doc.name});
31 | });
32 |
33 | $typeahead.typeahead(
34 | {
35 | highlight: true,
36 | minLength: 3
37 | },
38 | {
39 | limit: 10,
40 | display: displayTemplate,
41 | templates: { suggestion: suggestionTemplate },
42 | source: function(query, sync) {
43 | var results = searchIndex.search(query).map(function(result) {
44 | var doc = searchData[result.ref];
45 | doc.url = result.ref;
46 | return doc;
47 | });
48 | sync(results);
49 | }
50 | }
51 | );
52 | $form.removeClass('loading');
53 | $typeahead.trigger('focus');
54 | });
55 | });
56 |
57 | var baseURL = searchURL.slice(0, -"search.json".length);
58 |
59 | $typeahead.on('typeahead:select', function(e, result) {
60 | window.location = baseURL + result.url;
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.docset/Contents/Resources/docSet.dsidx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/docsets/UIEmptyState.docset/Contents/Resources/docSet.dsidx
--------------------------------------------------------------------------------
/docs/docsets/UIEmptyState.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/docsets/UIEmptyState.tgz
--------------------------------------------------------------------------------
/docs/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/img/carat.png
--------------------------------------------------------------------------------
/docs/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/img/dash.png
--------------------------------------------------------------------------------
/docs/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/img/gh.png
--------------------------------------------------------------------------------
/docs/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luispadron/UIEmptyState/4fb00263b97ee3a513f029244eb73580b605ab71/docs/img/spinner.gif
--------------------------------------------------------------------------------
/docs/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | $content = link.parent().parent().next();
27 | $content.slideToggle(animationDuration);
28 |
29 | // Keeps the document from jumping to the hash.
30 | var href = $(this).attr('href');
31 | if (history.pushState) {
32 | history.pushState({}, '', href);
33 | } else {
34 | location.hash = href;
35 | }
36 | event.preventDefault();
37 | });
38 |
39 | // Dumb down quotes within code blocks that delimit strings instead of quotations
40 | // https://github.com/realm/jazzy/issues/714
41 | $("code q").replaceWith(function () {
42 | return ["\"", $(this).contents(), "\""];
43 | });
44 |
--------------------------------------------------------------------------------
/docs/js/jazzy.search.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | var searchIndex = lunr(function() {
3 | this.ref('url');
4 | this.field('name');
5 | });
6 |
7 | var $typeahead = $('[data-typeahead]');
8 | var $form = $typeahead.parents('form');
9 | var searchURL = $form.attr('action');
10 |
11 | function displayTemplate(result) {
12 | return result.name;
13 | }
14 |
15 | function suggestionTemplate(result) {
16 | var t = '';
17 | t += '' + result.name + ' ';
18 | if (result.parent_name) {
19 | t += '' + result.parent_name + ' ';
20 | }
21 | t += '
';
22 | return t;
23 | }
24 |
25 | $typeahead.one('focus', function() {
26 | $form.addClass('loading');
27 |
28 | $.getJSON(searchURL).then(function(searchData) {
29 | $.each(searchData, function (url, doc) {
30 | searchIndex.add({url: url, name: doc.name});
31 | });
32 |
33 | $typeahead.typeahead(
34 | {
35 | highlight: true,
36 | minLength: 3
37 | },
38 | {
39 | limit: 10,
40 | display: displayTemplate,
41 | templates: { suggestion: suggestionTemplate },
42 | source: function(query, sync) {
43 | var results = searchIndex.search(query).map(function(result) {
44 | var doc = searchData[result.ref];
45 | doc.url = result.ref;
46 | return doc;
47 | });
48 | sync(results);
49 | }
50 | }
51 | );
52 | $form.removeClass('loading');
53 | $typeahead.trigger('focus');
54 | });
55 | });
56 |
57 | var baseURL = searchURL.slice(0, -"search.json".length);
58 |
59 | $typeahead.on('typeahead:select', function(e, result) {
60 | window.location = baseURL + result.url;
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/docs/undocumented.json:
--------------------------------------------------------------------------------
1 | {
2 | "warnings": [
3 |
4 | ],
5 | "source_directory": "/Users/luis/Programming/iOS/UIEmptyState/src"
6 | }
--------------------------------------------------------------------------------
/run-jazzy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | jazzy --clean -a Luis Padron --source-directory src -u https://luispadron.com -m UIEmptyState --module-version 1.0.0 --readme README.md -g https://github.com/luispadron/UIEmptyState --theme fullwidth
4 |
--------------------------------------------------------------------------------
/src/UIEmptyState.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/UIEmptyState.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/UIEmptyState.xcodeproj/xcshareddata/xcschemes/UIEmptyState.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
42 |
48 |
49 |
50 |
51 |
52 |
62 |
63 |
69 |
70 |
71 |
72 |
78 |
79 |
85 |
86 |
87 |
88 |
90 |
91 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/UIEmptyState/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/UIEmptyState/UIEmptyState.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIEmptyState.h
3 | // UIEmptyState
4 | //
5 | // Created by Luis Padron on 1/30/17.
6 | // Copyright © 2017 Luis Padron. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for UIEmptyState.
12 | FOUNDATION_EXPORT double UIEmptyStateVersionNumber;
13 |
14 | //! Project version string for UIEmptyState.
15 | FOUNDATION_EXPORT const unsigned char UIEmptyStateVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/UIEmptyState/UIEmptyStateDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIEmptyStateDelegate.swift
3 | // UIEmptyState
4 | //
5 | // Created by Luis Padron on 1/31/17.
6 | // Copyright © 2017 Luis Padron. All rights reserved.
7 | //
8 |
9 | /**
10 | The delegate for UIEmptyStateView
11 |
12 | **Important:**
13 | This delegate and its functions are only used when using `UIEmptyStateView`.
14 | If you will provide a custom view in the `UIEmptyStateDataSource` `viewForEmptyState`
15 | you must handle how this delegate operates
16 | */
17 | public protocol UIEmptyStateDelegate: class {
18 | /**
19 | The call back for when the `emptyStateView` will be shown on screen
20 |
21 | - parameters:
22 | - view: The view that is will show
23 | */
24 | func emptyStateViewWillShow(view: UIView)
25 |
26 | /**
27 | The call back for when the `emptyStateView` is now shown on screen
28 |
29 | - parameters:
30 | - view: The view that is now shown
31 | */
32 | func emptyStateViewDidShow(view: UIView)
33 |
34 | /**
35 | The call back for when the `emptyStateView` will be hidden
36 |
37 | - parameters:
38 | - view: The view that will be hidden
39 | */
40 | func emptyStateViewWillHide(view: UIView)
41 |
42 | /**
43 | The call back for when the button inside the emptyStateView is tapped
44 |
45 | - parameters:
46 | - button: The button that was tapped
47 | */
48 | func emptyStatebuttonWasTapped(button: UIButton)
49 |
50 | /**
51 | The call back for when the emptyStateView itself is tapped
52 |
53 | - parameters:
54 | - view: The view that was tapped
55 | */
56 | func emptyStateViewWasTapped(view: UIView)
57 |
58 | /**
59 | The call back for when the animation of the emptyStateView is done
60 | - paramaters:
61 | - view: The view which finished animating
62 | - didFinish: Whether the animation finished completely, i.e not interrupted
63 | */
64 | func emptyStateViewAnimationCompleted(for view: UIView, didFinish: Bool)
65 | }
66 |
67 | /// Extension to add default conformance to UIViewController, by default the method bodies are empty
68 | extension UIEmptyStateDelegate where Self: UIViewController {
69 | /// Default empty implementation of `emptyStateViewWillShow`
70 | public func emptyStateViewWillShow(view: UIView) { }
71 | /// Default empty implementation of `emptyStateViewDidShow`
72 | public func emptyStateViewDidShow(view: UIView) { }
73 | /// Default empty implementation of `emptyStateViewWillHide`
74 | public func emptyStateViewWillHide(view: UIView) { }
75 | /// Default empty implementation of `emptyStateButtonWasTapped`
76 | public func emptyStatebuttonWasTapped(button: UIButton) { }
77 | /// Default empty implementation of `emptyStateViewWasTapped`
78 | public func emptyStateViewWasTapped(view: UIView) { }
79 | /// Default empty implementation of `emptyStateViewAnimationCompleted`
80 | public func emptyStateViewAnimationCompleted(for view: UIView, didFinish: Bool) { }
81 | }
82 |
--------------------------------------------------------------------------------
/src/UIEmptyState/UIViewController+UIEmptyState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+UIEmptyState
3 | // UIEmptyState
4 | //
5 | // Created by Luis Padron on 1/31/17.
6 | // Copyright © 2017 Luis Padron. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// Extension on UIViewController which adds method and computed properties in order to allow empty view creation
12 | extension UIViewController {
13 | /// Private struct of keys to be used with objective-c associated objects
14 | private struct Keys {
15 | static var emptyStateView = "com.luispadron.emptyStateView"
16 | static var emptyStateDataSource = "com.luispadron.emptyStateDataSource"
17 | static var emptyStateDelegate = "com.luispadron.emptyStateDelegate"
18 | }
19 |
20 | /**
21 | The data source for the Empty View
22 |
23 | Default conformance for UIViewController is provided,
24 | however feel free to implement these methods to customize your view.
25 | */
26 | public var emptyStateDataSource: UIEmptyStateDataSource? {
27 | get { return objc_getAssociatedObject(self, &Keys.emptyStateDataSource) as? UIEmptyStateDataSource }
28 | set { objc_setAssociatedObject(self, &Keys.emptyStateDataSource, newValue, .OBJC_ASSOCIATION_ASSIGN) }
29 | }
30 |
31 | /**
32 | The delegate for UIEmptyStateView
33 |
34 | **Important:** this delegate and its functions are only used when using UIEmptyStateView.
35 | If you will provide a custom view in the UIEmptyStateDataSource you must handle how this delegate operates
36 | */
37 | public var emptyStateDelegate: UIEmptyStateDelegate? {
38 | get { return objc_getAssociatedObject(self, &Keys.emptyStateDelegate) as? UIEmptyStateDelegate }
39 | set { objc_setAssociatedObject(self, &Keys.emptyStateDelegate, newValue, .OBJC_ASSOCIATION_ASSIGN) }
40 | }
41 |
42 | /**
43 | The empty state view associated to the ViewController
44 |
45 | **Note:**
46 | This view corresponds and is created from
47 | the UIEmptyDataSource method: `func viewForEmptyState() -> UIView`
48 |
49 | To set this view, use `UIEmptyStateDataSource.emptyStateView`.
50 |
51 | By default this view is of type `UIEmptyStateView`
52 | */
53 | private var emptyView: UIView? {
54 | get { return objc_getAssociatedObject(self, &Keys.emptyStateView) as? UIView }
55 | set {
56 | objc_setAssociatedObject(self, &Keys.emptyStateView, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
57 | // Set the views delegate
58 | if let view = emptyView as? UIEmptyStateView { view.delegate = emptyStateDelegate }
59 | }
60 | }
61 |
62 | /**
63 | The method responsible for show and hiding the `UIEmptyStateDataSource.viewForEmptyState` view
64 |
65 | **Important:**
66 | This should be called whenever changes are made to the tableView data source or after reloading the tableview
67 |
68 | Do NOT override this method/implement it unless you need custom behavior and know what you are doing.
69 | */
70 | public func reloadEmptyStateForTableView(_ tableView: UITableView) {
71 | guard let source = emptyStateDataSource, source.emptyStateViewShouldShow(for: tableView) else {
72 | // Call the will hide delegate
73 | if let view = emptyView {
74 | self.emptyStateDelegate?.emptyStateViewWillHide(view: view)
75 | }
76 | // If shouldnt show view remove from superview, enable scrolling again
77 | emptyView?.isHidden = true
78 | tableView.isScrollEnabled = true
79 | // Also return edges for extended layout to the default values, if adjusted
80 | if emptyStateDataSource?.emptyStateViewAdjustsToFitBars ?? false {
81 | self.edgesForExtendedLayout = .all
82 | }
83 | return
84 | }
85 |
86 | // Check whether scrolling for tableview is allowed or not
87 | tableView.isScrollEnabled = source.emptyStateViewCanScroll
88 |
89 | finishReload(for: source, in: tableView)
90 | }
91 |
92 | /**
93 | The method responsible for show and hiding the `UIEmptyStateDataSource.viewForEmptyState` view
94 |
95 | **Important:**
96 | This should be called whenever changes are made to the collection view data source or after reloading the collection view.
97 |
98 | Do NOT override this method/implement it unless you need custom behavior and know what you are doing.
99 | */
100 | public func reloadEmptyStateForCollectionView(_ collectionView: UICollectionView) {
101 | guard let source = emptyStateDataSource,
102 | source.emptyStateViewShouldShow(for: collectionView) else {
103 | // Call the will hide delegate
104 | if let view = emptyView {
105 | self.emptyStateDelegate?.emptyStateViewWillHide(view: view)
106 | }
107 | // If shouldnt show view remove from superview, enable scrolling again
108 | emptyView?.isHidden = true
109 | collectionView.isScrollEnabled = true
110 | // Also return edges for extended layout to the default values, if adjusted
111 | if emptyStateDataSource?.emptyStateViewAdjustsToFitBars ?? false {
112 | self.edgesForExtendedLayout = .all
113 | }
114 | return
115 | }
116 |
117 | // Check to see if scrolling is enabled
118 | collectionView.isScrollEnabled = source.emptyStateViewCanScroll
119 |
120 | finishReload(for: source, in: collectionView)
121 |
122 | }
123 |
124 | /// Finishes the reload, i.e assigns the empty view, and adjusts any other UI
125 | private func finishReload(for source: UIEmptyStateDataSource, in superView: UIView) {
126 | let emptyView = showView(for: source, in: superView)
127 |
128 | // Only add constraints if they haven't already been added
129 | if emptyView.constraints.count <= 2 { // 2, because theres already 2 constraints added to it's subviews
130 | self.createViewConstraints(for: emptyView, in: superView, source: source)
131 | }
132 |
133 | // Return & call the did show view delegate
134 | self.emptyStateDelegate?.emptyStateViewDidShow(view: emptyView)
135 | }
136 |
137 | //// Private helper which creates view contraints for the UIEmptyStateView.
138 | private func createViewConstraints(for view: UIView, in superView: UIView, source: UIEmptyStateDataSource) {
139 |
140 | var centerYOffset: CGFloat?
141 | // Takes into account any extra offset that the table's header view might need, this way
142 | // we get a true center alignment with the table view.
143 | if let tableHeader = (superView as? UITableView)?.tableHeaderView {
144 | centerYOffset = tableHeader.frame.height / 2.0
145 | }
146 |
147 | var centerY = view.centerYAnchor.constraint(equalTo: superView.centerYAnchor)
148 | var centerX = view.centerXAnchor.constraint(equalTo: superView.centerXAnchor, constant: centerYOffset ?? 0)
149 | centerX.isActive = true
150 | centerY.isActive = true
151 |
152 | // If iOS 11.0 is not available, then adjust the extended layout accordingly using older API
153 | // and then return
154 | guard #available(iOS 11.0, *) else {
155 | // Adjust to fit bars if allowed
156 | if source.emptyStateViewAdjustsToFitBars {
157 | self.edgesForExtendedLayout = []
158 | } else {
159 | self.edgesForExtendedLayout = .all
160 | }
161 | return
162 | }
163 |
164 | // iOS 11.0+ is available, thus use new safeAreaLayoutGuide, but only if adjustesToFitBars is true.
165 | // The reason for this is safeAreaLayoutGuide will take into account any bar that may be used
166 | // If for some reason user doesn't want to adjust to bars, then keep the old center constraints
167 | if source.emptyStateViewAdjustsToFitBars {
168 | // Adjust constraint to fit new big title bars, etc
169 | centerX.isActive = false
170 | centerX = view.centerXAnchor.constraint(equalTo: superView.safeAreaLayoutGuide.centerXAnchor)
171 | centerX.isActive = true
172 |
173 | centerY.isActive = false
174 | centerY = view.centerYAnchor.constraint(equalTo: superView.safeAreaLayoutGuide.centerYAnchor,
175 | constant: centerYOffset ?? 0)
176 | centerY.isActive = true
177 |
178 | }
179 | }
180 |
181 | /// Private helper method which will create the empty state view if not created, or show it if hidden
182 | private func showView(for source: UIEmptyStateDataSource, in view: UIView) -> UIView {
183 |
184 | if let createdView = emptyView {
185 | // Call the will show delegate
186 | self.emptyStateDelegate?.emptyStateViewWillShow(view: createdView)
187 | // View has been created, update it and then reshow
188 | createdView.isHidden = false
189 | guard let view = createdView as? UIEmptyStateView else { return createdView }
190 |
191 | view.backgroundColor = source.emptyStateBackgroundColor
192 | view.title = source.emptyStateTitle
193 | view.image = source.emptyStateImage
194 | view.imageSize = source.emptyStateImageSize
195 | view.imageViewTintColor = source.emptyStateImageViewTintColor
196 | view.buttonTitle = source.emptyStateButtonTitle
197 | view.buttonImage = source.emptyStateButtonImage
198 | view.buttonSize = source.emptyStateButtonSize
199 | view.detailMessage = source.emptyStateDetailMessage
200 | view.spacing = source.emptyStateViewSpacing
201 | view.centerYOffset = source.emptyStateViewCenterYOffset
202 | view.backgroundColor = source.emptyStateBackgroundColor
203 |
204 | // Animate now
205 | if source.emptyStateViewCanAnimate && source.emptyStateViewAnimatesEverytime {
206 | DispatchQueue.main.async {
207 | source.emptyStateViewAnimation(
208 | for: view,
209 | animationDuration: source.emptyStateViewAnimationDuration,
210 | completion: { finished in
211 | self.emptyStateDelegate?.emptyStateViewAnimationCompleted(for: view, didFinish: finished)
212 | }
213 | )
214 | }
215 | }
216 |
217 | return view
218 |
219 | } else {
220 | // We can create the view now
221 | let newView = source.emptyStateView
222 | // Call the will show delegate
223 | self.emptyStateDelegate?.emptyStateViewWillShow(view: newView)
224 | // Add to emptyStateView property
225 | emptyView = newView
226 | // Add as a subView, bring it infront of the tableView
227 | view.addSubview(newView)
228 | view.bringSubviewToFront(newView)
229 | // Animate now
230 | if source.emptyStateViewCanAnimate {
231 | DispatchQueue.main.async {
232 | source.emptyStateViewAnimation(
233 | for: newView,
234 | animationDuration: source.emptyStateViewAnimationDuration,
235 | completion: { finished in
236 | self.emptyStateDelegate?.emptyStateViewAnimationCompleted(for: newView, didFinish: finished)
237 | }
238 | )
239 | }
240 | }
241 |
242 | return newView
243 | }
244 | }
245 |
246 | }
247 |
248 | /// A convenience extension for UITableViewController which defaults the tableView
249 | extension UITableViewController {
250 | /// Reloads the empty state, defaults the tableView to `self.tableView`
251 | public func reloadEmptyState() {
252 | self.reloadEmptyStateForTableView(self.tableView)
253 | }
254 | }
255 |
256 | /// A convenience extension for UICollectionViewController which defaults the collectionView
257 | extension UICollectionViewController {
258 | /// Reloads the empty state, defaults the collectionView to `self.collectionView`
259 | public func reloadEmptyState() {
260 | guard let collectionView = self.collectionView else {
261 | print("UIEmptyState ==== WARNING: Tried to reload collectionView's empty state but the collectionView for\n\(self) was nil.")
262 | return
263 | }
264 |
265 | self.reloadEmptyStateForCollectionView(collectionView)
266 | }
267 | }
268 |
269 |
270 |
271 |
--------------------------------------------------------------------------------
/src/UIEmptyStateTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/UIEmptyStateTests/UIEmptyStateTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIEmptyStateTests.swift
3 | // UIEmptyStateTests
4 | //
5 | // Created by Luis Padron on 1/30/17.
6 | // Copyright © 2017 Luis Padron. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import UIEmptyState
11 |
12 | class UIEmptyStateTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------