Created
February 28, 2018 08:11
-
-
Save mukhortov/6a09562b4e07efbdcd293b12616c6bf4 to your computer and use it in GitHub Desktop.
Visibility Toggler UIView Extension
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// VisibilityToggler+UIView.swift | |
// | |
private var associatedPropertyHeight: CGFloat = 0 | |
private var associatedPropertyWidth: CGFloat = 0 | |
extension UIView { | |
fileprivate var visibilityConstraintIdentifier: String { return "UIVisibilityGenerated" } | |
fileprivate var height: CGFloat? { | |
get { | |
return objc_getAssociatedObject(self, &associatedPropertyHeight) as? CGFloat | |
} | |
set(newValue) { | |
objc_setAssociatedObject(self, &associatedPropertyHeight, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) | |
} | |
} | |
fileprivate var width: CGFloat? { | |
get { | |
return objc_getAssociatedObject(self, &associatedPropertyWidth) as? CGFloat | |
} | |
set(newValue) { | |
objc_setAssociatedObject(self, &associatedPropertyWidth, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) | |
} | |
} | |
func updateConstrainedHeight(_ height: CGFloat) { | |
if let constraint = getConstraintBy(type: .height) { | |
constraint.constant = height | |
} | |
self.height = height | |
} | |
func updateConstrainedWidth(_ width: CGFloat) { | |
if let constraint = getConstraintBy(type: .width) { | |
constraint.constant = width | |
} | |
self.width = width | |
} | |
func zeroHeight(animated: Bool = false) { | |
if animated { | |
superview?.layoutIfNeeded() | |
UIView.animate(withDuration: 0.3, animations: { | |
self.zeroHeightContraint() | |
}) | |
} else { | |
zeroHeightContraint() | |
} | |
} | |
private func zeroHeightContraint() { | |
clipsToBounds = true | |
if let constraint = getConstraintBy(type: .height) { | |
if constraint.constant > 0 { | |
self.height = constraint.constant | |
} | |
constraint.constant = 0 | |
superview?.layoutIfNeeded() | |
} | |
} | |
func zeroWidth() { | |
clipsToBounds = true | |
if let constraint = getConstraintBy(type: .width) { | |
if constraint.constant > 0 { | |
self.width = constraint.constant | |
} | |
constraint.constant = 0 | |
superview?.layoutIfNeeded() | |
} | |
} | |
func restoreHeight(animated: Bool = false) { | |
if animated { | |
superview?.layoutIfNeeded() | |
UIView.animate(withDuration: 0.3, animations: { | |
self.restoreHeightConstraint() | |
}) | |
} else { | |
restoreHeightConstraint() | |
} | |
} | |
private func restoreHeightConstraint() { | |
if let constraint = getConstraintBy(type: .height) { | |
if constraint.constant == 0 { | |
if self.height != nil { | |
constraint.constant = self.height! | |
} else { | |
constraint.constant = self.frame.height | |
} | |
if constraint.identifier == visibilityConstraintIdentifier { | |
removeConstraint(constraint) | |
} | |
superview?.layoutIfNeeded() | |
} | |
} | |
} | |
func restoreWidth() { | |
if let constraint = getConstraintBy(type: .width) { | |
if constraint.constant == 0 { | |
if self.width != nil { | |
constraint.constant = self.width! | |
} else { | |
constraint.constant = self.frame.width | |
} | |
if constraint.identifier == visibilityConstraintIdentifier { | |
removeConstraint(constraint) | |
} | |
superview?.layoutIfNeeded() | |
} | |
} | |
} | |
func getConstant(type: NSLayoutAttribute) -> CGFloat? { | |
guard let constraint = getConstraintBy(type: type) else { return nil } | |
return constraint.constant | |
} | |
func isVisible() -> Bool { | |
if let heightConstraint = getConstraintBy(type: .height, createNewIfNotFound: false) { | |
return heightConstraint.constant != 0 && isHidden == false | |
} else if let widthConstraint = getConstraintBy(type: .width, createNewIfNotFound: false) { | |
return widthConstraint.constant != 0 && isHidden == false | |
} | |
return isHidden == false | |
} | |
fileprivate func getConstraintBy(type: NSLayoutAttribute, createNewIfNotFound: Bool = true) -> NSLayoutConstraint? { | |
var returnConstraint: NSLayoutConstraint? = nil | |
for constraint in self.constraints { | |
if constraint.firstAttribute == type && type(of: constraint) == NSLayoutConstraint.self { | |
if returnConstraint == nil { | |
returnConstraint = constraint | |
} else { | |
AppLogWarning("Operating on view with multiple \(type.rawValue) constraints: \(constraint)") | |
} | |
} | |
} | |
if returnConstraint == nil && createNewIfNotFound { | |
let newConstraint = NSLayoutConstraint(item: self, attribute: type, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 0) | |
newConstraint.identifier = visibilityConstraintIdentifier | |
addConstraint(newConstraint) | |
returnConstraint = newConstraint | |
} | |
return returnConstraint | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment