#はじめに
Swift Advent Calendar 2016 14日目です。
Swift Advent Calendar 2016
ということで、Swiftに関する話を書こうと思っていたのですが拡大解釈してC4入門の記事を書きます。お許し下さいッ…!!
#C4とは
簡単に言えばCoreGraphicsやCoreAnimationを扱いやすくしたものだとか、OpenFrameworkのCoreGraphics版とかそういったものです。
描画系関数や数値計算・生成系関数のセットがSwift3.0で書かれています。
極めればOpenFrameworkのように「Swift出来ればVJ出来ちゃう」みたいな感じのイケイケヒップホップエンジニアになれるはずです。
オシャレな展示を作るのに使ってもよし、UX向上の為に使ってもよしです。
しかも記述も非常に簡単なのでこれからSwiftを始める人にもおすすめです。
#インストール方法
target 'C4Lab' do
use_frameworks!
pod 'C4'
end
cocoapodsに対応しているので、Podfileに書けばインストール出来ます。
公式サイトにはCarthageやマニュアルインストールの方法も書いてあるので、好みによって参照してください。
#標準の描画関数
関数の殆どはC4独自のものですが、基本的にはUIKitやFoundationからプリフィクスを取った(Point/Rect/Transformなど)が使われます。
またそれぞれにFoundationの構造体を引数に取って生成するイニシャライザがあるので、例えばCGRectをRectに変換する場合もRect(cgrectValue)
のように、書くことができます。
これはSwiftのキャストと非常に記述が似ているので自然に使う事ができます。
以下は公式チュートリアルの基本的な部分を抜粋しています。
##背景を青で塗る
final class ViewController: CanvasController {
override func setup() {
canvas.backgroundColor = C4Blue
}
}
基本的にC4ではUIViewControllerの代わりにCanvasControllerを継承します。
CanvasControllerにはUIViewControllerにviewが生えているようにcanvasが生えており、それに対してC4のViewをaddして行きます。
上記はcanvasの背景色を青にした状態です。
viewDidLoadに初期化の記述を書くように、C4ではsetup関数の中に初期化のプロセスを記述します。
##四角を描く
final class ViewController: CanvasController {
override func setup() {
let square = Rectangle(frame: Rect(0, 0, 100, 100))
square.center = canvas.center
canvas.add(square)
}
}
ビューの追加はUIViewをaddSubViewする時と同じように行います。
addメソッドの内部では
public func add<T>(_ subview: T?) {
if let v = subview as? UIView {
view.addSubview(v)
} else if let v = subview as? View {
view.addSubview(v.view)
} else {
fatalError("Can't add subview of class `\(type(of: subview))`")
}
}
このような分岐が行われており、C4のViewの場合はC4.ViewからUIViewを生成してaddSubViewをしています。
C4では一定のパターンの図形はクラスとして定義されており、簡単に生成することが出来ます。
##円を描く
final class ViewController: CanvasController {
override func setup() {
let circle = Circle(center: canvas.center, radius: 50)
canvas.add(circle)
}
}
円を描く際、自前で行うとボーダーラインがframeから漏れてしまい微妙に小さくしたりする事がありますがC4では内側に線を引いてくれるようです。
##楕円を描く
final class ViewController: CanvasController {
override func setup() {
let ellipse = Ellipse(frame: Rect(0, 0, 200, 100))
ellipse.center = canvas.center
canvas.add(ellipse)
}
}
CircleはEllipseを継承しており、継承元のEllipseではCircleで補正されているアス比を無視して楕円を描画することが出来ます。
##線を描く
final class ViewController: CanvasController {
override func setup() {
let points = (Point(), Point(100, 100))
let line = Line(points)
line.center = canvas.center
canvas.add(line)
}
}
基本的な線を描画します。
##三角を描く
final class ViewController: CanvasController {
override func setup() {
let points = [Point(), Point(100, 100), Point(200, 0)]
let triangle = Triangle(points)
triangle.center = canvas.center
canvas.add(triangle)
}
}
Triangleクラスは与えるpointsが3つ以下だとassertしてくれます。
##ポリゴンを描く
final class ViewController: CanvasController {
override func setup() {
let points = [Point(), Point(100, 100), Point(200, 0), Point(300, 100)]
let polygon = Polygon(points)
polygon.center = canvas.center
canvas.add(polygon)
}
}
PolygonはTriangleやLineの基底クラスです。
基本的にはPolygonを使えばTriangleやLineと同じように描画出来ます。
##多角形
final class ViewController: CanvasController {
override func setup() {
let regularPolyon = RegularPolygon(center: canvas.center, radius: 50.0, sides: 6, phase: 0.0)
canvas.add(regularPolyon)
}
}
多角形を描画します。これも基底クラスはPolygonです。
##星を描く
final class ViewController: CanvasController {
override func setup() {
let star = Star(center: canvas.center, pointCount: 5, innerRadius: 25.0, outerRadius: 50.0)
canvas.add(star)
}
}
Starという名前がついていますが、頂点を凸部分は5つ以上にすることで破裂型吹き出しのような形にすることも出来ます。
ここまではSketchにあるシェイプによく似ていますね
##かまぼこ型を描く
final class ViewController: CanvasController {
override func setup() {
let arc = Arc(center: canvas.center, radius: 50, start: M_PI, end: 2 * M_PI)
canvas.add(arc)
}
}
##楔形を描く
final class ViewController: CanvasController {
override func setup() {
let wedge = Wedge(center: canvas.center, radius: 50, start: 1.25 * M_PI, end: 1.75 * M_PI)
canvas.add(wedge)
}
}
ピザ型を表現できます。
タイマーの経過のアニメーションにも使えそうですね。
##テキストを描画する
final class ViewController: CanvasController {
override func setup() {
let string = "C4"
let textShape = TextShape(text: string)!
textShape.center = canvas.center
canvas.add(textShape)
}
}
テキストを直接描画します。
フォントを選ぶこともできます
final class ViewController: CanvasController {
override func setup() {
let string = "日本語のテスト"
let textShape = TextShape(text: string)!
textShape.center = canvas.center
canvas.add(textShape)
}
}
日本語は表示されないようです。
フォントの問題なのかな
#プロパティ
##基本的なプロパティ
final class ViewController: CanvasController {
override func setup() {
let r = Rectangle(frame: Rect(0, 0, 100, 100))
r.center = canvas.center
r.lineWidth = 8 //線の太さ
r.strokeColor = C4Blue //線の色
r.fillColor = C4Pink //塗りの色
canvas.add(r)
canvas.backgroundColor = C4Purple //背景色
}
}
太さや色、塗り色などを指定出来ます。
#色について
##基本色
基本色が存在し、この色はC4をimportしていれば
backgroundColor = black
のように直接呼び出す事ができます。
black
darkGray
lightGray
white
gray
red
green
blue
cyan
yellow
magenta
orange
purple
brown
clear
C4Pink
C4Blue
C4Purple
C4Grey
##カスタムカラー
UIColorやCGColorから生成したりRGBを指定して生成することも出来ます。
Color(UIColor.red.cgColor)
Color(UIColor.red)
Color(12)
Color(red: 0.25, green: 0.5, blue: 0.75, alpha: 1.0)
##カスタムカラー2
Color(pattern: String)
を使うと画像を敷き詰める事ができます。
これもC4の世界ではColorとして扱います。
final class ViewController: CanvasController {
override func setup() {
canvas.backgroundColor = Color("image1")
}
}
#画像
##Image
final class ViewController: CanvasController {
override func setup() {
let image = Image("image1")!
image.center = canvas.center
canvas.add(image)
}
}
画像も単体のクラスとして存在します。UIImageViewと違い、Image自体をcanvasにadd出来ます。
##Filter
final class ViewController: CanvasController {
override func setup() {
let image = Image("image1")
image?.center = canvas.center
canvas.add(image)
var dotScreen = DotScreen()
dotScreen.width = 10.0
image?.apply(dotScreen)
}
}
フィルタをかける処理も短く書けます。
C4にはDotScreen以外にもガウジアンブラーやブルームといったフィルターも最初から入っています。
もちろんFilterクラスを継承すれば自分でフィルタを作ることも出来ます。
フィルタの実態はCIFilterなので、CIFilterが書ける人はもちろんOpenGLのシェーダーを使うことも出来ます。
##Generate Image
final class ViewController: CanvasController {
override func setup() {
let image = Image()
image.frame = Rect(0, 0, 100, 100)
let checkerBoard = Checkerboard()
image.generate(checkerBoard)
image.center = canvas.center
canvas.add(image)
}
}
画像を生成するクラスです。
現在C4にはLinearGradientとCheckerboardしかありません。
#Video
##再生
final class ViewController: CanvasController {
override func setup() {
let movie = Movie("ipod.mov")
movie?.center = canvas.center
canvas.add(movie)
movie?.play()
}
}
AVFoundationを意識せずに再生できます。
このMovie自体にもフィルタをかけたり出来ます。
上記のgifのようにデフォルトでは自動的にリサイズはされず、実サイズで再生されます。
#Gesture
C4ではUIGestureRecognizerもラップした関数があり、Viewに生えています。
直感的にビューに対してタップやパンの時の処理を書くことが出来ます。
##タップ
final class ViewController: CanvasController {
override func setup() {
let square = Rectangle(frame: Rect(0, 0, 100, 100))
square.addTapGestureRecognizer { (locations, center, state) in
square.fillColor = red
}
canvas.add(square)
}
}
#アニメーション
C4ではアニメーションはViewAnimationクラスを使って記述します。
ViewAnimationクラスは繋げたり同時に実行したりループしたりが簡単に行えて、色や移動の補完も自動的に行ってくれます。
##基本的なアニメーション
ViewAnimation(duration: 1.0) {
square.fillColor = C4Pink
}.animate()
このようにduraitonを指定しクロージャ内で最終状態を記述します。
UIView.animateWithDurationと非常に似ています。
let anim = ViewAnimation(duration: 1.0) {
self.canvas.backgroundColor = C4Blue
}
anim.curve = .EaseOut
anim.repeats = true
wait(1.0) {
anim.animate()
}
ViewAnimation自体はインスタンスを返すので、それに対してプロパティを付与することでアニメーションを変化させることが出来ます。
#色々遊んでみた
##四角と円形をタップで切り替える
final class ViewController: CanvasController {
private var isCircle = false
override func setup() {
let square = Rectangle(frame: Rect(0, 0, 100, 100))
square.corner = Size(10, 10)
square.center = canvas.center
canvas.add(square)
_ = square.addTapGestureRecognizer { (locations, center, state) in
self.isCircle = !self.isCircle
if self.isCircle {
ViewAnimation(duration: 1.0, animations: {
square.corner = Size(10, 10)
}).animate()
} else {
ViewAnimation(duration: 1.0, animations: {
square.corner = Size(50, 50)
}).animate()
}
}
}
}
##C4.ViewをUIViewのように追加する
C4.CanvasControllerじゃなくてもいいっぽい
final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let rect = Rect(CGRect(x: 0, y: 0, width: 100, height: 100))
let c4v = C4.View(frame: rect)
c4v.center = Point(view.center)
c4v.backgroundColor = red
view.add(c4v)
}
}
##モーフィング
final class ViewController: CanvasController {
override func setup() {
let c1 = Circle(center: canvas.center, radius: 20)
c1.fillColor = clear
c1.strokeColor = lightGray
canvas.add(c1)
let c2 = Circle(center: canvas.center, radius: 20)
c2.fillColor = clear
c2.strokeColor = lightGray
canvas.add(c2)
let c3 = Circle(center: canvas.center, radius: 20)
c3.fillColor = clear
c3.strokeColor = lightGray
canvas.add(c3)
let c1Anim = ViewAnimation(duration: 1.0, animations: {
c1.transform = Transform.makeScale(0.2, 0.2)
})
let c2Anim = ViewAnimation(duration: 1.0, animations: {
c2.transform.scale(0.2, 0.2)
c2.transform.translate(Vector(x: -50, y: 0))
})
let c3Anim = ViewAnimation(duration: 1.0, animations: {
c3.transform.scale(0.2, 0.2)
c3.transform.translate(Vector(x: 50, y: 0))
})
canvas.addTapGestureRecognizer { (_, _, _) in
ViewAnimationGroup(animations: [c1Anim, c2Anim, c3Anim]).animate()
}
}
}
#まとめ
基本的なところをさらっと載せました。
C4はCoreGraphicsやUIKitを使っていることもあり、低コストにマイクロインタラクションを実装したり出来るなど、一般的なアプリケーション開発との親和性も高そうに思えました。
エンジニアがちょっとした動きを実装したり、デザイナーも実際にコードを触って実装に関われるような簡単さもあって中々楽しいのではないでしょうか。
このC4を通してSwiftを知ったり、逆にエンジニアが芸術・展示作品に対してコミットしていくという事が出来そうに思います。
明日は @_ha1f さんの 「Photos.frameworkのサンプルリーディング」です!
それでは!