We provide a SearchableCollectionController
, a subclass of SweetCollectionController
that provides the same search functionality that a UITableView
combined with a UISearchController
can provide. That includes attaching the search bar to the bottom of the navigation bar, handling scrolling animations and automatically handling its positioning so that it’s never half-shown. Exactly the same as the native table view behaviour.
Just subclass it, override the following methods and it should be good to go.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
Of course it won’t do much until you also implement the UISearchBar
delegate method.
Here’s a very naive implementation:
extension SearchableCollectionViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.searchTerm = searchText
self.collectionView.reloadData()
}
}
// Before
let cell = tableView.dequeueReusableCell(withIdentifier: "TitleCell", for: indexPath) as! TitleCell
// After
let cell = tableView.dequeue(TitleCell.self, for: indexPath)
// Before
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
// After
let cell = collectionView.dequeue(CollectionViewCell.self, for: indexPath)
Simple protocol extensions to simplify registering a cell in UITableViewController and UICollectionViewController.
Before:
self.tableView.registerClass(ItemCell.self, forCellReuseIdentifier: "ItemCell")
After:
self.tableView.register(ItemCell.self)
Also, accessing the cell identifier is as easy as using ItemCell.reuseIdentifier
.
let alertController = UIAlertController.dismissableAlert(title: "Not allowed access", message: "Please contact your admin to get access.")
self.presentViewController(alertController, animated: true, completion: nil)
let alertController = UIAlertController.destructiveConfirmationAlert(message: "Are you sure you want to log out?", destructiveActionTitle: "Log out") {
self.controllerDelegate?.settingsControllerDidPressLogoutButton(self)
}
self.presentViewController(alertController, animated: true, completion: nil)
let alertController = UIAlertController.errorAlert(error)
self.presentViewController(alertController, animated: true, completion: nil)
let progressAlert = UIAlertController.progressAlert("Creating album...")
self.presentViewController(progressAlert, animated: true, completion: nil)
self.fetcher.createAlbum(title: self.titleTextField.text, photos: self.selectedPhotos) { error in
progressAlert.dismissViewControllerAnimated(true) {
if let error = error {
let alertController = UIAlertController.errorAlert(error)
self.presentViewController(alertController, animated: true, completion: nil)
} else {
// Success
}
}
}
let width = self.usernameLabel.width()
// Do something with new width
Helper class method to create a view from a nib file directly. Supports overriding the bundle and the name of the nib. Takes 4 possible arguments. Nib name, bundle, file owner and options. Same as when using UINib(nibName:bundle).instantiate(withOwner:options:)
.
let myView = MyView.instanceFromNib(nibName: "ViewXibName", bundle: .main)
Set a view’s top, left, right and bottom anchors to be the same as the superviews. Accepts an optional UIEdgeInsets
argument. Values can be all positive for margins, as it handles the negative values for bottom and right constants already.
view.fillSuperview()
anotherView.fillSuperview(UIEdgeInsets(top: 10, left: 10, bottom: 80, right: 10))
view.set(height: 30.0)
view.set(width: 50.0)
Great for toolbars, attaches to view to the top of the superview. Doesn’t set a height. If you pass a view controller, it will attach to viewController.topLayoutGuide.bottomAnchor
instead of superview.topAnchor
.
toolbar.attachToTop(viewController: self)
self.fetcher.authenticate(username, password: password) { clientID, clientSecret, accessToken, refreshToken, expiresIn, error in
if let error = error {
// Update UI to display error
self.tableView.shake()
} else {
// success
}
}
You can resize an image by providing a new height, width or scale rate.
let image = UIImage()
let scaledImage = image.resized(by: 0.5) // CGInterpolationQuality defaults to .medium
let widthImage = image.resized(toWidth: 300) // scales up or down as needed
let heightImage = image.resized(toHeight: 300)
let image = UIImage(named: "art.png")!
let frame = image.centeredFrame()
// Do something with new frame
let image = UIImage(color: .red)
button.setBackgroundImage(image, for: .normal)
or, if you need the image to have specific dimensions
let image = UIImage(color: .red, size: someSize)
Create images using rgba(255,255,255,1.0)
values.
UIColor(r: 200, b: 120, c: 255)
UIColor(r: 200, b: 120, c: 25, 0.5)
let window = self.applicationWindow()
This keyboard aware accessory view is part of your view(controller) and moves with the keyboard.
var keyboardAwareInputView: KeyboardAwareInputAccessoryView { get }
inputView(_:shouldUpdatePosition:)
A bunch of syntactic sugar to help with using CaseIterable
enums to manage sections and rows in static tableviews.
This allows you to use something like
let item = Item.forRow(at: indexPath)
in order to get a known item from a list. Please see the sample app's CaseIterableViewController
for an example.
/// Returns the `allCases` static var as an array so it can be accessed based on index.
public static var allCasesArray: [Self]
Should be used when the number of of cases in allCases
is predictable - usually when automatically generated by the compiler.
These methods will fatalError
if you try to access a case which does not exist.
public static func forIndex(_ index: Int) -> Self
public static func forSection(at indexPath: IndexPath) -> Self
public static func forRow(at indexPath: IndexPath) -> Self
public static func forItem(at indexPath: IndexPath) -> Self
Should be used when the number of cases in allCases
is variable - usually when this var is manually overridden to allow showing/hiding of a section or row.
public static func optionalForIndex(_ index: Int) -> Self?
public static func optionalForSection(at indexPath: IndexPath) -> Self?
public static func optionalForRow(at indexPath: IndexPath) -> Self?
public static func optionalForItem(at indexPath: IndexPath) -> Self?
SweetUIKit is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'SweetUIKit'
SweetUIKit is also available through Carthage. To install it, simply add the following line to your Cartfile:
github "UseSweet/SweetUIKit" ~> 1.0
SweetUIKit is available under the MIT license. See the LICENSE file for more info.
Bakken & Bæck, @use_sweet