Handy UI features that should have been part of UIKit in the first place.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Build Status codebeat badge Version: 1.7.3 Swift: 4.1 Platforms: iOS | tvOS License: MIT



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.


Currently the recommended way of installing this library is via Carthage. Cocoapods is supported, too.

You can of course also just include this framework manually into your project by downloading it or by using git submodules.

Note: This project is ready for Swift 4. Until Xcode 9 is officially released though, you need to use the branch "work/swift4".


Place the following line to your Cartfile:

github "Flinesoft/HandyUIKit" ~> 1.6

Now run carthage update. Then drag & drop the HandyUIKit.framework in the Carthage/build folder to your project. Now you can import HandyUIKit in each class you want to use its features. Refer to the Carthage README for detailed / updated instructions.


Add the line pod 'HandyUIKit' to your target in your Podfile and make sure to include use_frameworks! at the top. The result might look similar to this:

platform :ios, '8.0'

target 'MyAppTarget' do
  pod 'HandyUIKit', '~> 1.6'

Now close your project and run pod install from the command line. Then open the .xcworkspace from within your project folder. Build your project once (with Cmd+B) to update the frameworks known to Xcode. Now you can import HandyUIKit in each class you want to use its features. Refer to CocoaPods.org for detailed / updates instructions.


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.

Feature Overview


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.


Initializes a UIColor with given HLC (LCh) colors normed to ranges from 0 to 1.

let hlcaColor = UIColor(hue: 180/360, luminance: 30/100, chroma: 125/128, alpha: 1)


Returns a tuple with named HLCA parameters for easy access.

hlcaColor.hlca.hue // => 0.5
hlcaColor.hlca.luminance // => 0.3
hlcaColor.hlca.chroma // => 0.97
hlcaColor.hlca.alpha // => 1.0


Returns a tuple with named RGBA parameters for easy access.

let rgbaColor = UIColor(red: 0.1, green: 0.2, blue: 0.3, alpha: 0.4)
rgbaColor.rgba.red // => 0.1
rgbaColor.rgba.green // => 0.2
rgbaColor.rgba.blue // => 0.3
rgbaColor.rgba.alpha // => 0.4


Returns a tuple with named HSBA parameters for easy access.

let hsbaColor = UIColor(hue: 0.1, saturation: 0.2, brightness: 0.3, alpha: 0.4)
hsbaColor.hsba.hue // => 0.1
hsbaColor.hsba.saturation // => 0.2
hsbaColor.hsba.brightness // => 0.3
hsbaColor.hsba.alpha // => 0.4

.change(ChangeableAttribute, by:)

Creates a new UIColor object with a single attribute changed by a given difference using addition.

color.rgba.blue // => 0.3
let newColor = color.change(.blue, by: 0.2)
newColor.rgba.blue // => 0.5

.change(ChangeableAttribute, to:)

Creates a new UIColor object with the value of a single attribute set to a given value.

color.hlca.luminance // => 0.3
let newColor = color.change(.luminance, to: 0.8)
newColor.hlca.luminance // => 0.8



Takes a screenshot of the UIView's content optionally resizing the result to a given size.

let view = UIView(frame: CGRect(width: 500, height: 500))
let subview = UIView(frame: CGRect(width: 200, height: 200))

view.backgroundColor = .blue
subview.backgroundColor = .red

let fullSizeContent = view.toImage() // => <UIImage: width: 500, height: 500>
let downSizedContent = view.toImage(size: CGSize(width: 80, height: 80))
// => <UIImage: width: 80, height: 80>


Adds constraints to the subview so it always has the same size and position as the superview.

view.frame // => {x: 0, y: 0, w: 500, h: 500}
subview.frame // => {x: 150, y: 150, w: 200, h: 200}
subview.frame // => {x: 0, y: 0, w: 500, h: 500}


CGSize.inPixels / CGSize.inPixels(screen:)

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)



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


Calculates and returns the width needed to fit the text into a height-constrained rect.

loremIpsum.width(forFixedHeight: 21, font: UIFont.systemFont(ofSize: 12, weight: UIFontWeightUltraLight))
// => 2351.0390625


A hyphenated NSAttributedString with justified alignment and word wrapping line break mode.

loremIpsum.hyphenated() // => a justified & hyphenated NSAttributedString object

.superscripted(font:) / .subscripted(font:) / .superAndSubscripted(font:)

Superscript and/or subscript part of your strings with the structures ^{superscripted text} and _{subscripted text}.

"x^{2}".superscripted(font: UIFont.systemFont(ofSize: 20, weight: .medium))

Result: x2

"CO_{2}".subscripted(font: UIFont.systemFont(ofSize: 20, weight: .medium))

Result: CO2

"_{20}Ca^{1,0}".superAndSubscripted(font: UIFont.systemFont(ofSize: 20, weight: .regular))

Result: 20Ca1,0



Creates a grayscale version of the image.

let image = UIImage(named: "someImage")!
let grayscaleImage = image.toGrayscale()


Contributions are welcome. Please just open an Issue on GitHub to discuss a point or request a feature or send a Pull Request with your suggestion. If there's a related discussion on the Swift Evolution mailing list, please also post the thread name with a link.

Pull requests with new features will only be accepted when the following are given:

  • The UI feature is handy but not (yet) part of UIKit.
  • Tests for the new feature exist and all tests pass successfully.
  • Usage examples of the new feature are given in the Playgrounds.

Please also try to follow the same syntax and semantic in your commit messages (see rationale here).


This library is released under the MIT License. See LICENSE for details.