UIButtonにグラデーション、サブタイトル、左右アイコンを付ける例を紹介。
※ このコードにアイコンは付属しません
コード
import UIKit
class WideButton: UIButton {
var stackView = UIStackView(frame: .zero)
var gradientLayer = CAGradientLayer()
var startColor = UIColor(red: 41/255, green: 171/255, blue: 227/255, alpha: 1)
var endColor = UIColor(red: 41/255, green: 171/255, blue: 227/255, alpha: 1)
var title = UILabel()
var subtitle = UILabel()
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.frame.height / 2
self.setTitleColor(UIColor.white, for: UIControl.State.normal)
self.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
title.adjustsFontSizeToFitWidth = true
title.baselineAdjustment = .alignCenters
setLabelScale()
layoutLayerFrame()
}
convenience init() {
self.init(frame: CGRect.zero)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUp()
}
public override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
func setUp() {
self.setTitle("", for: UIControl.State.normal)
stackView.alignment = .firstBaseline
stackView.distribution = .equalSpacing
stackView.spacing = 8
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.isUserInteractionEnabled = false
self.addSubview(stackView)
self.centerYAnchor.constraint(equalTo: stackView.centerYAnchor).isActive = true
self.centerXAnchor.constraint(equalTo: stackView.centerXAnchor).isActive = true
title.font = UIFont.boldSystemFont(ofSize: 18)
title.textColor = UIColor.white
title.isHidden = true
subtitle.font = UIFont.boldSystemFont(ofSize: 15)
subtitle.textColor = UIColor.white
subtitle.isHidden = true
stackView.addArrangedSubview(title)
stackView.addArrangedSubview(subtitle)
}
func setTitle(_ text: String) {
title.text = text
title.isHidden = false
setLabelScale()
}
func setSubTitle(_ text: String) {
subtitle.text = text
subtitle.isHidden = false
setLabelScale()
}
func setGradientColors(_ start: UIColor, _ end: UIColor) {
startColor = start
endColor = end
gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
}
func setLeftIcon(_ imageName: String) {
if let iconImage = UIImage(named: imageName) {
let iconImageView = UIImageView(image: iconImage)
let iconWidth = iconImage.size.width
let iconHeight = iconImage.size.height
iconImageView.frame = CGRect(x: 20, y: (self.frame.height - iconHeight) / 2, width: iconWidth, height: iconHeight)
iconImageView.autoresizingMask = [.flexibleRightMargin]
self.addSubview(iconImageView)
}
}
func setRightIcon(_ imageName: String) {
if let iconImage = UIImage(named: imageName) {
let iconImageView = UIImageView(image: iconImage)
let iconWidth = iconImage.size.width
let iconHeight = iconImage.size.height
iconImageView.frame = CGRect(x: self.frame.width - iconWidth - 20, y: (self.frame.height - iconHeight) / 2, width: iconWidth, height: iconHeight)
iconImageView.autoresizingMask = [.flexibleLeftMargin]
self.addSubview(iconImageView)
}
}
private func layoutLayerFrame() {
gradientLayer.frame = self.bounds
gradientLayer.cornerRadius = self.layer.cornerRadius
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
gradientLayer.removeFromSuperlayer()
self.layer.insertSublayer(gradientLayer, at: 0)
}
private func setLabelScale() {
let labelWidth = title.frame.width + subtitle.frame.width
var scale: CGFloat = 1
if labelWidth > 0 { scale = (frame.width - 100) / labelWidth }
if scale < 1 {
stackView.transform = CGAffineTransform.identity.scaledBy(x: scale, y: scale)
} else {
stackView.transform = CGAffineTransform.identity.scaledBy(x: 1, y: 1)
}
}
}
使い方
以下のように使えます。
ViewController
@IBOutlet weak var gradientButton: WideButton! {
didSet {
gradientButton.setTitle("タイトルです")
gradientButton.setSubTitle("サブタイトル")
gradientButton.setLeftIcon("checkIcon")
gradientButton.setRightIcon("nextIcon")
gradientButton.setGradientColors(.cyan, .red)
}
}
アイコンの呼び出しにはUIImage(named: String)
を使っています。
設定したい画像をAssetCatalogに用意してください。