貝塞爾曲線,聽著挺牛氣一詞,不過下面我們在做畫圖板的時候就用到貝塞爾繪直線,沒用到繪製曲線的功能。如果會點PS的小夥伴會對貝塞爾曲線有更直觀的理解。這篇博文的重點不在於如何用使用貝塞爾曲線,而是利用貝塞爾劃線的功能來封裝一個畫圖板。
畫圖板的截圖如下,上面的白板就是我們的畫圖板,是自己封裝好的一個UIView,下面會詳細的介紹如何封裝這個畫圖板,下面的控制元件用來控制我們畫圖板的屬性以及Undo,Redo和儲存功能。點選儲存時會把繪製的圖片儲存到手機的相簿中。下面是具體的實現方案。
一.封裝畫圖板
其實上面的白板就是一繼承於UiView的一個子類,我們可以在這個子類中新增我們畫圖板相應的屬性和方法,然後例項化成物件新增到ViewController中,當然為了省事新增白板的時候是通過storyboard來完成的,讀者也可以自己例項化然後手動的新增到相應的ViewController中。
1.封裝白板的第一步是新建一個UIView的子類MyView,然後新增相應的屬性和方法。MyView.h中的程式碼如下,程式碼具體意思請參照註釋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#import 2 @interface MyView : UIView //用來設定線條的顏色 @property (nonatomic, strong) UIColor *color; //用來設定線條的寬度 @property (nonatomic, assign) CGFloat lineWidth; //用來記錄已有線條 @property (nonatomic, strong) NSMutableArray *allLine; //初始化相關引數 -(void)initMyView; //unDo操作 -(void)backImage; //reDo操作 -(void)forwardImage; @end |
2、上面的程式碼是對外的介面,有些屬性我們是寫在MyView.m的延展中以實現私有的目的,MyView延展部分如下:
1 2 3 4 5 6 |
@interface MyView() //宣告貝塞爾曲線 @property(nonatomic, strong) UIBezierPath *bezier; //儲存Undo出來的線條 @property(nonatomic, strong) NSMutableArray *cancleArray; @end |
3.下面的程式碼就是實現部分的程式碼了,會根據不同功能給出相應的說明
(1).初始化我們的白板,給線條指定預設顏色和寬度並且給相應的變數分配記憶體空間,初始化程式碼如下:
1 2 3 4 5 6 7 8 |
//進行一些初始化工作 -(void)initMyView { self.color = [UIColor redColor]; self.lineWidth = 1; self.allLine = [NSMutableArray arrayWithCapacity:50]; self.cancleArray = [NSMutableArray arrayWithCapacity:50]; } |
(2)Undo功能的封裝,相當於兩個棧,把顯示的線條出棧,進入為不顯示的線條棧中,每執行一次此操作顯示線條棧中的元素會少一條而不顯示線條棧中會多一條,大致就這個意思吧,程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//UnDo操作 -(void)backImage { if (self.allLine.count > 0) { int index = self.allLine.count - 1; [self.cancleArray addObject:self.allLine[index]]; [self.allLine removeObjectAtIndex:index]; [self setNeedsDisplay ]; } } |
(3)Redo操作和Undo操作相反,從未顯示棧中取出元素放入顯示的棧中,程式碼中的棧我們是用陣列來表示的,程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//ReDo操作 -(void)forwardImage { if (self.cancleArray.count > 0) { int index = self.cancleArray.count - 1; [self.allLine addObject:self.cancleArray[index]]; [self.cancleArray removeObjectAtIndex:index]; [self setNeedsDisplay]; } } |
(4)、當開始觸控時我們新建一個BezierPath,把觸控起點設定成BezierPath的起點,並把將要畫出的線條以及線條對應的屬性封裝成字典新增到顯示棧中,程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //新建貝塞斯曲線 self.bezier = [UIBezierPath bezierPath]; //獲取觸控的點 UITouch *myTouche = [touches anyObject]; CGPoint point = [myTouche locationInView:self]; //把剛觸控的點設定為bezier的起點 [self.bezier moveToPoint:point]; //把每條線存入字典中 NSMutableDictionary *tempDic = [[NSMutableDictionary alloc] initWithCapacity:3]; [tempDic setObject:self.color forKey:@"color"]; [tempDic setObject:[NSNumber numberWithFloat:self.lineWidth] forKey:@"lineWidth"]; [tempDic setObject:self.bezier forKey:@"line"]; //把線加入陣列中 [self.allLine addObject:tempDic]; } |
(5)當移動也就是劃線的時候把點儲存到BezierPath中,程式碼如下
1 2 3 4 5 6 7 8 9 10 11 |
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *myTouche = [touches anyObject]; CGPoint point = [myTouche locationInView:self]; [self.bezier addLineToPoint:point]; //重繪介面 [self setNeedsDisplay]; } |
(6)畫出線條
1 2 3 4 5 6 7 8 9 10 11 |
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *myTouche = [touches anyObject]; CGPoint point = [myTouche locationInView:self]; [self.bezier addLineToPoint:point]; //重繪介面 [self setNeedsDisplay]; } |
二.畫圖板的使用
上面是封裝畫圖板要用到的全部程式碼,下面的程式碼就是如何在ViewController中使用我們的畫圖板了,如何例項化控制元件,以及控制元件的初始化,註冊回撥等在這就不做贅述了,下面給出了主要控制元件的回撥方法
1、通過Slider來調節線條的寬度
1 2 3 4 5 |
//通過slider來設定線條的寬度 - (IBAction)sliderChange:(id)sender { self.myView.lineWidth = self.mySlider.value; } |
2、通過SegmentControl來設定線條的顏色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/通過segmentControl來設定線條的顏色 - (IBAction)tapSegment:(id)sender { switch (self.mySegment.selectedSegmentIndex) { case 0: self.myView.color = [UIColor redColor]; break; case 1: self.myView.color = [UIColor blackColor]; break; case 2: self.myView.color = [UIColor greenColor]; break; default: break; } } |
3、undo和redo操作
1 2 3 4 5 6 7 8 9 |
//Undo - (IBAction)tapBack:(id)sender { [self.myView backImage]; } //Redo操作 - (IBAction)tapGo:(id)sender { [self.myView forwardImage]; } |
4.儲存操作,也許下面的儲存操作在處理方式上略顯笨拙,如有更好的解決方案請留言。 儲存的時候我是先截了個屏,然後把白板進行切割,把切割後圖片存入到相簿中,程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//把畫的圖儲存到相簿 - (IBAction)tapSave:(id)sender { //截圖 UIGraphicsBeginImageContext(self.view.bounds.size); [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *uiImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); //擷取畫圖版部分 CGImageRef sourceImageRef = [uiImage CGImage]; CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, CGRectMake(36, 6, 249, 352)); UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; //把截的屏儲存到相簿 UIImageWriteToSavedPhotosAlbum(newImage , nil, nil, nil); //給個儲存成功的反饋 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"儲存照片成功" message:@"您已將照片儲存於圖片庫中,開啟照片程式即可檢視。" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } |
以上就是本畫圖板的主要程式碼了,有不足之處還望批評指正。轉載請註明出處。在本文結束時在來幾張截圖吧(demo下載地址:http://www.pgyer.com/LTQ8):
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!