The goal of this library is to provide handy UI related features that we feel like they should have been part of the UIKit frameworks themselves. Therefore this library is intended to inherit solutions for common tasks that appear in daily programming and tries to comply to the same naming conventions as already used in the Apple frameworks.
If you like this, please also checkout HandySwift for handy features that didn’t make it into the Swift standard library. It includes additions that are not UI related.
Installation
Currently the recommended way of installing this library is via Carthage. Cocoapods might work, too, but is not tested.
You can of course also just include this framework manually into your project by downloading it or by using git submodules.
Usage
Please have a look at the UsageExamples.playground for a complete list of features provided.
Open the Playground from within the .xcworkspace in order for it to work.
If you are using the RGB color system to define your colors, you definitely should checkout this great blog post on why RGB is a bad choice for most projects (not all, of course). And if you think you found the perfect way of changing the brightness of a color using the HSB system, you’ll be proved wrong there, too. Honestly, it’s worth a read. If you don’t want though: “Luminance” is the keyword here and it is the single most important reason why HandyUIKit integrates native support for the HLC (or sometimes called LCh) color system to the UIColor class. HLC is a more human-understandable transformation of the LAB color space and shares its great advantage of having a single value that you need to change to correctly change the perceived brightness of any given color: The luminance value. And changing the brightness can save you a lot of time when working with colors in apps, as described in the blog post.
init(hue:luminance:chroma:)
Initializes a UIColor with given HLC (LCh) colors normed to ranges from 0 to 1.
Returns a new CGSize object with the width and height converted to true pixels on screen.
let size = CGSize(width: 100, height: 50)
size.inPixels // test this with a Retina screen target
// => {w 200 h 100}
size.inPixels(UIScreen.screens.last!) // pass a different screen
// => {w 50 h 25}
CGPoint.inPixels / CGPoint.inPixels(screen:)
Returns a new CGPoint object with the x and y converted to true pixels on screen.
let point = CGPoint(x: 100, y: 50)
point.inPixels // test this with a Retina screen target
// => {x 200 y 100}
let someScreen = UIScreen.screens.last!
point.inPixels(someScreen) // pass a different screen
// => {x 50 y 25}
CGRect.inPixels / CGRect.inPixels(screen:)
Returns a new CGRect object with the origin and size converted to true pixels on screen.
let rect = CGRect(x: 10, y: 20, width: 100, height: 50)
rect.inPixels // test this with a Retina screen target
// => {x 20 y 40 w 200 h 100}
let someScreen = UIScreen.screens.last!
rect.inPixels(someScreen) // pass a different screen
// => {x 5 y 10 w 50 h 25}
CGRect.init(size:) / CGRect.init(width:height:)
Creates a new CGRect object from origin zero with given size.
let someSize = CGSize(width: 100, height: 50)
let originZeroRect1 = CGRect(size: someSize)
let originZeroRect2 = CGRect(width: 100, height: 50)
StringExtension
.height(forFixedWidth:font:)
Calculates and returns the height needed to fit the text into a width-constrained rect.
let loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
loremIpsum.height(forFixedWidth: 300, font: UIFont.systemFont(ofSize: 14, weight: UIFontWeightBold))
// => 183.77734375
.width(forFixedHeight:font:)
Calculates and returns the width needed to fit the text into a height-constrained rect.
Returns the currently visible view controller if any reachable within the window.
visibleViewController(from:)
Recursively follows navigation controllers, tab bar controllers and modal presented view controllers starting from the given view controller to find the currently visible view controller.
NibLoadable
This is a protocol helper you can make any UIView subclass conform to. The situation where you might want to do this is when you want to design a UIView subclass in a XIB file. In this case, just make your view type conform to NibLoadable like this:
class MyTableViewCell: UITableViewCell, NibLoadable {
// your code
}
By default NibLoadable will search for a file named like your type, for example MyTableViewCell.xib within the project and load it. You can override static var nibName: String to change this behavior if you need to.
Your view must be set as the Files owner within the XIB file, also there must be only one root UIView object (which should just be of type UIView, not your subclass).
Now you can add IBOutlets and IBActions to your subclass and connect them within the XIB file to the Files owner.
In order to make loading work from both code and Storyboards, call loadFromNib() from within your init methods like so:
That’s it, now you should be able to load your custom view types designed within XIBs from code & in Storyboards. For Storyboard usage, simply add a UIView object and change it’s type to your view subclass and everything should work when running your app. To see your custom view within Interface Builder, add @IBDesignable in front of the class declaration.
If you need to do any setup steps after the IBOutlets are loaded, you can override nibDidLoad which can be seen as the analogous to viewDidLoad in view controller in this perspective.
RoundableView
This is an IBDesignable subclass of UIView which provides the cornerRadius to be set right from within Interface Builder. Simply add a UIView object to your IB file and change it’s type to RoundableView and you should see cornerRadius within the property inspector.
TemplateButton
This is an IBDesignable subclass of UIButton which will automatically make the image a mask for the tintColor value by setting the image rendering mode to .alwaysTemplate automatically.
TemplateImageView
This is an IBDesignable subclass of UIImageView which will automatically make the image a mask for the tintColor value by setting the image rendering mode to .alwaysTemplate automatically.
Donation
BartyCrouch was brought to you by Cihat Gündüz in his free time. If you want to thank me and support the development of this project, please make a small donation on PayPal. In case you also like my other open source contributions and articles, please consider motivating me by becoming a sponsor on GitHub or a patron on Patreon.
Thank you very much for any donation, it really helps out a lot! 💯
Installation • Usage • Donation • Issues • Contributing • License
HandyUIKit
The goal of this library is to provide handy UI related features that we feel like they should have been part of the UIKit frameworks themselves. Therefore this library is intended to inherit solutions for common tasks that appear in daily programming and tries to comply to the same naming conventions as already used in the Apple frameworks.
If you like this, please also checkout HandySwift for handy features that didn’t make it into the Swift standard library. It includes additions that are not UI related.
Installation
Currently the recommended way of installing this library is via Carthage. Cocoapods might work, too, but is not tested.
You can of course also just include this framework manually into your project by downloading it or by using git submodules.
Usage
Please have a look at the UsageExamples.playground for a complete list of features provided. Open the Playground from within the
.xcworkspacein order for it to work.Feature Overview
UIColorExtension
init(hue:luminance:chroma:)
Initializes a UIColor with given HLC (LCh) colors normed to ranges from 0 to 1.
.hlca
Returns a tuple with named HLCA parameters for easy access.
.rgba
Returns a tuple with named RGBA parameters for easy access.
.hsba
Returns a tuple with named HSBA parameters for easy access.
.change(ChangeableAttribute, by:)
Creates a new
UIColorobject with a single attribute changed by a given difference using addition..change(ChangeableAttribute, to:)
Creates a new
UIColorobject with the value of a single attribute set to a given value.UIViewExtension
.toImage(size:)
Takes a screenshot of the UIView’s content optionally resizing the result to a given size.
.bindEdgesToSuperview()
Adds constraints to the subview so it always has the same size and position as the superview.
CoreGraphicsExtensions
CGSize.inPixels / CGSize.inPixels(screen:)
Returns a new CGSize object with the width and height converted to true pixels on screen.
CGPoint.inPixels / CGPoint.inPixels(screen:)
Returns a new CGPoint object with the x and y converted to true pixels on screen.
CGRect.inPixels / CGRect.inPixels(screen:)
Returns a new CGRect object with the origin and size converted to true pixels on screen.
CGRect.init(size:) / CGRect.init(width:height:)
Creates a new CGRect object from origin zero with given size.
StringExtension
.height(forFixedWidth:font:)
Calculates and returns the height needed to fit the text into a width-constrained rect.
.width(forFixedHeight:font:)
Calculates and returns the width needed to fit the text into a height-constrained rect.
.hyphenated()
A hyphenated NSAttributedString with justified alignment and word wrapping line break mode.
.superscripted(font:) / .subscripted(font:) / .superAndSubscripted(font:)
Superscript and/or subscript part of your strings with the structures
^{superscripted text}and_{subscripted text}.Result: x2
Result: CO2
Result: 20Ca1,0
UIImageExtension
.toGrayscale()
Creates a grayscale version of the image.
UITableViewExtension
dequeueCell(ofType:, for:)
Returns a reusable table view cell of type
cellTypewith the name of its type as reuse identifier and adds it to the table.dequeueHeaderFooterView(ofType:)
Returns a reusable header or footer view of type
viewTypewith the name of its type as reuse identifier and adds it to the table.registerCell(ofType:)
Registers a nib with the name of
cellTypeif it exists or registers the class of typecellTypeas reusable cell.registerHeaderFooterView(ofType:)
Registers a nib with the name of
viewTypeif it exists or registers the class of typeviewTypeas reusable header footer view.UIWindowExtension
visibleViewController
Returns the currently visible view controller if any reachable within the window.
visibleViewController(from:)
Recursively follows navigation controllers, tab bar controllers and modal presented view controllers starting from the given view controller to find the currently visible view controller.
NibLoadable
This is a protocol helper you can make any
UIViewsubclass conform to. The situation where you might want to do this is when you want to design aUIViewsubclass in a XIB file. In this case, just make your view type conform toNibLoadablelike this:By default
NibLoadablewill search for a file named like your type, for exampleMyTableViewCell.xibwithin the project and load it. You can overridestatic var nibName: Stringto change this behavior if you need to.Your view must be set as the
Files ownerwithin the XIB file, also there must be only one rootUIViewobject (which should just be of typeUIView, not your subclass).Now you can add
IBOutletsandIBActionsto your subclass and connect them within the XIB file to theFiles owner.In order to make loading work from both code and Storyboards, call
loadFromNib()from within your init methods like so:That’s it, now you should be able to load your custom view types designed within XIBs from code & in Storyboards. For Storyboard usage, simply add a
UIViewobject and change it’s type to your view subclass and everything should work when running your app. To see your custom view within Interface Builder, add@IBDesignablein front of the class declaration.If you need to do any setup steps after the IBOutlets are loaded, you can override
nibDidLoadwhich can be seen as the analogous toviewDidLoadin view controller in this perspective.RoundableView
This is an
IBDesignablesubclass ofUIViewwhich provides thecornerRadiusto be set right from within Interface Builder. Simply add aUIViewobject to your IB file and change it’s type toRoundableViewand you should seecornerRadiuswithin the property inspector.TemplateButton
This is an
IBDesignablesubclass ofUIButtonwhich will automatically make theimagea mask for thetintColorvalue by setting the image rendering mode to.alwaysTemplateautomatically.TemplateImageView
This is an
IBDesignablesubclass ofUIImageViewwhich will automatically make theimagea mask for thetintColorvalue by setting the image rendering mode to.alwaysTemplateautomatically.Donation
BartyCrouch was brought to you by Cihat Gündüz in his free time. If you want to thank me and support the development of this project, please make a small donation on PayPal. In case you also like my other open source contributions and articles, please consider motivating me by becoming a sponsor on GitHub or a patron on Patreon.
Thank you very much for any donation, it really helps out a lot! 💯
Contributing
See the file CONTRIBUTING.md.
License
This library is released under the MIT License. See LICENSE for details.