更新:
之前写这个控件只是为了好玩,现在项目中需要图片处理功能,就把这个控件润色了一下,让它看起来像是那么回事。
最新效果如下:
通过数据源方法把要处理的图片传递给裁剪控件,可设置裁剪框的最小宽度和高度,每当裁剪框拖动结束后都会回调代理方法,传递裁剪框的frame,当然你也可以自己添加一个block来回调,把最新截图传递给代理对象。
创建自定义控件的思路
控件的所有细节都是直接在drawRect中画出来的,这样做很方便,但是有个缺陷,就是它只能通过用户触摸移动来改变形态,不能通过设置起始终点值来运行动画。
在drawRect中画黑色蒙版和中间的空白,然后画空白的边框、以及边框的四角和四边上的触摸线,最后画中间的四条分割线。代码比较简单:
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 蒙版层
[[UIColor colorWithWhite:0.0 alpha:0.3] setFill];
CGContextFillRect(ctx, self.bounds);
CGContextClearRect(ctx, self.pictureFrame);
// 矩形框
[[UIColor whiteColor] setStroke];
CGContextAddRect(ctx, self.pictureFrame);
CGContextStrokePath(ctx);
CGFloat edge_3 = 3;
CGFloat edge_20 = 20;
[[UIColor whiteColor] setFill];
// 左上
CGContextAddRect(ctx, CGRectMake(_cornerPoint.topLeftPoint.x-edge_3, _cornerPoint.topLeftPoint.y-edge_3, edge_20, edge_3));
CGContextFillPath(ctx);
CGContextAddRect(ctx, CGRectMake(_cornerPoint.topLeftPoint.x-edge_3, _cornerPoint.topLeftPoint.y-edge_3, edge_3, edge_20));
CGContextFillPath(ctx);
// 左下
CGContextAddRect(ctx, CGRectMake(_cornerPoint.bottomLeftPoint.x-edge_3, _cornerPoint.bottomLeftPoint.y, edge_20, edge_3));
CGContextFillPath(ctx);
CGContextAddRect(ctx, CGRectMake(_cornerPoint.bottomLeftPoint.x-edge_3, _cornerPoint.bottomLeftPoint.y-edge_20+edge_3, edge_3, edge_20));
CGContextFillPath(ctx);
// 右上
CGContextAddRect(ctx, CGRectMake(_cornerPoint.topRightPoint.x-edge_20+edge_3, _cornerPoint.topRightPoint.y-edge_3, edge_20, edge_3));
CGContextFillPath(ctx);
CGContextAddRect(ctx, CGRectMake(_cornerPoint.topRightPoint.x, _cornerPoint.topRightPoint.y-edge_3, edge_3, edge_20));
CGContextFillPath(ctx);
// 右下
CGContextAddRect(ctx, CGRectMake(_cornerPoint.topRightPoint.x-edge_20+edge_3, _cornerPoint.bottomRightPoint.y, edge_20, edge_3));
CGContextFillPath(ctx);
CGContextAddRect(ctx, CGRectMake(_cornerPoint.bottomRightPoint.x, _cornerPoint.bottomRightPoint.y-edge_20+edge_3, edge_3, edge_20));
CGContextFillPath(ctx);
CGFloat direction_30 = 30;
DirectionRect frame = directionPointToDirectionRect(_directionPoint, direction_30, edge_3);
// 上
CGContextAddRect(ctx, frame.topRect);
CGContextFillPath(ctx);
// 下
CGContextAddRect(ctx, frame.bottomRect);
CGContextFillPath(ctx);
// 左
CGContextAddRect(ctx, frame.leftRect);
CGContextFillPath(ctx);
// 右
CGContextAddRect(ctx, frame.rightRect);
CGContextFillPath(ctx);
CGFloat height_1 = 1/[UIScreen mainScreen].scale;
// 横一
CGContextAddRect(ctx, CGRectMake((int)_cornerPoint.topLeftPoint.x, (int)(_cornerPoint.bottomLeftPoint.y-(_cornerPoint.bottomLeftPoint.y-_cornerPoint.topLeftPoint.y)/3*2), _cornerPoint.topRightPoint.x-_cornerPoint.topLeftPoint.x, height_1));
CGContextFillPath(ctx);
// 横二
CGContextAddRect(ctx, CGRectMake((int)_cornerPoint.topLeftPoint.x, (int)(_cornerPoint.bottomLeftPoint.y-(_cornerPoint.bottomLeftPoint.y-_cornerPoint.topLeftPoint.y)/3), _cornerPoint.topRightPoint.x-_cornerPoint.topLeftPoint.x, height_1));
CGContextFillPath(ctx);
// 竖一
CGContextAddRect(ctx, CGRectMake((int)(_cornerPoint.topRightPoint.x-(_cornerPoint.topRightPoint.x-_cornerPoint.topLeftPoint.x)/3*2), (int)_cornerPoint.topRightPoint.y, height_1, _cornerPoint.bottomLeftPoint.y-_cornerPoint.topLeftPoint.y));
CGContextFillPath(ctx);
// 竖二
CGContextAddRect(ctx, CGRectMake((int)(_cornerPoint.topRightPoint.x-(_cornerPoint.topRightPoint.x-_cornerPoint.topLeftPoint.x)/3), (int)_cornerPoint.topRightPoint.y, height_1, _cornerPoint.bottomLeftPoint.y-_cornerPoint.topLeftPoint.y));
CGContextFillPath(ctx);
}
这样就画出了控件,不过还不能用。想要使用它,得处理“触摸”方法:
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event;
- (void)cancelTrackingWithEvent:(UIEvent *)event;
自定义控件之所以能够与用户交互,全靠这四个方法。这些方法用于处理比较复杂的交互逻辑,通过它们获取用户在屏幕上触摸和移动时的坐标,根据这些坐标,在drawRect
方法中根据这些坐标重绘控件样式。
在- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
中判断用户的触摸区域是中间还是边角,如果是中间,接下来应该移动剪裁框,如果是边角,则应该伸缩裁剪框;
在- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
中计算拉伸或移动的距离,记录下必要的参数,调用- (void)setNeedsDisplay
,通知控件进行重绘;
在- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
里回调代理方法,传递截图框的frame,最后还原参数,别忘了- (void)cancelTrackingWithEvent:(UIEvent *)event
中也要还原参数。
网友评论