Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

はじめに

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

peromasamune
iOSがメインです(swift,Objective-C)。たまにAndroid、サーバーサイドなど(PHP, Ruby)
http://peromasamune.hateblo.jp/
yumemi
みんなが知ってるあのサービス、実はゆめみが作ってます。スマホアプリ/Webサービスの企画・UX/UI設計、開発運用。Swift, Kotlin, PHP, Vue.js, React.js, Node.js, AWS等エンジニア・クリエイターの会社です。Twitterで情報配信中https://twitter.com/yumemiinc
http://www.yumemi.co.jp
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした