【Swift】簡易ペイントを作成してみた。

とりあえず絵が描けるようになったので、コードをメモしておきます。結構時間かかってしまいました。

 

キャンバスを作成する

まずは絵を描くキャンバスを作成します。

var canvas = UIImageView()
canvas.frame = CGRect(x:0,y:0,width:screenWidth,height:screenHeight)
canvas.backgroundColor = UIColor.clearColor()
view.addSubview(canvas)

このUIImageViewの上に絵を描いていきます。

 

タッチイベントを作成する

画面がタッチされたときのアクションをかいていきます。

まずは指が触れたときに呼び出されるメソッドから。

 var bezierPath:UIBezierPath!
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touchEvent = touches.first!
        let currentPoint:CGPoint = touchEvent.locationInView(canvas)
        bezierPath = UIBezierPath()
        bezierPath.lineWidth = 4.0
        bezierPath.moveToPoint(currentPoint)
}

Swift2.0ではtouchesがSet<UITouch>になっています。

3行目でタッチ時のイベントを取得します。

4行目で現在の座標を取得します。

bezierPathは曲線を扱うためのやつなんだとか。

線の太さを設定して、始点を現在の位置に設定しています。

 

次にドラッグ中のイベントです

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if bezierPath == nil {
            return
        }
        let touchEvent = touches.first!
        let currentPoint:CGPoint = touchEvent.locationInView(canvas)
        bezierPath.addLineToPoint(currentPoint)
        drawLine(bezierPath)
}

 

最初にもしもタッチ開始時にパスを初期化していない場合は処理を終了します。

そのあと現在の座標を取得して、線を引いていきます。 drawLineメソッドは後述します。

 

そして指を離したときのイベントです。

let lastDrawImage:UIImage!
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if bezierPath == nil {
            return
        }
        let touchEvent = touches.first!
        let currentPoint:CGPoint = touchEvent.locationInView(canvas)
        bezierPath.addLineToPoint(currentPoint)
        drawLine(bezierPath)
        lastDrawImage = canvas.image
}

途中までは先ほどと同じです。

最後にlastDrawImageにこれまで描いた絵を保存します。

これまで描いた絵を保存しておかないと黒い点がついてくるというよくわからないアプリに・・・

 

最後に描画時の処理です。

func drawLine(path:UIBezierPath){
        UIGraphicsBeginImageContext(canvas.frame.size)
        if lastDrawImage != nil {
            lastDrawImage.drawAtPoint(CGPointZero)
        }
        let lineColor = UIColor.blackColor()
        lineColor.setStroke()
        path.stroke()
        self.canvas.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
}

 

まずUIGraphicsBeginImageContextで非表示の描画領域を生成します。ここに描画してから画面に表示させます。

これまでに描いた絵があれば描画します。

線の色を決めて、線を描きます。

そしてUIImageViewのcanvasに画像を写します。

最後に描画を終了する文をかいて終わりです。

 

ひっかかったところ

タッチした座標を取得するときに、let touch = touches.anyObject() as UITouchとかいてもエラーが出るし、let touch = UITouch()とかいても取得できない。後者は当たり前なんですけども。。。

touchesはanyObjectじゃないよーということですね。バージョンの違いでエラーが出てしまいました。

touches.first!で座標を取得することができました。

ここまでたどり着くのにそこそこかかってしまった・・・

 

ちなみに.lineCapStyle = kCGLineCapRoundでエラーが出る原因もわからずとりあえず放置しています。バージョンが違うのかと思いきやそうでもなさそう。原因不明です。

 

あくまでも簡易・・・

undoボタンやredoボタンもなしで削除もできないという状態です。なのでただ線が描ける!というだけです。

これから様々な機能をつけていこうと思います。

今回は全体コードは割愛させていただきます。

 
 

2018/04/14追記 Swift4に対応してみました。
単純に置き換えただけですが。



アデュー

Comments...

コメントは認証制です。詳しくは下記の注意をお読みください。お気軽にコメントお願いします!

Write a Comment

コメント時の注意

「Twitter」「Facebook」「Google+」「WordPress」のいずれかのアカウントをお持ちの方は各アカウントと連携することでコメントできます。 コメントしたことはSNSに流れませんので、アカウントをお持ちの方はこちらの方法でコメントを投稿して下さると嬉しいです。 アカウントをお持ちでない方はメールアドレスで投稿することができます。 初回コメント時は承認後に表示されます。

Related Memo...

記事を書くほどでもないけれどメモっておきたいこと

テスト投稿。

例えばiphone7 の画面サイズ

750 × 1334
半分375 × 667

iOS

UITableView.RowAnimation の .none はアニメーションするよ

UITableView.RowAnimation の .none はアニメーションがnoneなわけじゃなく、デフォルトの設定を使うよという意味らしい。

The inserted or deleted rows use the default animations.

なのでアニメーションしちゃう。今更の気づき。

 

iOS

UINavigationController + UIScrollView の組み合わせで使っている時に謎の余白ができる時

UINavigationController + UIScrollView の組み合わせで使っていて、UIScrollView 上に AutoLayout で上下左右0で View を設置しているのに、30px程度上にずれてしまうとき。

`navigationController.navigationBar.isTranslucent = false` にすると直るかもしれない。

ScrollView上のコンテンツとNavigationBarの重なっているところが透過していたら多分これで直せるはず。

通常のターゲットではちゃんと動いているのに、iOSSnapshotTestCase を用いたテストでだけこの対応が必要なのよくわからないけれど。。。

iOS
more