今Swiftお絵かきアプリを作ろうと試行錯誤しているのですが、
肝心の描画部分のサンプルがあまりなかったので、
Objective-Cで実装しているこちらの記事をSwift化してみました。
ただし、undo,redo,クリアはボタンではなくtableViewで実装しています。
変数宣言
必要な変数を宣言します。
lastDrawImage以下の変数も最初はnilであるため、Implicitly Unwrapped Optionalを示すエクスクラメーションマーク(!)を付けます。
lastDrawImage, bezierPathは処理中にnilである場合があるので、
厳密にはクエスチョンマーク(?)のほうがいいかもしれません。
class MainViewController: UIViewController, UIScrollViewDelegate, UITableViewDataSource, UITableViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
@IBOutlet weak var canvas: UIImageView!
@IBOutlet weak var toolBar: UITableView!
var lastDrawImage: UIImage!
var bezierPath: UIBezierPath!
var undoStack: NSMutableArray!
var redoStack: NSMutableArray!
初期化
ViewWillApperで初期化を行います。
/**
* View初期表示時の処理
*/
override func viewWillAppear(animated: Bool) {
undoStack = NSMutableArray()
redoStack = NSMutableArray()
}
タッチ時の処理
/**
* タッチ開始時の処理
*/
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject() as UITouch
let currentPoint:CGPoint = touch.locationInView(canvas)
bezierPath = UIBezierPath()
bezierPath.lineCapStyle = kCGLineCapRound
bezierPath.lineWidth = 1.0
bezierPath.moveToPoint(currentPoint)
}
/**
* タッチ移動時の処理
*/
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
if bezierPath == nil {
return
}
let touch = touches.anyObject() as UITouch
let currentPoint:CGPoint = touch.locationInView(canvas)
bezierPath.addLineToPoint(currentPoint)
drawLine(bezierPath)
}
/**
* タッチ終了時の処理
*/
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
if bezierPath == nil {
return
}
let touch = touches.anyObject() as UITouch
let currentPoint:CGPoint = touch.locationInView(canvas)
bezierPath.addLineToPoint(currentPoint)
drawLine(bezierPath)
lastDrawImage = canvas.image
undoStack.addObject(bezierPath)
redoStack.removeAllObjects()
}
/**
* 描画処理
*/
func drawLine(path:UIBezierPath) {
UIGraphicsBeginImageContext(canvas.frame.size)
if lastDrawImage != nil {
lastDrawImage.drawAtPoint(CGPointZero)
}
var blackColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
blackColor.setStroke()
path.stroke()
canvas.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
やっていることはObjective-C版と同じなので特に言うことはありませんが、
UIColorの初期化に引数が必要になったところだけ違います。
ていうかBezierってことはまさにベジェ曲線なんですかね。
昔イラレで死ぬほど触りましたが、今度はプログラムで触ることになるとは。
こちらの記事のようにコントロールポイントも指定できるようなので、スムージングとか色々できそうですね。
undo, redo, クリア
ここはObjective-C版と異なり、クリア処理もundoできるようにしようとundoStackに”clear”文字列を入れたりしているのですが、
まだ処理が甘々なのでうまく動作していません。(redoは無視してるし)
func undo() {
let undoPath: AnyObject? = undoStack.lastObject
undoStack.removeLastObject()
redoStack.addObject(undoPath!)
lastDrawImage = nil
canvas.image = nil
for path in undoStack {
if path is NSString {
lastDrawImage = nil
} else {
drawLine(path as UIBezierPath)
lastDrawImage = canvas.image
}
}
}
func redo() {
let redoPath: UIBezierPath = redoStack.lastObject as UIBezierPath
redoStack.removeLastObject()
undoStack.addObject(redoPath)
for path in undoStack {
drawLine(path as UIBezierPath)
lastDrawImage = canvas.image
}
}
func clear() {
lastDrawImage = nil
canvas.image = nil
undoStack.addObject("clear");
}
// table view delegate
var texts = ["undo", "redo", "clear"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return texts.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")
cell.textLabel?.text = texts[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
if undoStack.count > 0 {
undo()
}
} else if indexPath.row == 1 {
if redoStack.count > 0 {
redo()
}
} else if indexPath.row == 2 {
clear()
}
}
お絵かきアプリを作るにあたっての検討事項
これでタッチで描画ができるようにはなったのですが、
アプリに仕上げていくには色々と追加すべきものがあります。
優先順位順に上げていくと…
- 拡大、縮小、スクロール
- 保存処理
- ペンのプロパティ変更
- 消しゴム
- レイヤー
- 透明度
などなど。
iOS開発初心者、Swift初心者の自分がどこまで実装できるか、やるだけやってみます。


コメント
[…] 今回は全体コードは割愛させていただきます。 参考サイト [iOSアプリ開発] タッチでお絵かきしてみる をSwift化 [iOSアプリ開発] タッチでお絵かきしてみる [Swift] 画像をドラッグ […]