Skip to content

Instantly share code, notes, and snippets.

@Josscii
Last active May 3, 2020 07:39
Show Gist options
  • Save Josscii/994088039e557b8ff9b45bd131526456 to your computer and use it in GitHub Desktop.
Save Josscii/994088039e557b8ff9b45bd131526456 to your computer and use it in GitHub Desktop.
支持上下左右图片文字布局的 button,支持 xib
import UIKit
@IBDesignable
class Button: UIButton {
enum TextPosition: Int {
case top
case left
case bottom
case right
}
@IBInspectable private var position: Int {
set {
textPosition = TextPosition(rawValue: newValue) ?? .right
}
get {
return textPosition.rawValue
}
}
var textPosition: TextPosition = .right
@IBInspectable var spacing: CGFloat = 0
// in case frame pixel
func scaleFloor(_ value: CGFloat) -> CGFloat {
return floor(value * UIScreen.main.scale) / UIScreen.main.scale
}
override func layoutSubviews() {
super.layoutSubviews()
if currentImage == nil {
return
}
if currentTitle == nil {
return
}
guard let titleLabel = titleLabel, let imageView = imageView else {
return
}
let textIntrinsicSize = titleLabel.intrinsicContentSize
let imageIntrinsicSize = imageView.intrinsicContentSize
switch textPosition {
case .top:
let textWidth = textIntrinsicSize.width
let textHeight = textIntrinsicSize.height
let imageWidth = imageIntrinsicSize.width
let imageHeight = imageIntrinsicSize.height
let totalHeight = textHeight + spacing + imageHeight
titleLabel.bounds.size = textIntrinsicSize
titleLabel.frame.origin.x = scaleFloor((bounds.width - textWidth)/2)
titleLabel.frame.origin.y = scaleFloor((bounds.height - totalHeight)/2)
imageView.bounds.size = imageIntrinsicSize
imageView.frame.origin.x = scaleFloor((bounds.width - imageWidth)/2)
imageView.frame.origin.y = scaleFloor(titleLabel.frame.maxY) + spacing
case .bottom:
let textWidth = textIntrinsicSize.width
let textHeight = textIntrinsicSize.height
let imageWidth = imageIntrinsicSize.width
let imageHeight = imageIntrinsicSize.height
let totalHeight = imageHeight + spacing + textHeight
imageView.bounds.size = imageIntrinsicSize
imageView.frame.origin.x = scaleFloor((bounds.width - imageWidth)/2)
imageView.frame.origin.y = scaleFloor((bounds.height - totalHeight)/2)
titleLabel.bounds.size = textIntrinsicSize
titleLabel.frame.origin.x = scaleFloor((bounds.width - textWidth)/2)
titleLabel.frame.origin.y = scaleFloor(imageView.frame.maxY) + spacing
case .left:
let imageWidth = imageIntrinsicSize.width
let imageHeight = imageIntrinsicSize.height
let textWidth = textIntrinsicSize.width
let textHeight = textIntrinsicSize.height
let totalWidth = textWidth + spacing + imageWidth
titleLabel.bounds.size = textIntrinsicSize
titleLabel.frame.origin.y = scaleFloor((bounds.height - textHeight)/2)
titleLabel.frame.origin.x = scaleFloor((bounds.width - totalWidth)/2)
imageView.bounds.size = imageIntrinsicSize
imageView.frame.origin.y = scaleFloor((bounds.height - imageHeight)/2)
imageView.frame.origin.x = scaleFloor(titleLabel.frame.maxX) + spacing
case .right:
let imageWidth = imageIntrinsicSize.width
let imageHeight = imageIntrinsicSize.height
let textWidth = textIntrinsicSize.width
let textHeight = textIntrinsicSize.height
let totalWidth = imageWidth + spacing + textWidth
imageView.bounds.size = imageIntrinsicSize
imageView.frame.origin.y = scaleFloor((bounds.height - imageHeight)/2)
imageView.frame.origin.x = scaleFloor((bounds.width - totalWidth)/2)
titleLabel.bounds.size = textIntrinsicSize
titleLabel.frame.origin.y = scaleFloor((bounds.height - textHeight)/2)
titleLabel.frame.origin.x = scaleFloor(imageView.frame.maxX) + spacing
}
}
override var intrinsicContentSize: CGSize {
if currentImage == nil {
return super.intrinsicContentSize
}
if currentTitle == nil {
return super.intrinsicContentSize
}
guard let titleLabel = titleLabel, let imageView = imageView else {
return super.intrinsicContentSize
}
let textSize = titleLabel.intrinsicContentSize
let imageSize = imageView.intrinsicContentSize
switch textPosition {
case .top, .bottom:
let width = contentEdgeInsets.left + max(textSize.width, imageSize.width) + contentEdgeInsets.right
let height = contentEdgeInsets.top + textSize.height + spacing + imageSize.height + contentEdgeInsets.bottom
return CGSize(width: width, height: height)
case .left, .right:
let height = contentEdgeInsets.top + max(textSize.height, imageSize.height) + contentEdgeInsets.bottom
let width = contentEdgeInsets.left + textSize.width + spacing + imageSize.width + contentEdgeInsets.right
return CGSize(width: width, height: height)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment