Recently in learning quartz2d, learned a simple artboard implementation, now the implementation process record.
The main point is to draw lines, screenshots, draw pictures, select pictures, and save all drawn lines.
First of all, the layout of the control on the storyboard, set constraints, and so on, the final effect is this:
Custom artboard Drawview that may be loaded from xib or created manually, so the method of creating an object needs to implement two:
#import <UIKit/UIKit.h>
@interface drawview:uiview
/** line width *
/@property (nonatomic, assign) Nsinteger linewidth;
/** color *
/@property (nonatomic, strong) Uicolor *pathcolor;
/** Picture * * *
@property (nonatomic, strong) UIImage *image;
-(void) clear;
-(void) undo;
-(void) awakefromnib {
[self setUp];
}
-(Instancetype) initWithFrame: (CGRect) Frame {
if (self = = [Super Initwithframe:frame]) {
[self setUp];
} return
self;
}
The setup initialization method, the thing to do when initializing is to add a drag gesture to the artboard, or you can set the line width of the brush path here
Custom Initialization Method
-(void) setUp {
//Add gesture
uipangesturerecognizer *pan = [[Uipangesturerecognizer alloc] Initwithtarget:self Action: @selector (pan:)];
[Self addgesturerecognizer:pan];
Set the path line width when initializing
_linewidth = 2;
}
Start drawing lines when you move your finger on the artboard, because the native Uibezierpath class has no way to set the path color, so you can only customize the paths class
#import <UIKit/UIKit.h>
@interface drawpath:uibezierpath
@property (nonatomic, strong) Uicolor * Pathcolor;
@end
When the finger moves, draw the line, the path is a custom path class
@interface Drawview ()
@property (nonatomic, strong) DrawPath *path;
/** Save the array of all paths *
/@property (nonatomic, strong) Nsmutablearray *patharr;
@end
//Lazy load
-(Nsmutablearray *) Patharr {
if (_patharr = = nil) {
_patharr = [Nsmutablearray array];< c23/>} return
_patharr
}
-(void) pan: (Uipangesturerecognizer *) pan {
//Get start touch point
cgpoint STARTP = [pan locationinview:self];
if (pan.state = = Uigesturerecognizerstatebegan) {
//create Bezier path
_path = [[DrawPath alloc]init];
_path.linewidth = _linewidth;
_path.pathcolor = _pathcolor;
The path cannot be added to the array when the finger is raised, because the path has not been added to the array when the paintings line is enumerated
[_patharr Addobject:_path];
Set the starting point
[_path MOVETOPOINT:STARTP];
}
Wired
[_path ADDLINETOPOINT:STARTP];
redrawing, calling the DrawRect method
[self setneedsdisplay];
}
Draw a line to achieve the DrawRect method, draw lines or pictures, is the array of the path to draw all the
-(void) DrawRect: (cgrect) Rect {
//Draw all paths for
(DrawPath *path in Self.patharr) {
if ([path iskindofclass:[ UIImage class]] {
//paint
uiimage *image = (uiimage *) path;
[Image Drawinrect:rect];
} else {
//Draw line
[Path.pathcolor set];
[Path stroke];}}
When you add a picture to the artboard
-(void) SetImage: (UIImage *) Image {
_image = image;
[Self.patharr Addobject:image];
Redraw the call DrawRect to display the picture on the artboard
[self setneedsdisplay];
You can also encapsulate the actions of the direct update path array in the artboard
-(void) Clear {
//erase
[Self.patharr removeallobjects];
[Self setneedsdisplay];
}
-(void) Undo {
//revoke
[Self.patharr removelastobject];
[Self setneedsdisplay];
}
In the controller:
@interface Viewcontroller () <uiimagepickercontrollerdelegate, uinavigationcontrollerdelegate>
@property (Weak, nonatomic) Iboutlet Drawview *drawview;
@end
Implement several buttons on the artboard:
-(Ibaction) clear: (ID) Sender {//clearing screen [_drawview cleared];
}-(Ibaction) Undo: (ID) Sender {//Undo [_drawview Undo];
}-(Ibaction) Eraser: (ID) Sender {//erase is to set the color of the path to the background color of the artboard, false _drawview.pathcolor = _drawview.backgroundcolor;
_drawview.linewidth = 20;
}-(Ibaction) Changelinewidth: (UISlider *) Sender {//Change the path line width _drawview.linewidth = sender.value;
}-(Ibaction) ChangeColor: (UIButton *) Sender {//change path color _drawview.pathcolor = Sender.backgroundcolor; }-(Ibaction) Pickphoto: (ID) Sender {//SELECT Photo//Pop-up system album Uiimagepickercontroller *picker = [[Uiimagepickercontroll
ER Alloc]init]; Set the source of the selection controller uiimagepickercontrollersourcetypesavedphotosalbum: Photo Gallery Picker.sourcetype =
Uiimagepickercontrollersourcetypesavedphotosalbum;
Set Agent picker.delegate = self;
Modal out controller [self presentviewcontroller:picker animated:yes completion:nil]; }-(void) Imagepickercontroller: (Uiimagepickercontroller *) Picker diDfinishpickingmediawithinfo: (nsdictionary<nsstring *,id> *) Info {//Get selected picture UIImage *image = Info[uiimagepic
Kercontrolleroriginalimage];
Create a view imagehandleview that handles the picture *handleview = [[Imagehandleview alloc]initwithframe:self.drawview.bounds];
Handleview.handlecompletionblock = ^ (UIImage *image) {_drawview.image = image;
};
[Self.drawview Addsubview:handleview];
Draw the picture on the artboard handleview.image = image;
_drawview.image = image;
Dismiss [self dismissviewcontrolleranimated:yes completion:nil];
NSLog (@ "%@", info);
}-(Ibaction) Save: (ID) Sender {[UIView animatewithduration:0.15 animations:^{//save content on current artboard//open context
Uigraphicsbeginimagecontextwithoptions (_drawview.bounds.size, NO, 0);
Gets the bitmap context cgcontextref CTX = Uigraphicsgetcurrentcontext ();
Renders the layer on the control to the context [_drawview.layer renderincontext:ctx]; Gets the picture in the context uiimage *image = UigraphicsgetimagefromcurrEntimagecontext ();
Closes the context uigraphicsendimagecontext (); Save picture to album Uiimagewritetosavedphotosalbum (image, Self, @selector (image:didFinishSavingWithError:contextInfo:), nil)
;
Self.drawView.alpha = 0;
} completion:^ (BOOL finished) {[UIView animatewithduration:0.15 animations:^{self.drawView.alpha = 1;
}];
}]; The method must be this one, not casually written-(void) Image: (UIImage *) image didfinishsavingwitherror: (nserror *) error ContextInfo: (void *)
ContextInfo {NSLog (@ "save Success");
}
Select the picture from the album after the picture is displayed on the artboard but has not yet been rendered to the layer, this time need to move the picture to zoom rotation of these operations, but UIImage can not stretch the rotation of these operations, Uiimageview, So the solution is to customize a view to deal specifically with the operation of the picture, put a uiimageview on the custom view, and set the image from the photo album to Uiimageview, so that the custom view operation Uiiamgeview.
#import <UIKit/UIKit.h>
@interface imagehandleview:uiview
/** Pictures * * *
@property (nonatomic, Strong) UIImage *image;
/** block */
@property (nonatomic, strong) void (^handlecompletionblock) (UIImage *image);
@end
#import "ImageHandleView.h" @interface Imagehandleview () <UIGestureRecognizerDelegate>/** image */@property (
Nonatomic, weak) Uiimageview *imageview;
@end @implementation Imagehandleview//Prevent touch events on the picture from passing to the artboard-(UIView *) HitTest: (cgpoint) point withevent: (Uievent *) Event {
return _imageview; }-(Uiimageview *) ImageView {if (_imageview = = nil) {Uiimageview *imagev = [[Uiimageview alloc]initwithfram
E:self.bounds];
_imageview = Imagev;
Set Imgaeview allow interaction with the user _imageview.userinteractionenabled = YES;
Add gesture [self setupgesturerecognizer];
Add this imageview to the view on the image processing [self Addsubview:imagev];
return _imageview; #pragma mark-Add gesture-(void) Setupgesturerecognizer {//translate gesture uipangesturerecognizer *pan = [[Uipangesturerecogn
Izer alloc]initwithtarget:self Action: @selector (pan:)];
[_imageview Addgesturerecognizer:pan]; Rotate gesture Uirotationgesturerecognizer *rotation = [[UirotationgestuRerecognizer alloc]initwithtarget:self Action: @selector (rotation:)];
Rotation.delegate = self;
[_imageview addgesturerecognizer:rotation]; Zoom gesture Uipinchgesturerecognizer *pinch = [Uipinchgesturerecognizer alloc]initwithtarget:self action: @selector (pinch
:)];
Pinch.delegate = self;
[_imageview Addgesturerecognizer:pinch]; Long press gesture Uilongpressgesturerecognizer *longpress = [[Uilongpressgesturerecognizer alloc]initwithtarget:self action:@
Selector (longpress:)];
[_imageview addgesturerecognizer:longpress]; #pragma mark-process panning gesture-(void) pan: (Uipangesturerecognizer *) Pan {//Get finger offset cgpoint TRANP = [Pan Translationi
NView:self.imageView];
Setting the ImageView deformation self.imageView.transform = Cgaffinetransformtranslate (Self.imageView.transform, tranp.x, TRANP.Y);
Reset [Pan Settranslation:cgpointzero InView:self.imageView]; #pragma mark-Process rotation gesture-(void) Rotation: (Uirotationgesturerecognizer *) Rotation {//set ImageView deformation Self.imageviEw.transform = Cgaffinetransformrotate (Self.imageView.transform, rotation.rotation);
Reset rotation.rotation = 0; #pragma mark-Process zoom gesture-(void) Pinch: (Uipinchgesturerecognizer *) Pinch {//set ImageView deformation self.imageView.transf
ORM = Cgaffinetransformscale (Self.imageView.transform, Pinch.scale, Pinch.scale);
Reset Pinch.scale = 1; #pragma mark-handle long press gesture-(void) Longpress: (Uilongpressgesturerecognizer *) longpress {//Picture processing complete if (Longpress.sta Te = = Uigesturerecognizerstatebegan) {//Highlight effect [UIView animatewithduration:0.25 animations:^{Self.imag
Eview.alpha = 0; } completion:^ (BOOL finished) {[UIView animatewithduration:0.25 animations:^{Self.imageView.alpha =
1; completion:^ (BOOL finished) {//Highlight to generate a new picture//Open bitmap context Uigraphicsbeginimagecontextwitho
Ptions (self.bounds.size, NO, 0); Gets the bitmap context cgcontextref CTX = Uigraphicsgetcurrentcontext ();
Renders the layer of the control to the context [Self.layer renderincontext:ctx];
Gets the new picture from the context uiimage *image = Uigraphicsgetimagefromcurrentimagecontext ();
Closes the context uigraphicsendimagecontext ();
Call block if (_handlecompletionblock) {_handlecompletionblock (image);
//Remove the parent control [self removefromsuperview];
}];
}]; #pragma mark-Gesture Agent Method <UIGestureRecognizerDelegate>-(BOOL) Gesturerecognizer: (Uigesturerecognizer *) gestu Rerecognizer Shouldrecognizesimultaneouslywithgesturerecognizer: (Uigesturerecognizer *) OtherGestureRecognizer {//
Yes to support multiple gestures return yes at the same time;
}-(void) SetImage: (UIImage *) image {_image = image;
Show the picture to the uiimageview self.imageView.image = image;
} @end
It should be noted that when the long press will be the operation of the picture drawing is a new picture on the artboard, this time need to set this image to the artboard Drawview, but this time it is necessary to deal with the image of the view to import the artboard view, so the coupling is too strong. So for the understanding of decoupling, you can use a proxy or block. I used block to save the image just generated, and then assign the value to Drawview after initializing the Imagehandleview in the controller.
The last thing you save on the artboard is to save the content from the artboard to the album. Note that the method that is executed after the save is done must be this:
Copy Code code as follows:
-(void) Image: (UIImage *) image didfinishsavingwitherror: (nserror *) error ContextInfo: (void *) ContextInfo;
The final effect diagram is this:
The above is the entire content of this article, I hope to learn about iOS program design help.