在iOS中實現一個簡單的畫板App

在這個隨筆中,咱們要爲iPhone實現一個簡單的畫板App。git

首先須要指出的是,這個demo中使用QuarzCore進行繪畫,而不是OpenGL。這兩個均可以實現相似的功能,區別是OpenGL更快,可是QuarzCore更簡單。
 
第一步,新建Xcode項目,項目名稱就叫SimplePaint。
第二步,添加QuarzCore.framework到項目中。
 
 
第三步,建立一個新類,類名叫Line。它表明在iPhone的屏幕上繪畫時候的線。由於無論是畫一條直線仍是一條曲線,均可以看作是多條短的直線鏈接起來的。那麼Line須要的是什麼屬性呢?簡單點就是,這條線的開始點和結束點,還有這條線的顏色。因此,打開剛剛建立的Line類,
修改Line.h:
 
而後修改Line.m:
 
第四步,接下來建立另外一個類,類名叫作ColorPiker。它表明顏色選擇器,咱們能夠點擊多個顏色中的一個做爲畫筆的顏色進行繪畫。如下是ColorPiker.h的代碼:
 
aColorPikerIsSelected是一個委託,噹噹前選擇器被選中後,它能夠把當前選中的顏色選擇器的顏色值傳遞出去,傳遞給實現了這個委託的類。在咱們的這個demo中,咱們會讓畫板View的實現此委託。
 
實現ColorPiker.m:
 
 
第五步,接下來咱們就建立咱們的畫板View,它表明能夠畫圖的那部分有效區域。建立一個新類叫作TouchDrawView。修改TouchDrawView.h的內容:
 
剛剛上文中也提過了,咱們畫圖的主要思想就是把多個短線首尾鏈接起來,就能夠成爲一條軌跡。因此咱們的畫板有一個array,它的item就是Line類型,它就是滑過軌跡的全部Line的集合。咱們還有一個單獨的Line對象,表示在繪畫過程當中,當前正在畫的這條線。另外有一個Color類型的屬性,表示線的顏色,也就是用來保存ColorPiker傳遞出來的顏色值。
 
實現TouchDrawView.m
  1 //
  2 //  TouchDrawView.m
  3 //  CaplessCoderPaint
  4 //
  5 //  Created by backslash112 on 14/10/29.
  6 //  Copyright (c) 2014年 backslash112. All rights reserved.
  7 //
  8 
  9 #import "TouchDrawView.h"
 10 #import "Common.h"
 11 
 12 @implementation TouchDrawView
 13 {
 14 }
 15 @synthesize currentLine;
 16 @synthesize linesCompleted;
 17 @synthesize drawColor;
 18 
 19 - (id)initWithCoder:(NSCoder *)c
 20 {
 21     self = [super initWithCoder:c];
 22     if (self) {
 23         linesCompleted = [[NSMutableArray alloc] init];
 24         [self setMultipleTouchEnabled:YES];
 25         
 26         drawColor = [UIColor blackColor];
 27         [self becomeFirstResponder];
 28     }
 29     return self;
 30 }
 31 
 32 //  It is a method of UIView called every time the screen needs a redisplay or refresh.
 33 - (void)drawRect:(CGRect)rect
 34 {
 35     CGContextRef context = UIGraphicsGetCurrentContext();
 36     CGContextSetLineWidth(context, 5.0);
 37     CGContextSetLineCap(context, kCGLineCapRound);
 38     [drawColor set];
 39     for (Line *line in linesCompleted) {
 40         [[line color] set];
 41         CGContextMoveToPoint(context, [line begin].x, [line begin].y);
 42         CGContextAddLineToPoint(context, [line end].x, [line end].y);
 43         CGContextStrokePath(context);
 44     }
 45 }
 46 
 47 - (void)undo
 48 {
 49     if ([self.undoManager canUndo]) {
 50         [self.undoManager undo];
 51         [self setNeedsDisplay];
 52     }
 53 }
 54 
 55 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 56 {
 57     [self.undoManager beginUndoGrouping];
 58     for (UITouch *t in touches) {
 59         // Create a line for the value
 60         CGPoint loc = [t locationInView:self];
 61         Line *newLine = [[Line alloc] init];
 62         [newLine setBegin:loc];
 63         [newLine setEnd:loc];
 64         [newLine setColor:drawColor];
 65         currentLine = newLine;
 66     }
 67 }
 68 
 69 - (void)addLine:(Line*)line
 70 {
 71     [[self.undoManager prepareWithInvocationTarget:self] removeLine:line];
 72     [linesCompleted addObject:line];
 73 }
 74 
 75 - (void)removeLine:(Line*)line
 76 {
 77     if ([linesCompleted containsObject:line])
 78         [linesCompleted removeObject:line];
 79 }
 80 
 81 - (void)removeLineByEndPoint:(CGPoint)point
 82 {
 83     NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
 84         Line *evaluatedLine = (Line*)evaluatedObject;
 85         return evaluatedLine.end.x == point.x &&
 86         evaluatedLine.end.y == point.y;
 87     }];
 88     NSArray *result = [linesCompleted filteredArrayUsingPredicate:predicate];
 89     if (result && result.count > 0) {
 90         [linesCompleted removeObject:result[0]];
 91     }
 92 }
 93 
 94 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
 95 {
 96     for (UITouch *t in touches) {
 97         [currentLine setColor:drawColor];
 98         CGPoint loc = [t locationInView:self];
 99         [currentLine setEnd:loc];
100         
101         if (currentLine) {
102             [self addLine:currentLine];
103         }
104         Line *newLine = [[Line alloc] init];
105         [newLine setBegin:loc];
106         [newLine setEnd:loc];
107         [newLine setColor:drawColor];
108         currentLine = newLine;
109     }
110     [self setNeedsDisplay];
111 }
112 
113 - (void)endTouches:(NSSet *)touches
114 {
115     [self setNeedsDisplay];
116 }
117 
118 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
119 {
120     [self endTouches:touches];
121     [self.undoManager endUndoGrouping];
122 }
123 
124 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
125 {
126     [self endTouches:touches];
127 }
128 
129 - (BOOL)canBecomeFirstResponder
130 {
131     return YES;
132 }
133 
134 - (void)didMoveToWindow
135 {
136     [self becomeFirstResponder];
137 }
138 
139 - (id)initWithFrame:(CGRect)frame
140 {
141     self = [super initWithFrame:frame];
142     if (self) {
143         // Initialization code
144     }
145     return self;
146 }
147 
148 @end

這個文件包含了主要的邏輯,說明下主要方法的做用:github

-(id)initWithCoder:當此view被建立的時候這個方法自動調用,因此你不必定必需要實現它;當時當你想在初始化的時候作一些別的工做的時候你就須要實現它。redis

-(void)drawRect:每次當屏幕須要從新顯示或者刷新的時候這個方法會被調用。less

-(void)touchBegan:當你的手指點擊到屏幕的時候這個方法會被調用。工具

-(void)touchMove:當你的手指點擊屏幕後開始在屏幕移動,它會被調用。隨着手指的移動,相關的對象會秩序發送該消息。lua

-(void)touchEnd:當你的手指點擊屏幕以後離開的時候,它會被調用。spa

還須要講解下的是,當每次touchMove方法中,往array中添加入了新的Line,要想在畫布中顯示出來,須要刷新下頁面,調用[self setNeedsDisplay]方法便可。
 
基本的主要邏輯就是這樣,咱們還差什麼?固然是UI!
 
第六步,建立一個 .xib文件,叫作TouchDrawViewController.xib。在右邊的工具箱中添加一個View,再往View中加入多個子View,加多少個你隨意,由於這幾個子View是用來做爲顏色選擇器的,多幾個少幾個無所謂。而後設置這幾個子View的Class爲 ColorPiker,接着設置他們的背景顏色,顏色值你隨意,由於會把被選中的顏色選擇器的背景顏色直接做爲參數傳出來。
 
 
咱們還須要一個畫布的區域,再添加一個View,拉伸它,讓它覆蓋整個空白區域。一樣更改它的Class,改成 TouchDrawView。
 
 
咱們基本快要完成了。
 
第七步,爲剛剛的UI添加一個View Controller類,新建類文件,命名爲TouchDrawViewController。修改 .h 文件爲:
 
能夠看到它實現了ColorPikerDelegate委託,當ColorPiker 被選中後,色值(背景色)會傳遞到當前類做爲畫筆的顏色。
 
接下來鏈接UI和ViewController。
同時打開TouchDrawViewController.xib和TouchDrawViewController.h,Ctrl+Drop UI上的每一個色塊和畫布到TouchDrawViewController.h,完成後TouchDrawViewController.h是這樣的:
 
實現TouchDrawViewController.m:
 
在ViewDidLoad方法中,咱們把每一個ColorPiker的delegate爲self,而後實現aColorPikerIsSelected方法,這樣色值就能夠傳遞過來了。
 
最後,設置TouchrawViewController爲rootController。打開delegate.m文件,修改didFinishLaunchingWithOptions方法爲:
 
能夠了,運行它吧!

 

相關源代碼:github3d

相關文章
相關標籤/搜索