Quartz2D實現(xiàn)簡單“畫圖板”

概念

1.首先要明白所有iOS中見到的所有東西述雾,都是因為通過UIView內(nèi)部的圖層——CALayer對象;

并且溅漾,UIView顯示到屏幕上時哎甲,會調(diào)用【 deawRect: 】方法進行繪圖。

即:

》UIView負(fù)責(zé):交互啤挎、響應(yīng)驻谆;

》CALayer負(fù)責(zé):展示、繪圖庆聘;

但——系統(tǒng)提供的可能無法滿足需求旺韭,那么我們就需要到Quartz2D(自定義UI控件)了。

2.圖形上下文CGContextRef三個作用:

》路徑

》狀態(tài)

》目標(biāo)

3.drawRect:方法

注意:

》與View相關(guān)的【圖形上下文】只能在 drawRect:方法中取得掏觉,但重寫 drawRect:方法需要一個UIView類区端,控制器類UIViewController中無法得到 drawRect:,往往需要自行創(chuàng)建一個澳腹;

》drawRect不能手動調(diào)用织盼,有可能獲取不到正確的上下文;

》drawRect的調(diào)用時機:

? ?①酱塔、在View第一次顯示時沥邻;

? ?②、重繪:調(diào)用【 view的setNeedsDisplay 】或【setNeedsDisplayInRect:】的時候羊娃;



步驟:

一唐全、搭建UI界面

二、畫筆功能:

1蕊玷、重寫drawRect方法邮利,需創(chuàng)建一個UIView類—— MayView,指定sb (storyboard) 中繪圖區(qū)View的class為 MayView垃帅;

2延届、在MayView類中創(chuàng)建一個可變數(shù)組用于存儲所有的路徑

//存儲路徑的數(shù)組:路徑不只有一條

@property (nonatomic, strong) NSMutableArray *allPaths;

并且進行懶加載

#pragma mark - Getter & Setter

//懶加載

- (NSMutableArray *)allPaths {

if (_allPaths == nil) {

_allPaths = [NSMutableArray array];

}

return _allPaths;

}

3、思考:每一條線都有什么狀態(tài)贸诚,怎么修改方庭?想畫出一條線,怎么做酱固?

a》注意:路徑的顏色的設(shè)置需要在 drawRect:方法中械念,并且因為每一條線都是獨立的,我們可能為每一條線設(shè)置不同的顏色等狀態(tài)运悲。我們需要為每一個路徑龄减,創(chuàng)建獨立的對象,讓它成為一個獨立的存在扇苞,并且擁有顏色屬性欺殿,那么我們可以通類對象來設(shè)置顏色屬性寄纵。因此鳖敷,我們需要創(chuàng)建一個路徑類脖苏;

@interface MayPath : UIBezierPath

//每條路徑自己的顏色狀態(tài)

@property (nonatomic, strong) UIColor *pathColor;

@end

b》畫一條線:至少分兩步走:點擊 和 移動,所以需要調(diào)用touchesBegan方法和touchesMove方法

3-1.?調(diào)用方法

在MayView類中引入頭文件

#import "MayPath.h"

在“touchesBegan方法”里面創(chuàng)建一條路徑定踱,并且添加到全局的路徑數(shù)組中(為什么每次都創(chuàng)建而不是用全局的棍潘?因為畫板不可能只點擊一次,所以我們要為每一次的點擊都創(chuàng)建一個路徑)

//開始點擊

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {

//? ? 1.創(chuàng)建路徑

//每次點擊時候都創(chuàng)建一條MayPath對象路徑

MayPath * path = [MayPath bezierPath];

//? ? 將創(chuàng)建好的路徑添加到路徑數(shù)組中

[self.allPaths addObject:path];

3-2.這一步我們要在MayView.h文件中創(chuàng)建一個lineWidth屬性崖媚。(后面會將它與sb中的slider控件關(guān)聯(lián))

//線寬(設(shè)為公開屬性為外部調(diào)用亦歉,與slider控件關(guān)聯(lián))

@property (nonatomic, assign) CGFloat lineWidth;

回到.m文件,設(shè)置線寬,將定于好的lineWidth賦值過來

//? ? 2.設(shè)置線寬

[path setLineWidth:self.lineWidth];

3-3.我們需要回到控制器類ViewController中畅哑,引入自定義MayView類肴楷;

將MayView作為屬性傳入

#import "MayView.h"。

@interface ViewController ()

//拿到自定義view(畫板)荠呐,以拿到畫板的屬性

@property (weak, nonatomic) IBOutlet MayView *paintView;

@end

然后赛蔫,為sb中的slider控件拖一條方法連線,并且在屬性欄中更改它的值


//設(shè)置線寬與UISlider關(guān)聯(lián)

- (IBAction)setLineWidth:(UISlider *)sender {

self.paintView.lineWidth = sender.value;

}

這樣泥张,lineWidth的值會隨著UISlider控件的變化而變化呵恢;

同時我們需要在viewDidLoad中設(shè)置線寬的初始值,不設(shè)置媚创,一開始沒有點擊UISlider渗钉,那么默認(rèn)值為0,會無法顯示钞钙。

- (void)viewDidLoad {

[super viewDidLoad];

//設(shè)置線寬的初始值

self.paintView.lineWidth = 1;

}

3-4.回到MayView.m中

//? ? 連接處的樣式

[path setLineJoinStyle:kCGLineJoinRound];

//? ? 收尾樣式

[path setLineCapStyle:kCGLineCapRound];

3-5.設(shè)置顏色

像lineWidth屬性一樣鳄橘,我們將lineColor設(shè)置為公開的屬性。然后設(shè)置路徑的顏色為lineColor

@property (nonatomic, strong) UIColor * lineColor;

//? ? 將顏色存儲在對象屬性中

path.pathColor = self.lineColor;

在控制器類中為顏色按鈕拖線芒炼,三個按鈕控件連接同一個方法挥唠。將按鈕的背景顏色傳給view的lineColor;

//設(shè)置顏色

- (IBAction)setLineColor:(UIButton *)sender {

self.paintView.lineColor = sender.backgroundColor;

}

回到MayView.m中

- (void)drawRect:(CGRect)rect {

//? ? 設(shè)置顏色

//? ? [[UIColor blackColor] setStroke];

//? ? 渲染(遍歷數(shù)組中所有路徑焕议,進行繪制)

for (MayPath * path in self.allPaths) {

//為路徑渲染相應(yīng)的顏色

[path.pathColor setStroke];

//渲染路徑

[path stroke];

}

}

3-6.開始描線

//? ? 3.設(shè)置起點

//? ? 3-1.獲取點擊對象

UITouch * touch =[touches anyObject];

//? ? 3-2.獲取點擊的位置

CGPoint currentBeganPoint = [touch locationInView:touch.view];

//? ? 4.設(shè)置起點

[path moveToPoint:currentBeganPoint];

//每次單擊都有效果

[path addLineToPoint:currentBeganPoint];

//重繪

[self setNeedsDisplay];

}

//點擊移動- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event {

//? ? 1.獲取點擊對象

UITouch * touch = [touches anyObject];

//? ? 2.獲取點擊位置

CGPoint? currentMovedPoint = [touch locationInView:touch.view];

//? ? 3.將點擊起點處 連線 到當(dāng)前點(取得起點:就是數(shù)組中的最后一個)

[[self.allPaths lastObject] addLineToPoint:currentMovedPoint];

//? ? 4.重繪/渲染? view

[self setNeedsDisplay];

}

三宝磨、清屏、撤銷盅安、橡皮 功能

在MayView.h聲明方法唤锉,在.m中實現(xiàn),在控制器類中為三個按鈕拖線并且分別調(diào)用各自的方法

//清屏

- (void)clearScreen {

//將路徑數(shù)組清空

[self.allPaths removeAllObjects];

//? ? 重繪 view

[self setNeedsDisplay];

}

//撤銷

- (void)goBack {

//清除路徑最后一條

[self.allPaths removeLastObject];

//? ? 重繪 view

[self setNeedsDisplay];

}

//橡皮

- (void)erase{

self.lineColor = self.backgroundColor;

}

四别瞭、保存到相冊功能

4-1.在MayView.h聲明方法窿祥,在.m中實現(xiàn)

4-2.圖片類型的上下文:其實就是改目標(biāo)。開啟圖片類型的上下文:(默認(rèn)是view蝙寨,但——只要你開啟了圖片類型的上下文晒衩,那么渲染的目標(biāo)就是內(nèi)部的UIImage對象

4-3.以后比較常用的開啟圖片上下文的方法:

UIGraphicsBeginImageContextWithOptions(大小嗤瞎,不透明,縮放)

大小:確定后里面圖片就是這個大小

縮放:設(shè)置為0就是根據(jù)你的屏幕設(shè)置它的點倍數(shù)

4-4.有開啟圖片上下文就要有關(guān)閉听系;UIGraphicsEndImageContext

4-5.小技巧

和繪圖有關(guān)的方法都是CGContext開頭

與上下文有關(guān)的方法是UIGraphics開頭

//保存

- (void)saveToPhoto {

//開啟圖片類型的上下文

UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);

CGContextRef context = UIGraphicsGetCurrentContext();

//圖層內(nèi)容給與到上下文

[self.layer renderInContext:context];

//獲取圖片

UIImage * img = UIGraphicsGetImageFromCurrentImageContext();

//將圖片保存到相冊

UIImageWriteToSavedPhotosAlbum(img, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);

//? ? ? ? 關(guān)閉圖片類型上下文

UIGraphicsEndImageContext();

}

注意:保存到相冊的那個方法UIImageWriteToSavedPhotosAlbum:它內(nèi)部假如要調(diào)用一個方法只能是(image:didFinishSavingWithError:contextInfo)贝奇。官方文檔有說明;

- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {

if (error) {

NSLog(@"保存失敗");

}

else NSLog(@"保存成功");

}

在控制器類中為保存按鈕拖線并且調(diào)用方法

//保存

- (IBAction)beSave:(UIBarButtonItem *)sender {

//彈出提示框

UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"將保存到相冊" message:@"請輸入圖片的名字:" preferredStyle:UIAlertControllerStyleAlert];

[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {

}];

[self presentViewController:alert animated:YES completion:nil];

//? ? 添加按鈕

UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];

UIAlertAction * confirm = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

//? ? 文件保存名字

UITextField * tf = alert.textFields[0];

self.paintView.imgName = [NSString stringWithFormat:@"%@.png",tf.text];

[self.paintView saveToPhoto];

}];

[alert addAction:cancel];

[alert addAction:confirm];

}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末靠胜,一起剝皮案震驚了整個濱河市掉瞳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浪漠,老刑警劉巖陕习,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異址愿,居然都是意外死亡该镣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門响谓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來损合,“玉大人,你說我怎么就攤上這事歌粥∷觯” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵失驶,是天一觀的道長土居。 經(jīng)常有香客問我,道長嬉探,這世上最難降的妖魔是什么擦耀? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮涩堤,結(jié)果婚禮上眷蜓,老公的妹妹穿的比我還像新娘。我一直安慰自己胎围,他們只是感情好吁系,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著白魂,像睡著了一般汽纤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上福荸,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天蕴坪,我揣著相機與錄音,去河邊找鬼。 笑死背传,一個胖子當(dāng)著我的面吹牛呆瞻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播径玖,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼痴脾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挺狰?” 一聲冷哼從身側(cè)響起明郭,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤买窟,失蹤者是張志新(化名)和其女友劉穎丰泊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體始绍,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡瞳购,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了亏推。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片学赛。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吞杭,靈堂內(nèi)的尸體忽然破棺而出盏浇,到底是詐尸還是另有隱情,我是刑警寧澤芽狗,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布绢掰,位于F島的核電站,受9級特大地震影響童擎,放射性物質(zhì)發(fā)生泄漏滴劲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一顾复、第九天 我趴在偏房一處隱蔽的房頂上張望班挖。 院中可真熱鬧,春花似錦芯砸、人聲如沸萧芙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽双揪。三九已至,卻和暖如春虎谢,著一層夾襖步出監(jiān)牢的瞬間盟榴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工婴噩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留擎场,地道東北人羽德。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像迅办,于是被迫代替她去往敵國和親宅静。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • Quartz2D以及drawRect的重繪機制字?jǐn)?shù)1487 閱讀21 評論1 喜歡1一站欺、什么是Quartz2D Q...
    PurpleWind閱讀 766評論 0 3
  • Quartz2D 簡介及用途 Quartz 2D 是一個二維繪圖引擎姨夹,同時支持iOS和Mac系統(tǒng),Quartz2D...
    45b645c5912e閱讀 962評論 1 16
  • 在iOS中隨處都可以看到絢麗的動畫效果矾策,實現(xiàn)這些動畫的過程并不復(fù)雜磷账,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,471評論 6 30
  • Quartz2D 簡介 Quartz2D是二維(平面)的繪圖引擎(經(jīng)包裝的函數(shù)庫贾虽,方便開發(fā)者使用逃糟。也就是說蘋果幫我...
    iOS_Cqlee閱讀 629評論 0 2
  • 轉(zhuǎn)載自cocoaChina http://www.cocoachina.com/bbs/read.php?tid...
    wzjmyff閱讀 409評論 0 0