EZSwiftExtensions/Sources/UIViewExtensions.swift

592 lines
19 KiB
Swift

//
// UIViewExtensions.swift
// EZSwiftExtensions
//
// Created by Goktug Yilmaz on 15/07/15.
// Copyright (c) 2015 Goktug Yilmaz. All rights reserved.
//
import UIKit
// MARK: Custom UIView Initilizers
extension UIView {
/// EZSwiftExtensions
public convenience init(x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat) {
self.init(frame: CGRect(x: x, y: y, width: w, height: h))
}
/// EZSwiftExtensions, puts padding around the view
public convenience init(superView: UIView, padding: CGFloat) {
self.init(frame: CGRect(x: superView.x + padding, y: superView.y + padding, width: superView.w - padding*2, height: superView.h - padding*2))
}
/// EZSwiftExtensions - Copies size of superview
public convenience init(superView: UIView) {
self.init(frame: CGRect(origin: CGPoint.zero, size: superView.size))
}
}
// MARK: Frame Extensions
extension UIView {
/// EZSwiftExtensions, add multiple subviews
public func addSubviews(views: [UIView]) {
views.forEach { eachView in
self.addSubview(eachView)
}
}
//TODO: Add pics to readme
/// EZSwiftExtensions, resizes this view so it fits the largest subview
public func resizeToFitSubviews() {
var width: CGFloat = 0
var height: CGFloat = 0
for someView in self.subviews {
let aView = someView
let newWidth = aView.x + aView.w
let newHeight = aView.y + aView.h
width = max(width, newWidth)
height = max(height, newHeight)
}
frame = CGRect(x: x, y: y, width: width, height: height)
}
/// EZSwiftExtensions, resizes this view so it fits the largest subview
public func resizeToFitSubviews(tagsToIgnore: [Int]) {
var width: CGFloat = 0
var height: CGFloat = 0
for someView in self.subviews {
let aView = someView
if !tagsToIgnore.contains(someView.tag) {
let newWidth = aView.x + aView.w
let newHeight = aView.y + aView.h
width = max(width, newWidth)
height = max(height, newHeight)
}
}
frame = CGRect(x: x, y: y, width: width, height: height)
}
/// EZSwiftExtensions
public func resizeToFitWidth() {
let currentHeight = self.h
self.sizeToFit()
self.h = currentHeight
}
/// EZSwiftExtensions
public func resizeToFitHeight() {
let currentWidth = self.w
self.sizeToFit()
self.w = currentWidth
}
/// EZSwiftExtensions
public var x: CGFloat {
get {
return self.frame.origin.x
} set(value) {
self.frame = CGRect(x: value, y: self.y, width: self.w, height: self.h)
}
}
/// EZSwiftExtensions
public var y: CGFloat {
get {
return self.frame.origin.y
} set(value) {
self.frame = CGRect(x: self.x, y: value, width: self.w, height: self.h)
}
}
/// EZSwiftExtensions
public var w: CGFloat {
get {
return self.frame.size.width
} set(value) {
self.frame = CGRect(x: self.x, y: self.y, width: value, height: self.h)
}
}
/// EZSwiftExtensions
public var h: CGFloat {
get {
return self.frame.size.height
} set(value) {
self.frame = CGRect(x: self.x, y: self.y, width: self.w, height: value)
}
}
/// EZSwiftExtensions
public var left: CGFloat {
get {
return self.x
} set(value) {
self.x = value
}
}
/// EZSwiftExtensions
public var right: CGFloat {
get {
return self.x + self.w
} set(value) {
self.x = value - self.w
}
}
/// EZSwiftExtensions
public var top: CGFloat {
get {
return self.y
} set(value) {
self.y = value
}
}
/// EZSwiftExtensions
public var bottom: CGFloat {
get {
return self.y + self.h
} set(value) {
self.y = value - self.h
}
}
/// EZSwiftExtensions
public var origin: CGPoint {
get {
return self.frame.origin
} set(value) {
self.frame = CGRect(origin: value, size: self.frame.size)
}
}
/// EZSwiftExtensions
public var centerX: CGFloat {
get {
return self.center.x
} set(value) {
self.center.x = value
}
}
/// EZSwiftExtensions
public var centerY: CGFloat {
get {
return self.center.y
} set(value) {
self.center.y = value
}
}
/// EZSwiftExtensions
public var size: CGSize {
get {
return self.frame.size
} set(value) {
self.frame = CGRect(origin: self.frame.origin, size: value)
}
}
/// EZSwiftExtensions
public func leftOffset(offset: CGFloat) -> CGFloat {
return self.left - offset
}
/// EZSwiftExtensions
public func rightOffset(offset: CGFloat) -> CGFloat {
return self.right + offset
}
/// EZSwiftExtensions
public func topOffset(offset: CGFloat) -> CGFloat {
return self.top - offset
}
/// EZSwiftExtensions
public func bottomOffset(offset: CGFloat) -> CGFloat {
return self.bottom + offset
}
//TODO: Add to readme
/// EZSwiftExtensions
public func alignRight(offset: CGFloat) -> CGFloat {
return self.w - offset
}
/// EZSwiftExtensions
public func reorderSubViews(reorder: Bool = false, tagsToIgnore: [Int] = []) -> CGFloat {
var currentHeight: CGFloat = 0
for someView in subviews {
if !tagsToIgnore.contains(someView.tag) && !(someView ).hidden {
if reorder {
let aView = someView
aView.frame = CGRect(x: aView.frame.origin.x, y: currentHeight, width: aView.frame.width, height: aView.frame.height)
}
currentHeight += someView.frame.height
}
}
return currentHeight
}
public func removeSubviews() {
for subview in subviews {
subview.removeFromSuperview()
}
}
/// EZSE: Centers view in superview horizontally
public func centerXInSuperView() {
guard let parentView = superview else {
assertionFailure("EZSwiftExtensions Error: The view \(self) doesn't have a superview")
return
}
self.x = parentView.w/2 - self.w/2
}
/// EZSE: Centers view in superview vertically
public func centerYInSuperView() {
guard let parentView = superview else {
assertionFailure("EZSwiftExtensions Error: The view \(self) doesn't have a superview")
return
}
self.y = parentView.h/2 - self.h/2
}
/// EZSE: Centers view in superview horizontally & vertically
public func centerInSuperView() {
self.centerXInSuperView()
self.centerYInSuperView()
}
}
// MARK: Transform Extensions
extension UIView {
/// EZSwiftExtensions
public func setRotationX(x: CGFloat) {
var transform = CATransform3DIdentity
transform.m34 = 1.0 / -1000.0
transform = CATransform3DRotate(transform, x.degreesToRadians(), 1.0, 0.0, 0.0)
self.layer.transform = transform
}
/// EZSwiftExtensions
public func setRotationY(y: CGFloat) {
var transform = CATransform3DIdentity
transform.m34 = 1.0 / -1000.0
transform = CATransform3DRotate(transform, y.degreesToRadians(), 0.0, 1.0, 0.0)
self.layer.transform = transform
}
/// EZSwiftExtensions
public func setRotationZ(z: CGFloat) {
var transform = CATransform3DIdentity
transform.m34 = 1.0 / -1000.0
transform = CATransform3DRotate(transform, z.degreesToRadians(), 0.0, 0.0, 1.0)
self.layer.transform = transform
}
/// EZSwiftExtensions
public func setRotation(x x: CGFloat, y: CGFloat, z: CGFloat) {
var transform = CATransform3DIdentity
transform.m34 = 1.0 / -1000.0
transform = CATransform3DRotate(transform, x.degreesToRadians(), 1.0, 0.0, 0.0)
transform = CATransform3DRotate(transform, y.degreesToRadians(), 0.0, 1.0, 0.0)
transform = CATransform3DRotate(transform, z.degreesToRadians(), 0.0, 0.0, 1.0)
self.layer.transform = transform
}
/// EZSwiftExtensions
public func setScale(x x: CGFloat, y: CGFloat) {
var transform = CATransform3DIdentity
transform.m34 = 1.0 / -1000.0
transform = CATransform3DScale(transform, x, y, 1)
self.layer.transform = transform
}
}
// MARK: Layer Extensions
extension UIView {
/// EZSwiftExtensions
public func setCornerRadius(radius radius: CGFloat) {
self.layer.cornerRadius = radius
self.layer.masksToBounds = true
}
//TODO: add this to readme
/// EZSwiftExtensions
public func addShadow(offset offset: CGSize, radius: CGFloat, color: UIColor, opacity: Float, cornerRadius: CGFloat? = nil) {
self.layer.shadowOffset = offset
self.layer.shadowRadius = radius
self.layer.shadowOpacity = opacity
self.layer.shadowColor = color.CGColor
if let r = cornerRadius {
self.layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: r).CGPath
}
}
/// EZSwiftExtensions
public func addBorder(width width: CGFloat, color: UIColor) {
layer.borderWidth = width
layer.borderColor = color.CGColor
layer.masksToBounds = true
}
/// EZSwiftExtensions
public func addBorderTop(size size: CGFloat, color: UIColor) {
addBorderUtility(x: 0, y: 0, width: frame.width, height: size, color: color)
}
//TODO: add to readme
/// EZSwiftExtensions
public func addBorderTopWithPadding(size size: CGFloat, color: UIColor, padding: CGFloat) {
addBorderUtility(x: padding, y: 0, width: frame.width - padding*2, height: size, color: color)
}
/// EZSwiftExtensions
public func addBorderBottom(size size: CGFloat, color: UIColor) {
addBorderUtility(x: 0, y: frame.height - size, width: frame.width, height: size, color: color)
}
/// EZSwiftExtensions
public func addBorderLeft(size size: CGFloat, color: UIColor) {
addBorderUtility(x: 0, y: 0, width: size, height: frame.height, color: color)
}
/// EZSwiftExtensions
public func addBorderRight(size size: CGFloat, color: UIColor) {
addBorderUtility(x: frame.width - size, y: 0, width: size, height: frame.height, color: color)
}
/// EZSwiftExtensions
private func addBorderUtility(x x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, color: UIColor) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.frame = CGRect(x: x, y: y, width: width, height: height)
layer.addSublayer(border)
}
//TODO: add this to readme
/// EZSwiftExtensions
public func drawCircle(fillColor fillColor: UIColor, strokeColor: UIColor, strokeWidth: CGFloat) {
let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: self.w, height: self.w), cornerRadius: self.w/2)
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.CGPath
shapeLayer.fillColor = fillColor.CGColor
shapeLayer.strokeColor = strokeColor.CGColor
shapeLayer.lineWidth = strokeWidth
self.layer.addSublayer(shapeLayer)
}
//TODO: add this to readme
/// EZSwiftExtensions
public func drawStroke(width width: CGFloat, color: UIColor) {
let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: self.w, height: self.w), cornerRadius: self.w/2)
let shapeLayer = CAShapeLayer ()
shapeLayer.path = path.CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = color.CGColor
shapeLayer.lineWidth = width
self.layer.addSublayer(shapeLayer)
}
}
private let UIViewAnimationDuration: NSTimeInterval = 1
private let UIViewAnimationSpringDamping: CGFloat = 0.5
private let UIViewAnimationSpringVelocity: CGFloat = 0.5
//TODO: add this to readme
// MARK: Animation Extensions
extension UIView {
/// EZSwiftExtensions
public func spring(animations animations: (() -> Void), completion: ((Bool) -> Void)? = nil) {
spring(duration: UIViewAnimationDuration, animations: animations, completion: completion)
}
/// EZSwiftExtensions
public func spring(duration duration: NSTimeInterval, animations: (() -> Void), completion: ((Bool) -> Void)? = nil) {
UIView.animateWithDuration(
UIViewAnimationDuration,
delay: 0,
usingSpringWithDamping: UIViewAnimationSpringDamping,
initialSpringVelocity: UIViewAnimationSpringVelocity,
options: UIViewAnimationOptions.AllowAnimatedContent,
animations: animations,
completion: completion
)
}
/// EZSwiftExtensions
public func animate(duration duration: NSTimeInterval, animations: (() -> Void), completion: ((Bool) -> Void)? = nil) {
UIView.animateWithDuration(duration, animations: animations, completion: completion)
}
/// EZSwiftExtensions
public func animate(animations animations: (() -> Void), completion: ((Bool) -> Void)? = nil) {
animate(duration: UIViewAnimationDuration, animations: animations, completion: completion)
}
/// EZSwiftExtensions
public func pop() {
setScale(x: 1.1, y: 1.1)
spring(duration: 0.2, animations: { [unowned self] () -> Void in
self.setScale(x: 1, y: 1)
})
}
/// EZSwiftExtensions
public func popBig() {
setScale(x: 1.25, y: 1.25)
spring(duration: 0.2, animations: { [unowned self] () -> Void in
self.setScale(x: 1, y: 1)
})
}
}
//TODO: add this to readme
// MARK: Render Extensions
extension UIView {
/// EZSwiftExtensions
public func toImage () -> UIImage! {
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, 0.0)
drawViewHierarchyInRect(bounds, afterScreenUpdates: false)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
// MARK: Gesture Extensions
extension UIView {
/// http://stackoverflow.com/questions/4660371/how-to-add-a-touch-event-to-a-uiview/32182866#32182866
/// EZSwiftExtensions
public func addTapGesture(tapNumber tapNumber: Int = 1, target: AnyObject, action: Selector) {
let tap = UITapGestureRecognizer(target: target, action: action)
tap.numberOfTapsRequired = tapNumber
addGestureRecognizer(tap)
userInteractionEnabled = true
}
/// EZSwiftExtensions - Make sure you use "[weak self] (gesture) in" if you are using the keyword self inside the closure or there might be a memory leak
public func addTapGesture(tapNumber tapNumber: Int = 1, action: ((UITapGestureRecognizer) -> ())?) {
let tap = BlockTap(tapCount: tapNumber, fingerCount: 1, action: action)
addGestureRecognizer(tap)
userInteractionEnabled = true
}
/// EZSwiftExtensions
public func addSwipeGesture(direction direction: UISwipeGestureRecognizerDirection, numberOfTouches: Int = 1, target: AnyObject, action: Selector) {
let swipe = UISwipeGestureRecognizer(target: target, action: action)
swipe.direction = direction
#if os(iOS)
swipe.numberOfTouchesRequired = numberOfTouches
#endif
addGestureRecognizer(swipe)
userInteractionEnabled = true
}
/// EZSwiftExtensions - Make sure you use "[weak self] (gesture) in" if you are using the keyword self inside the closure or there might be a memory leak
public func addSwipeGesture(direction direction: UISwipeGestureRecognizerDirection, numberOfTouches: Int = 1, action: ((UISwipeGestureRecognizer) -> ())?) {
let swipe = BlockSwipe(direction: direction, fingerCount: numberOfTouches, action: action)
addGestureRecognizer(swipe)
userInteractionEnabled = true
}
/// EZSwiftExtensions
public func addPanGesture(target target: AnyObject, action: Selector) {
let pan = UIPanGestureRecognizer(target: target, action: action)
addGestureRecognizer(pan)
userInteractionEnabled = true
}
/// EZSwiftExtensions - Make sure you use "[weak self] (gesture) in" if you are using the keyword self inside the closure or there might be a memory leak
public func addPanGesture(action action: ((UIPanGestureRecognizer) -> ())?) {
let pan = BlockPan(action: action)
addGestureRecognizer(pan)
userInteractionEnabled = true
}
#if os(iOS)
/// EZSwiftExtensions
public func addPinchGesture(target target: AnyObject, action: Selector) {
let pinch = UIPinchGestureRecognizer(target: target, action: action)
addGestureRecognizer(pinch)
userInteractionEnabled = true
}
#endif
#if os(iOS)
/// EZSwiftExtensions - Make sure you use "[weak self] (gesture) in" if you are using the keyword self inside the closure or there might be a memory leak
public func addPinchGesture(action action: ((UIPinchGestureRecognizer) -> ())?) {
let pinch = BlockPinch(action: action)
addGestureRecognizer(pinch)
userInteractionEnabled = true
}
#endif
/// EZSwiftExtensions
public func addLongPressGesture(target target: AnyObject, action: Selector) {
let longPress = UILongPressGestureRecognizer(target: target, action: action)
addGestureRecognizer(longPress)
userInteractionEnabled = true
}
/// EZSwiftExtensions - Make sure you use "[weak self] (gesture) in" if you are using the keyword self inside the closure or there might be a memory leak
public func addLongPressGesture(action action: ((UILongPressGestureRecognizer) -> ())?) {
let longPress = BlockLongPress(action: action)
addGestureRecognizer(longPress)
userInteractionEnabled = true
}
}
//TODO: add to readme
extension UIView {
/// EZSwiftExtensions [UIRectCorner.TopLeft, UIRectCorner.TopRight]
public func roundCorners(corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.CGPath
self.layer.mask = mask
}
/// EZSwiftExtensions
public func roundView() {
self.layer.cornerRadius = min(self.frame.size.height, self.frame.size.width) / 2
}
}
extension UIView {
///EZSE: Shakes the view for as many number of times as given in the argument.
public func shakeViewForTimes(times: Int) {
let anim = CAKeyframeAnimation(keyPath: "transform")
anim.values = [
NSValue(CATransform3D: CATransform3DMakeTranslation(-5, 0, 0 )),
NSValue(CATransform3D: CATransform3DMakeTranslation( 5, 0, 0 ))
]
anim.autoreverses = true
anim.repeatCount = Float(times)
anim.duration = 7/100
self.layer.addAnimation(anim, forKey: nil)
}
}
extension UIView {
///EZSE: Loops until it finds the top root view. //TODO: Add to readme
func rootView() -> UIView {
guard let parentView = superview else {
return self
}
return parentView.rootView()
}
}