iOS開發之畫圖板(貝塞爾曲線)

貝塞爾曲線,聽著挺牛氣一詞,不過下面我們在做畫圖板的時候就用到貝塞爾繪直線,沒用到繪制曲線的功能。如果會點PS的小伙伴會對貝塞爾曲線有更直觀的理解。這篇文章的重點不在于如何用使用貝塞爾曲線,而是利用貝塞爾劃線的功能來封裝一個畫圖板。

畫圖板的截圖如下,上面的白板就是我們的畫圖板,是自己封裝好的一個UIView,下面會詳細的介紹如何封裝這個畫圖板,下面的控件用來控制我們畫圖板的屬性以及Undo,Redo和保存功能。點擊保存時會把繪制的圖片保存到手機的相冊中。下面是具體的實現方案。

一、 封裝畫圖板

其實上面的白板就是一繼承于UiView的一個子類,我們可以在這個子類中添加我們畫圖板相應的屬性和方法,然后實例化成對象添加到 ViewController中,當然為了省事添加白板的時候是通過storyboard來完成的,讀者也可以自己實例化然后手動的添加到相應的 ViewController中。

1. 封裝白板的第一步是新建一個UIView的子類MyView,然后添加相應的屬性和方法。MyView.h中的代碼如下,代碼具體意思請參照注釋:

#import

@interfaceMyView?:?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延展部分如下:

@interfaceMyView()

//聲明貝塞爾曲線

@property(nonatomic,?strong)?UIBezierPath?*bezier;

//存儲Undo出來的線條

@property(nonatomic,?strong)?NSMutableArray?*cancleArray;

@end

3. 下面的代碼就是實現部分的代碼了,會根據不同功能給出相應的說明。

(1) 初始化我們的白板,給線條指定默認顏色和寬度并且給相應的變量分配內存空間,初始化代碼如下:

//進行一些初始化工作

-(void)initMyView

{

self.color?=?[UIColor?redColor];

self.lineWidth?=?1;

self.allLine?=?[NSMutableArray?arrayWithCapacity:50];

self.cancleArray?=?[NSMutableArray?arrayWithCapacity:50];

}

(2) Undo功能的封裝,相當于兩個棧,把顯示的線條出棧,進入為不顯示的線條棧中,每執行一次此操作顯示線條棧中的元素會少一條而不顯示線條棧中會多一條,大致就這個意思吧,代碼如下:

//UnDo操作

-(void)backImage

{

if(self.allLine.count?>?0)

{

intindex?=?self.allLine.count?-?1;

[self.cancleArray?addObject:self.allLine[index]];

[self.allLine?removeObjectAtIndex:index];

[self?setNeedsDisplay

];

}

}

(3) Redo操作和Undo操作相反,從未顯示棧中取出元素放入顯示的棧中,代碼中的棧我們是用數組來表示的,代碼如下:

//ReDo操作

-(void)forwardImage

{

if(self.cancleArray.count?>?0)

{

intindex?=?self.cancleArray.count?-?1;

[self.allLine?addObject:self.cancleArray[index]];

[self.cancleArray?removeObjectAtIndex:index];

[self?setNeedsDisplay];

}

}

(4) 當開始觸摸時我們新建一個BezierPath,把觸摸起點設置成BezierPath的起點,并把將要畫出的線條以及線條對應的屬性封裝成字典添加到顯示棧中,代碼如下

-(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中,代碼如下

-(void)touchesMoved:(NSSet?*)touches?withEvent:(UIEvent?*)event

{

UITouch?*myTouche?=?[touches?anyObject];

CGPoint?point?=?[myTouche?locationInView:self];

[self.bezier?addLineToPoint:point];

//重繪界面

[self?setNeedsDisplay];

}

(6) 畫出線條

//?Only?override?drawRect:?if?you?perform?custom?drawing.

//?An?empty?implementation?adversely?affects?performance?during?animation.

-?(void)drawRect:(CGRect)rect

{

//對之前的線的一個重繪過程

for(inti?=?0;?i?<?self.allLine.count;?i?++)

{

NSDictionary?*tempDic?=?self.allLine[i];

UIColor?*color?=?tempDic[@"color"];

CGFloat?width?=?[tempDic[@"lineWidth"]?floatValue];

UIBezierPath?*path?=?tempDic[@"line"];

[color?setStroke];

[path?setLineWidth:width];

[path?stroke];

}

}

二、 畫圖板的使用

上面是封裝畫圖板要用到的全部代碼,下面的代碼就是如何在ViewController中使用我們的畫圖板了,如何實例化控件,以及控件的初始化,注冊回調等在這就不做贅述了,下面給出了主要控件的回調方法。

1. 通過Slider來調節線條的寬度

//通過slider來設置線條的寬度

-?(IBAction)sliderChange:(id)sender

{

self.myView.lineWidth?=?self.mySlider.value;

}

2. 通過SegmentControl來設置線條的顏色

/通過segmentControl來設置線條的顏色

-?(IBAction)tapSegment:(id)sender?{

switch(self.mySegment.selectedSegmentIndex)?{

case0:

self.myView.color?=?[UIColor?redColor];

break;

case1:

self.myView.color?=?[UIColor?blackColor];

break;

case2:

self.myView.color?=?[UIColor?greenColor];

break;

default:

break;

}

}

3. undo和redo操作

//Undo

-?(IBAction)tapBack:(id)sender?{

[self.myView?backImage];

}

//Redo操作

-?(IBAction)tapGo:(id)sender?{

[self.myView?forwardImage];

}

4. 保存操作,也許下面的保存操作在處理方式上略顯笨拙,如有更好的解決方案請留言。 保存的時候我是先截了個屏,然后把白板進行切割,把切割后圖片存入到相冊中,代碼如下:

//把畫的圖保存到相冊

-?(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];

}

以上就是本畫圖板的主要代碼了,有不足之處還望批評指正。轉載請注明出處。在本文結束時在來幾張截圖吧

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容