ButtonWithImageAndTitleExtension.swift 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. //
  2. // ButtonWithImageAndTitleExtension.swift
  3. // ButtonWithImageAndTitleDemo
  4. //
  5. // Created by Mervyn Ong on 24/10/14.
  6. // Copyright (c) 2014 mervynokm. All rights reserved.
  7. //
  8. //
  9. // The MIT License (MIT)
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining a copy
  12. // of this software and associated documentation files (the "Software"), to deal
  13. // in the Software without restriction, including without limitation the rights
  14. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. // copies of the Software, and to permit persons to whom the Software is
  16. // furnished to do so, subject to the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be included in all
  19. // copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  27. // SOFTWARE.
  28. import UIKit
  29. @objc extension UIButton {
  30. /// Enum to determine the title position with respect to the button image
  31. ///
  32. /// - top: title above button image
  33. /// - bottom: title below button image
  34. /// - left: title to the left of button image
  35. /// - right: title to the right of button image
  36. @objc enum Position: Int {
  37. case top, bottom, left, right
  38. }
  39. /// This method sets an image and title for a UIButton and
  40. /// repositions the titlePosition with respect to the button image.
  41. ///
  42. /// - Parameters:
  43. /// - image: Button image
  44. /// - title: Button title
  45. /// - titlePosition: UIViewContentModeTop, UIViewContentModeBottom, UIViewContentModeLeft or UIViewContentModeRight
  46. /// - additionalSpacing: Spacing between image and title
  47. /// - state: State to apply this behaviour
  48. @objc func set(image: UIImage?, title: String, titlePosition: Position, additionalSpacing: CGFloat, state: UIControl.State){
  49. imageView?.contentMode = .center
  50. setImage(image, for: state)
  51. setTitle(title, for: state)
  52. titleLabel?.contentMode = .center
  53. adjust(title: title as NSString, at: titlePosition, with: additionalSpacing)
  54. }
  55. /// This method sets an image and an attributed title for a UIButton and
  56. /// repositions the titlePosition with respect to the button image.
  57. ///
  58. /// - Parameters:
  59. /// - image: Button image
  60. /// - title: Button attributed title
  61. /// - titlePosition: UIViewContentModeTop, UIViewContentModeBottom, UIViewContentModeLeft or UIViewContentModeRight
  62. /// - additionalSpacing: Spacing between image and title
  63. /// - state: State to apply this behaviour
  64. @objc func set(image: UIImage?, attributedTitle title: NSAttributedString, at position: Position, width spacing: CGFloat, state: UIControl.State){
  65. imageView?.contentMode = .center
  66. setImage(image, for: state)
  67. adjust(attributedTitle: title, at: position, with: spacing)
  68. titleLabel?.contentMode = .center
  69. setAttributedTitle(title, for: state)
  70. }
  71. // MARK: Private Methods
  72. @objc private func adjust(title: NSString, at position: Position, with spacing: CGFloat) {
  73. let imageRect: CGRect = self.imageRect(forContentRect: frame)
  74. // Use predefined font, otherwise use the default
  75. let titleFont: UIFont = titleLabel?.font ?? UIFont()
  76. let titleSize: CGSize = title.size(withAttributes: [NSAttributedString.Key.font: titleFont])
  77. arrange(titleSize: titleSize, imageRect: imageRect, atPosition: position, withSpacing: spacing)
  78. }
  79. @objc private func adjust(attributedTitle: NSAttributedString, at position: Position, with spacing: CGFloat) {
  80. let imageRect: CGRect = self.imageRect(forContentRect: frame)
  81. let titleSize = attributedTitle.size()
  82. arrange(titleSize: titleSize, imageRect: imageRect, atPosition: position, withSpacing: spacing)
  83. }
  84. @objc private func arrange(titleSize: CGSize, imageRect:CGRect, atPosition position: Position, withSpacing spacing: CGFloat) {
  85. switch (position) {
  86. case .top:
  87. titleEdgeInsets = UIEdgeInsets(top: -(imageRect.height + titleSize.height + spacing), left: -(imageRect.width), bottom: 0, right: 0)
  88. imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -titleSize.width)
  89. contentEdgeInsets = UIEdgeInsets(top: spacing / 2 + titleSize.height, left: -imageRect.width/2, bottom: 0, right: -imageRect.width/2)
  90. case .bottom:
  91. titleEdgeInsets = UIEdgeInsets(top: (imageRect.height + titleSize.height + spacing), left: -(imageRect.width), bottom: 0, right: 0)
  92. imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -titleSize.width)
  93. contentEdgeInsets = UIEdgeInsets(top: 0, left: -imageRect.width/2, bottom: spacing / 2 + titleSize.height, right: -imageRect.width/2)
  94. case .left:
  95. titleEdgeInsets = UIEdgeInsets(top: 0, left: -(imageRect.width * 2), bottom: 0, right: 0)
  96. imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -(titleSize.width * 2 + spacing))
  97. contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: spacing / 2)
  98. case .right:
  99. titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: -spacing)
  100. imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  101. contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: spacing / 2)
  102. }
  103. }
  104. }