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

iOSアプリで、吹き出しっぽいviewを作成

More than 3 years have passed since last update.

人(キャラクター)が喋っている感じを表現しようと、吹き出しを描いた際のメモ。
Xcode7.2で動作確認しています。

方針としては、グラフィックスコンテキストを作成して、吹き出しぽい形を描画していくのが良さそう。
グラフィックスコンテキストを利用した描画に関しての説明は、以下の記事などが詳しい。

SwiftでCoreGraphics画像作成(基本)【メモ】 - Qiita

実装

StoryBoardに置いたViewController.swiftに、吹き出しをaddSubview(_:)する。
吹き出しは、BalloonViewというUIViewのサブクラスとして宣言し、幅280px, 高さ100pxで描画。

ViewController.swift
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で、だいたい正三角形

  1. CGContextAddRect(_:_:)で長方形部分のpathを指定
  2. CGContextMoveToPoint(_:_:_:), CGContextAddLineToPoint(_:_:_:)で三角形のpathを指定
    • 算出済みの三角形の各頂点の座標を利用

これらをそれぞれCGContextFillPath(_:)で塗りつぶし、吹き出しが完成。

BalloonView.swift
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)
    }

}

以下のようなビューになる。

スクリーンショット 2015-12-27 20.18.18.png

吹き出しに枠線をつけたい場合は、CGContextStrokePath(_:)などを使って実装することになるだろう。

蛇足

せっかくなので、セリフと喋ってるキャラクター(というか猫)の写真だけ入れてみた。
セリフはUILabel、写真はUIImageViewで実装してaddSubViewしてるだけです。

ViewController.swift
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)
}

出来上がり。以上です。

スクリーンショット 2015-12-27 20.21.21.png

ysk_1031
Software Engineer at Atrae, Inc. iOS, Android, Webの開発など色々やっています. 最近はyentaというアプリを作ったりしてます
atrae
People Techカンパニーとして、転職サイトGreen, ビジネスマッチングアプリyenta, 組織改善プラットフォームwevoxなどのサービスを運営。全ての社員が誇りを持てる組織と事業の創造にこだわり、関わる人々がファンとして応援したくなるような魅力ある会社であり続けることを目指しています。
https://atrae.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