Edited at

iOS標準っぽいボタンを自作する

More than 3 years have passed since last update.


はじめに

iOS7からUIButtonの見た目がフラットになってしまい、

普通に使うと文字だけの残念なボタンになってしまいました。

今回はそんなiOS標準っぽいボタンを自作してみます。

タッチ処理も含めてのカスタマイズになります。(UIButtonクラスは継承しません)

swiftバージョンは1.2になります

完成版は下記のような感じ↓


実装


クラス

UIViewのサブクラスとしてクラスを作成

import UIKit

class PMFlatButton: UIView {

}


プロパティ

//MARK: Properties

//Public
var lineColor : UIColor = (UIColor(red: 0.294, green: 0.431, blue: 0.988, alpha: 1.000)) {
didSet{
contentView.layer.borderColor = lineColor.CGColor
textLabel.textColor = lineColor
}
}
var disableColor = UIColor.lightGrayColor()
var disableTextColor = UIColor.whiteColor()
var highlightedTextColor = UIColor.whiteColor()
var textLabel : UILabel!

var highlighted : Bool = false {
didSet{
if (highlighted != oldValue){ reloadButtonColors() }
}
}

var enabled : Bool = true {
didSet{
if (enabled != oldValue){
self.userInteractionEnabled = enabled
reloadButtonColors()
}
}
}

//Private
private var contentView : UIView!
private weak var target : AnyObject?
private var selector : Selector?
private var clickHandler: (() -> Void)?

lineColor,highlighted,enabledは値の変更を監視して見た目や挙動を変えられるようにします。


初期化

//MARK: Initializer

override init(frame: CGRect) {
super.init(frame: frame)

self.backgroundColor = UIColor.clearColor()
self.alpha = 1.0

contentView = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame)))
contentView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
contentView.backgroundColor = UIColor.clearColor()
contentView.layer.borderColor = lineColor.CGColor
contentView.layer.borderWidth = 1.0
contentView.layer.cornerRadius = 5.0
contentView.layer.masksToBounds = true
self.addSubview(contentView)

textLabel = UILabel(frame: CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame)))
textLabel.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
textLabel.backgroundColor = UIColor.clearColor()
textLabel.textColor = lineColor
textLabel.numberOfLines = 0
textLabel.textAlignment = NSTextAlignment.Center
textLabel.font = UIFont.systemFontOfSize(14)
self.addSubview(textLabel)
}


パブリックメソッド

文字のセットとクリック時のハンドラー用関数を追加。

UIButtonのSelector方式と、お手軽に使えるクロージャー方式の2つを用意

//MARK: Class Method

func setText(text: NSString){
textLabel.text = text as String
}

func setTarget(target: AnyObject, selector: Selector){
self.target = target;
self.selector = selector
}

func setClickHandler(handler : () -> Void){
self.clickHandler = handler
}


プライベートメソッド

見た目変更用の関数

//MARK: Private Method

private func reloadButtonColors(){
if(enabled == true){
contentView.backgroundColor = (highlighted) ? lineColor : UIColor.clearColor()
textLabel.textColor = (highlighted) ? highlightedTextColor : lineColor
}else{
contentView.backgroundColor = disableColor
contentView.layer.borderColor = disableColor.CGColor
textLabel.textColor = disableTextColor
}
}


 タッチイベント

UIViewのタッチイベント関数を使ってボタンのタッチ判定を実装します

//MARK: Touch Event

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
highlighted = true
}

override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
highlighted = false
}

override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {

let touch = touches.first as? UITouch

var touchPoint : CGPoint = CGPointZero
if let _touch = touch{
touchPoint = _touch.locationInView(self)
}

//タッチ領域から外れた場合はキャンセル扱いにする
if(touchPoint.x > CGRectGetWidth(self.bounds) || touchPoint.x < 0 || touchPoint.y > CGRectGetHeight(self.bounds) || touchPoint.y < 0){
touchesCancelled(touches, withEvent: event)
}
}

override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
if (!highlighted){
return
}

if (target != nil && selector != nil && target!.respondsToSelector(selector!)){
var control : UIControl = UIControl()
control.sendAction(selector!, to: target, forEvent: nil)
}

if (clickHandler != nil){
clickHandler!()
}

highlighted = false
}


使用例

var flatButton : PMFlatButton = PMFlatButton(frame: CGRectMake(0, 0, 200, 50))

flatButton.setText("Flat Button")
//クリックハンドラーは下2行のどちらかを使用
flatButton.setTarget(self, selector: "buttonDidPush:")
flatButton.setClickHandler { () -> Void in
NSLog(__FUNCTION__+" Button clicked")
}
contentView.addSubview(flatButton)

func buttonDidPush(sender : AnyObject){
NSLog(__FUNCTION__+" Button clicked")
}

ソースコードは下記githubにて公開しております。

PMFlatButton_demo_swift - GitHub


終わりに

iOS標準っぽい見た目のボタンができました。

UIViewを継承しているので、いろいろなカスタマイズができます。