人(キャラクター)が喋っている感じを表現しようと、吹き出しを描いた際のメモ。
Xcode7.2で動作確認しています。
方針としては、グラフィックスコンテキストを作成して、吹き出しぽい形を描画していくのが良さそう。
グラフィックスコンテキストを利用した描画に関しての説明は、以下の記事などが詳しい。
SwiftでCoreGraphics画像作成(基本)【メモ】 - Qiita
実装
StoryBoardに置いたViewController.swift
に、吹き出しをaddSubview(_:)
する。
吹き出しは、BalloonView
というUIView
のサブクラスとして宣言し、幅280px, 高さ100pxで描画。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let balloon = BalloonView(frame: CGRectMake((view.bounds.size.width - 280) / 2, 100, 280, 100))
balloon.backgroundColor = UIColor.whiteColor()
view.addSubview(balloon)
}
}
BalloonView
の中身は以下の通り。
drawRect(_:)
メソッドの中で、
- グラフィックスコンテキストを宣言
-
UIGraphicsGetCurrentContext
で呼び出し
-
- 吹き出しを塗りつぶす色を指定
- それぞれ
CGContextSetFillColorWithColor
- それぞれ
- 吹き出しの塗りつぶし範囲の指定 & 実行
-
contextBalloonPath(_:rect:)
メソッドで
-
塗りつぶしについて。
今回描こうと思っている吹き出しは、長方形部分と三角形部分に分割できる。
contextBalloonPath(_:rect:)
メソッドの中では、三角形部分の座標を計算し、それを利用して塗りつぶしを行う。
※三角形の一辺の長さを20px, 高さを17.3pxで、だいたい正三角形
-
CGContextAddRect(_:_:)
で長方形部分のpathを指定 -
CGContextMoveToPoint(_:_:_:)
,CGContextAddLineToPoint(_:_:_:)
で三角形のpathを指定- 算出済みの三角形の各頂点の座標を利用
これらをそれぞれCGContextFillPath(_:)
で塗りつぶし、吹き出しが完成。
class BalloonView: UIView {
let triangleSideLength: CGFloat = 20
let triangleHeight: CGFloat = 17.3
override func drawRect(rect: CGRect) {
super.drawRect(rect)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, UIColor.greenColor().CGColor)
contextBalloonPath(context!, rect: rect)
}
func contextBalloonPath(context: CGContextRef, rect: CGRect) {
let triangleRightCorner = (x: (rect.size.width + triangleSideLength) / 2, y: CGRectGetMaxY(rect) - triangleHeight)
let triangleBottomCorner = (x: rect.size.width / 2, y: CGRectGetMaxY(rect))
let triangleLeftCorner = (x: (rect.size.width - triangleSideLength) / 2, y: CGRectGetMaxY(rect) - triangleHeight)
// 塗りつぶし
CGContextAddRect(context, CGRectMake(0, 0, 280, rect.size.height - triangleHeight))
CGContextFillPath(context)
CGContextMoveToPoint(context, triangleLeftCorner.x, triangleLeftCorner.y)
CGContextAddLineToPoint(context, triangleBottomCorner.x, triangleBottomCorner.y)
CGContextAddLineToPoint(context, triangleRightCorner.x, triangleRightCorner.y)
CGContextFillPath(context)
}
}
以下のようなビューになる。
吹き出しに枠線をつけたい場合は、CGContextStrokePath(_:)
などを使って実装することになるだろう。
蛇足
せっかくなので、セリフと喋ってるキャラクター(というか猫)の写真だけ入れてみた。
セリフはUILabel
、写真はUIImageView
で実装してaddSubView
してるだけです。
override func viewDidLoad() {
super.viewDidLoad()
let balloon = BalloonView(frame: CGRectMake((view.bounds.size.width - 280) / 2, 100, 280, 100))
balloon.backgroundColor = UIColor.whiteColor()
view.addSubview(balloon)
let label = UILabel(frame: balloon.bounds)
label.frame.origin.y -= 8.7
label.text = "ニャーオ"
label.textColor = UIColor.whiteColor()
label.font = UIFont.boldSystemFontOfSize(24)
label.textAlignment = .Center
balloon.addSubview(label)
let imageView = UIImageView()
imageView.frame.size = CGSizeMake(100, 100)
imageView.frame.origin.y = CGRectGetMaxY(balloon.frame) + 10
imageView.center.x = balloon.center.x
imageView.layer.cornerRadius = 50
imageView.image = UIImage(named: "Cat")
imageView.contentMode = .ScaleAspectFill
imageView.clipsToBounds = true
view.addSubview(imageView)
}
出来上がり。以上です。