Skip to content

Instantly share code, notes, and snippets.

@nebiros
Created February 28, 2017 15:39
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save nebiros/ecf69ff9cb90568edde071386c6c4ddb to your computer and use it in GitHub Desktop.
import UIKit
enum LayoutableButtonVerticalAlignment: String {
case center
case top
case bottom
case unset
}
enum LayoutableButtonHorizontalAlignment: String {
case center
case left
case right
case unset
}
@IBDesignable
class LayoutableButton: UIButton {
@IBInspectable
var imageToTitleSpacing: CGFloat = 8.0 {
didSet {
setNeedsLayout()
}
}
var imageVerticalAlignment: LayoutableButtonVerticalAlignment = .unset {
didSet {
setNeedsLayout()
}
}
var imageHorizontalAlignment: LayoutableButtonHorizontalAlignment = .unset {
didSet {
setNeedsLayout()
}
}
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageVerticalAlignment' instead.")
@IBInspectable
var imageVerticalAlignmentName: String! {
willSet {
if let newImageVerticalAlignmentName = LayoutableButtonVerticalAlignment(rawValue: newValue.lowercased()) {
imageVerticalAlignment = newImageVerticalAlignmentName
}
}
}
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageHorizontalAlignmentName' instead.")
@IBInspectable
var imageHorizontalAlignmentName: String! {
willSet {
if let newImageHorizontalAlignmentName = LayoutableButtonHorizontalAlignment(rawValue: newValue.lowercased()) {
imageHorizontalAlignment = newImageHorizontalAlignmentName
}
}
}
var extraContentEdgeInsets: UIEdgeInsets = UIEdgeInsets.zero
override var contentEdgeInsets: UIEdgeInsets {
get {
return super.contentEdgeInsets
}
set {
super.contentEdgeInsets = newValue
self.extraContentEdgeInsets = newValue
}
}
var extraImageEdgeInsets: UIEdgeInsets = UIEdgeInsets.zero
override var imageEdgeInsets: UIEdgeInsets {
get {
return super.imageEdgeInsets
}
set {
super.imageEdgeInsets = newValue
self.extraImageEdgeInsets = newValue
}
}
var extraTitleEdgeInsets: UIEdgeInsets = UIEdgeInsets.zero
override var titleEdgeInsets: UIEdgeInsets {
get {
return super.titleEdgeInsets
}
set {
super.titleEdgeInsets = newValue
self.extraTitleEdgeInsets = newValue
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.imageEdgeInsets = super.imageEdgeInsets
self.titleEdgeInsets = super.titleEdgeInsets
self.contentEdgeInsets = super.contentEdgeInsets
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func layoutSubviews() {
if let imageSize = self.imageView?.image?.size,
let font = self.titleLabel?.font,
let textSize = self.titleLabel?.attributedText?.size() ?? self.titleLabel?.text?.size(attributes: [NSFontAttributeName: font]) {
var imageEdgeInsets = UIEdgeInsets.zero
var titleEdgeInsets = UIEdgeInsets.zero
var contentEdgeInsets = UIEdgeInsets.zero
let halfImageToTitleSpacing = imageToTitleSpacing / 2.0
switch imageVerticalAlignment {
case .bottom:
imageEdgeInsets.top = (textSize.height + imageToTitleSpacing) / 2.0
imageEdgeInsets.bottom = (-textSize.height - imageToTitleSpacing) / 2.0
titleEdgeInsets.top = (-imageSize.height - imageToTitleSpacing) / 2.0
titleEdgeInsets.bottom = (imageSize.height + imageToTitleSpacing) / 2.0
contentEdgeInsets.top = (min(imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
contentEdgeInsets.bottom = (min(imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
case .top:
imageEdgeInsets.top = (-textSize.height - imageToTitleSpacing) / 2.0
imageEdgeInsets.bottom = (textSize.height + imageToTitleSpacing) / 2.0
titleEdgeInsets.top = (imageSize.height + imageToTitleSpacing) / 2.0
titleEdgeInsets.bottom = (-imageSize.height - imageToTitleSpacing) / 2.0
contentEdgeInsets.top = (min(imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
contentEdgeInsets.bottom = (min(imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
case .center:
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
break
case .unset:
break
}
switch imageHorizontalAlignment {
case .left:
imageEdgeInsets.left = -halfImageToTitleSpacing
imageEdgeInsets.right = halfImageToTitleSpacing
titleEdgeInsets.left = halfImageToTitleSpacing
titleEdgeInsets.right = -halfImageToTitleSpacing
contentEdgeInsets.left = halfImageToTitleSpacing
contentEdgeInsets.right = halfImageToTitleSpacing
case .right:
imageEdgeInsets.left = textSize.width + halfImageToTitleSpacing
imageEdgeInsets.right = -textSize.width - halfImageToTitleSpacing
titleEdgeInsets.left = -imageSize.width - halfImageToTitleSpacing
titleEdgeInsets.right = imageSize.width + halfImageToTitleSpacing
contentEdgeInsets.left = halfImageToTitleSpacing
contentEdgeInsets.right = halfImageToTitleSpacing
case .center:
imageEdgeInsets.left = textSize.width / 2.0
imageEdgeInsets.right = -textSize.width / 2.0
titleEdgeInsets.left = -imageSize.width / 2.0
titleEdgeInsets.right = imageSize.width / 2.0
contentEdgeInsets.left = -((imageSize.width + textSize.width) - max(imageSize.width, textSize.width)) / 2.0
contentEdgeInsets.right = -((imageSize.width + textSize.width) - max(imageSize.width, textSize.width)) / 2.0
case .unset:
break
}
contentEdgeInsets.top += extraContentEdgeInsets.top
contentEdgeInsets.bottom += extraContentEdgeInsets.bottom
contentEdgeInsets.left += extraContentEdgeInsets.left
contentEdgeInsets.right += extraContentEdgeInsets.right
imageEdgeInsets.top += extraImageEdgeInsets.top
imageEdgeInsets.bottom += extraImageEdgeInsets.bottom
imageEdgeInsets.left += extraImageEdgeInsets.left
imageEdgeInsets.right += extraImageEdgeInsets.right
titleEdgeInsets.top += extraTitleEdgeInsets.top
titleEdgeInsets.bottom += extraTitleEdgeInsets.bottom
titleEdgeInsets.left += extraTitleEdgeInsets.left
titleEdgeInsets.right += extraTitleEdgeInsets.right
super.imageEdgeInsets = imageEdgeInsets
super.titleEdgeInsets = titleEdgeInsets
super.contentEdgeInsets = contentEdgeInsets
} else {
super.imageEdgeInsets = extraImageEdgeInsets
super.titleEdgeInsets = extraTitleEdgeInsets
super.contentEdgeInsets = extraContentEdgeInsets
}
super.layoutSubviews()
}
}
@nebiros
Copy link
Author

nebiros commented Feb 28, 2017

@hemangshah
Copy link

Hi @Nebrios, how to make it work for the Arabic language? Because when I use the same code for it works totally different.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment