Touchイベントの勉強をきっかけにこちらの記事を見て作ってみました。
記事に書かれている主機能の他に消しゴム、ペン/消しゴムのサイズの変更を追加しました。
ViewControllerはこのような構成
class ViewController: UIViewController {
@IBOutlet weak var drawView: DrawView! ///お絵かきのカスタムView
@IBOutlet weak var eraserSelected: UISegmentedControl!
@IBOutlet weak var selectColor: UISegmentedControl!
@IBOutlet weak var selectSize: UISegmentedControl!
@IBAction func undoTapped(_ sender: Any) {
}
@IBAction func clearTapped(_ sender: Any) {
}
@IBAction func penOrEraser(_ sender: UISegmentedControl) {
}
@IBAction func penTapped(_ sender: UISegmentedControl) {
}
@IBAction func sizeSelected(_ sender: UISegmentedControl) {
}
}
サイズの種類を定義するEnum
enum size {
case small
case middle
case big
}
一描きの要素を含むDrawing
struct Drawing {
var points = [CGPoint]()
var color = UIColor.black
var size:size? = .small
}
タッチイベントの処理、主機能の処理のソースコードが詰まっている
カスタムビューDrawViewはこのような構成
class DrawView: UIView{
var finishedDrawings = [Drawing]()///完成したかきデータ
var currentDrawing: Drawing?///進行中のかきデータ
var currentColor = UIColor.black
var currentSize: size?
var eraserSelected = false
override func draw(_ rect: CGRect) {
strokeToLine()///完成したデータと進行中のデータのDrawingを一つずつ処理していく
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
///タッチポイントを取得してcurrentDrawingへ入れる
setNeedsDisplay()
///setNeedsDisplayによってdrawが自動的に呼び出されてタッチが処理されていく
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
///同上
setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
///同上、currentDrawingを完成データへ入れる
setNeedsDisplay()
}
func strokeToLine(drawing:Drawing){
///drawingのpointsを線で繋ぐ処理
let path = UIBezierPath()///宣言
path.move(to: beginPoint)///開始点
path.addLine(to: endPoint)///終了点
path.stroke()///描画する
}
func clear(){
}
func undo(){
}
func setColor(_ color: UIColor){
}
func setSize(_ newSize:size){
}
}
完成したソースコードは以下になります。
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var drawView: DrawView!
@IBOutlet weak var eraserSelected: UISegmentedControl!
@IBOutlet weak var selectColor: UISegmentedControl!
@IBOutlet weak var selectSize: UISegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func undoTapped(_ sender: Any) {
drawView.undo()
}
@IBAction func clearTapped(_ sender: Any) {
drawView.clear()
}
@IBAction func penOrEraser(_ sender: UISegmentedControl) {
switch eraserSelected.selectedSegmentIndex{
case 0:
drawView.eraserSelected = false
case 1:
drawView.eraserSelected = true
default:
break
}
}
@IBAction func penTapped(_ sender: UISegmentedControl) {
var c = UIColor.black
switch selectColor.selectedSegmentIndex {
case 1:
c = UIColor.red
case 2:
c = UIColor.yellow
default:
break
}
drawView.setColor(c)
}
@IBAction func sizeSelected(_ sender: UISegmentedControl) {
switch selectSize.selectedSegmentIndex {
case 0:
drawView.setSize(.small)
case 1:
drawView.setSize(.middle)
case 2:
drawView.setSize(.big)
default:
break
}
}
}
DrawView.swift
class DrawView: UIView{
var finishedDrawings = [Drawing]()
var currentDrawing: Drawing?
var currentColor = UIColor.black
var currentSize: size?
var eraserSelected = false
override func draw(_ rect: CGRect) {
for drawing in finishedDrawings{
drawing.color.setStroke()
strokeToLine(drawing: drawing)
}
if let drawing = currentDrawing{
drawing.color.setStroke()
strokeToLine(drawing: drawing)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let point = touches.first!.location(in: self)
currentDrawing = Drawing()
if eraserSelected {
currentDrawing?.color = UIColor.white
}else{
currentDrawing?.color = currentColor
}
currentDrawing?.size = currentSize
currentDrawing?.points.append(point)
setNeedsDisplay()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let point = touches.first!.location(in: self)
currentDrawing?.points.append(point)
setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let point = touches.first!.location(in: self)
if var drawing = currentDrawing {
drawing.points.append(point)
finishedDrawings.append(drawing)
}
currentDrawing = nil
setNeedsDisplay()
}
func strokeToLine(drawing:Drawing){
var width:CGFloat = 6.0
switch drawing.size{
case .middle:
width = 12.0
case .big:
width = 20.0
default:
width = 6.0
}
let path = UIBezierPath()
path.lineCapStyle = .round
path.lineJoinStyle = .round
path.lineWidth = width
let beginPoint = drawing.points[0]
path.move(to: beginPoint)
if drawing.points.count > 1{
for i in 1...(drawing.points.count - 1){
let endPoint = drawing.points[i]
path.addLine(to: endPoint)
}
}
path.stroke()
}
func clear(){
finishedDrawings.removeAll()
setNeedsDisplay()
}
func undo(){
if finishedDrawings.count == 0 {
return
}
finishedDrawings.remove(at: finishedDrawings.count - 1)
setNeedsDisplay()
}
func setColor(_ color: UIColor){
currentColor = color
}
func setSize(_ newSize:size){
currentSize = newSize
}
}