Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
25
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@peromasamune

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

はじめに

iOS7からUIButtonの見た目がフラットになってしまい、
普通に使うと文字だけの残念なボタンになってしまいました。

今回はそんなiOS標準っぽいボタンを自作してみます。
タッチ処理も含めてのカスタマイズになります。(UIButtonクラスは継承しません)

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

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

screen1.png

実装

クラス

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を継承しているので、いろいろなカスタマイズができます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
25
Help us understand the problem. What are the problem?