72
74

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SwiftAdvent Calendar 2014

Day 9

XcodeのLive Renderingを使って簡単に使い勝手の良いアイコンボタンをつくろう

Last updated at Posted at 2014-12-09

こんばんは。Xcode6になって様々な機能がXcodeに追加されました。その中で、作業的にかなりやりやすくなったLive Renderingについて書いてみたいと思います。とても便利なのにもしかしたらあまり使われていないのかもと思ったからです。Live Renderingとは、UIViewで書いた内容がInterfaceBuilder上にリアルタイムに反映されるというとても便利な機能です。入り込みやすいようにチュートリアル形式にしました。

Live Renderingを利用することでの変化

今まではカスタムのViewをInterfaceBuilderで表示する際、中身がリアルタイムに描画されないので、下記のようになってしまっていました。もしくは、Viewに色を付けずタップしないとどこにカスタムのビューがあるかわからないような状況が発生していました。

morizotter_blogview.png

それがLive Renderingを利用することで、このように実際に端末に表示された時のようにアイコンを見ることができるようになり、より一歩踏み込んだビューの作成ができると思います

morizotter_blogview21.png

それでは実際にLive Renderingを利用したボタンを作ってみたいと思います。

簡単にアイコンボタンを作る

UIControl(UIView+イベントハンドリングができる)を継承したクラスを作成します。そして、下記のコードを書き込みます。 @IBDesignable をクラス宣言の前に書くことで、Live Renderingが有効になります。 @IBInspectable をインスタンス変数の前に書くことで、InterfaceBuilderから値を変更することができるようになります。ここで、

@IBDesignable
class IconButton: UIControl {
    
    @IBInspectable var iconImage: UIImage?
    
    override func drawRect(rect: CGRect) {
        
        if let iconImage = self.iconImage {
            iconImage.drawInRect(self.bounds)
            
            let maskPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: CGRectGetWidth(self.bounds) / 2)
            let maskLayer = CAShapeLayer()
            maskLayer.path = maskPath.CGPath
            self.layer.mask = maskLayer;
        }
    }
}

InterfaceBuilderを開き、UIViewを画面に追加します。そして、クラスを作成したIconButtonに変更します。

morizotter_blogclass.png

すると、InterfaceBuilderでこのような表示を見ることができます。IconButtonで設定したiconImageがInterfaceBuilderから変更できるようになっています。

morizotter_blogicon-image.png

今回は下記の画像を利用することにしました。

morizotter_blogIcon@2x.png

今の時点でInterfaceBuilderはこのようになっています。

morizotter_blognow.png

ここまでのコードは、こちらを御覧ください

ブラッシュアップ

ちょっとさみしいので、枠線を追加したいと思います。

@IBDesignable
class IconButton: UIControl {
    
    @IBInspectable var iconImage: UIImage?
    @IBInspectable var borderColor: UIColor = UIColor.clearColor()
    @IBInspectable var lineWidth: CGFloat = 0.0
    var borderLayer: CAShapeLayer?
    
    override func drawRect(rect: CGRect) {
        
        if let iconImage = self.iconImage {
            iconImage.drawInRect(self.bounds)
        }
        
        let path = UIBezierPath(roundedRect: self.bounds, cornerRadius: CGRectGetWidth(self.bounds) / 2)
        let maskLayer = CAShapeLayer()
        maskLayer.path = path.CGPath
        self.layer.mask = maskLayer;
        
        if self.borderLayer == nil {
            self.borderLayer = CAShapeLayer()
            self.borderLayer!.path = path.CGPath
            self.borderLayer!.fillColor = UIColor.clearColor().CGColor
            self.layer.addSublayer(self.borderLayer!)
        }
        self.borderLayer!.strokeColor = self.borderColor.CGColor
        self.borderLayer!.lineWidth = self.lineWidth
        self.borderLayer!.lineCap = kCALineCapRound
    }
}
View2

attributes Inspectorはこのようになっています。

morizotter_blogattributes.png

ボタンの要素を幾つか追加して簡単にアイコン・ボタンを作ることが出来ました。

更に、アクションやhighlightedの時の変化などを付け加えて、より使い勝手の良いボタンにしました。

@IBDesignable
class IconButton: UIControl {
    
    @IBInspectable var normalImage: UIImage? {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    @IBInspectable var highlightedImage: UIImage? {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    @IBInspectable var normalBorderColor: UIColor = UIColor.clearColor() {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    @IBInspectable var highlightedBorderColor: UIColor = UIColor.clearColor() {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    @IBInspectable var lineWidth: CGFloat = 0.0 {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    lazy var maskLayer: CAShapeLayer = {
        return CAShapeLayer()
    }()
    
    lazy var borderLayer: CAShapeLayer = {
        let borderLayer = CAShapeLayer()
        borderLayer.fillColor = UIColor.clearColor().CGColor
        self.layer.addSublayer(borderLayer)
        return borderLayer
    }()
    
    var circlePath: UIBezierPath {
        get {
            return UIBezierPath(roundedRect: self.bounds, cornerRadius: CGRectGetWidth(self.bounds) / 2)
        }
    }
    
    override var highlighted: Bool {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    override func drawRect(rect: CGRect) {
        
        var iconImage: UIImage?
        var borderColor = UIColor.clearColor()
        if self.highlighted {
            if let highlightedImage = self.highlightedImage {
                iconImage = highlightedImage
                borderColor = self.highlightedBorderColor
            }
        } else {
            if let normalImage = self.normalImage {
                iconImage = normalImage
                borderColor = self.normalBorderColor
            }
        }
        
        iconImage?.drawInRect(self.bounds)
        
        self.maskLayer.path = self.circlePath.CGPath
        self.layer.mask = self.maskLayer
        
        self.borderLayer.path = self.circlePath.CGPath
        self.borderLayer.strokeColor = borderColor.CGColor
        self.borderLayer.lineWidth = self.lineWidth
    }
}

import UIKit

class ViewController: UIViewController {
    
    @IBAction func buttonTapped(sender: IconButton) {
        println("button tapped!")
    }
}

おまけ:利用画像をベクターで

この時点で、どんな形に伸縮しても縦横が同じサイズであればその矩形の大きさのアイコンボタンを作ることが出来ました。ただし、現在、100px x 100pxの表示をするために2倍スケールの200px x 200px の画像を利用していています。このままではiPhone 6Plusのために別に3倍スケールの画像を用意する必要があります。別画像を用意するのではなく、1つの画像を用意するだけで3倍スケールにも対応できるようにvectorを利用しようと思います。

先ほどの画像ファイルは元はIllustratorで作成したものでした。これをIllustratorで開きます。
morizotter_blogillustrator.png

ファイル>複製を保存... を選択し、PDF形式で保存します。

morizotter_blogillustrator-save.png

ダイアログにはこのように返答しました。

morizotter_blogillustrator-dialog.png

ImageAssetsのTypesをVectorsに変更します。

morizotter_blogassets.png

これでVector画像を扱えるようになりました。今回は100px x 100px のpdfを書き出してセットしています。ビルドをする際にXcodeがscale毎のビットマップ画像(@1x, @2x, @3x)を出力してくれるということです。

Live Renderingを利用することで、開発が更に楽しくなると思っています!ちなみに最後になりましたが、この機能はObjective-Cでも利用できます。

サンプルコード

一通り実装したサンプルコードはこちらになります。

参考

72
74
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
72
74

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?