之前做一些界面UI都只是用系统自带的UI控件,比如UILabel、button之类的,没有尝试自己去画一个自定义控件,而自己自定义过的一些控件,也仅仅是出于逻辑交互需求的考虑,这几天正好看了看Quartz2D,准备写点东西分享一下。
Quartz2D绘图的代码步骤
- 一、获得图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext(); - 二、拼接路径(下面代码是搞一条线段)
CGContextMoveToPoint(ctx, 10, 10); CGContextAddLineToPoint(ctx, 100, 100); - 三、绘制路径
CGContextStrokePath(ctx); // CGContextFillPath(ctx);
常用拼接参数
- 新建一个起点
void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y) - 添加新的线段到某个点
void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y) - 添加一个矩形
void CGContextAddRect(CGContextRef c, CGRect rect) - 添加一个椭圆
void CGContextAddEllipseInRect(CGContextRef context, CGRect rect) - 添加一个圆弧
void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
常用绘制路径函数
- Mode参数决定绘制的模式
void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode) - 绘制空心路径
void CGContextStrokePath(CGContextRef c) - 绘制实心路径
void CGContextFillPath(CGContextRef c)
矩阵操作
- 利用矩阵操作,能让绘制到上下文中的所有路径一起发生变化
- 缩放:
void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy) - 旋转:
void CGContextRotateCTM(CGContextRef c, CGFloat angle) - 平移:
void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
- 缩放:
图形上下文栈的操作
- 将当前的上下文copy一份,保存到栈顶(那个栈叫做”图形上下文栈”)
void CGContextSaveGState(CGContextRef c) - 将栈顶的上下文出栈,替换掉当前的上下文
void CGContextRestoreGState(CGContextRef c)
裁剪图片(带圆环)
+ (UIImage *)imageWithClipImage:(UIImage *)image borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)color
{
CGFloat imageWH = image.size.width;
CGFloat border = borderWidth;
CGFloat ovalWH = imageWH + 2 * border;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(ovalWH, ovalWH), NO, 0);
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, ovalWH, ovalWH)];
[color set];
[path fill];
UIBezierPath *clipPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(border, border, imageWH, imageWH)];
[image drawAtPoint:CGPointMake(border, border)];
UIImage *clipImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return clipImage;
}
水印图片
/**
* 水印图片
*
* @param image 图片
* @param textColor 水印文字的颜色
* @param font 水印文字的大小
* @param point 水印文字的起始坐标
* @param text 水印文字的内容
*
* @return 水印图片
*/
+ (UIImage *)imageWithWaterMarkImage:(UIImage *)image textColor:(UIColor *)textColor fontSize:(CGFloat)fontSize drawPoint:(CGPoint)point text:(NSString *)text
{
// size:位图上下文的尺寸(新图片的尺寸)
// opaque: 不透明度 YES:不透明 NO:透明,通常我们一般都弄透明的上下文
// scale:通常不需要缩放上下文,取值为0,表示不缩放
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
// 1.绘制原生的图片
[image drawAtPoint:CGPointZero];
// 2.给原生的图片添加文字
// 创建字典属性
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSForegroundColorAttributeName] = textColor;
dict[NSFontAttributeName] = [UIFont systemFontOfSize:fontSize];
[text drawAtPoint:point withAttributes:dict];
// 3.生成一张图片给我们,从上下文中获取图片
UIImage *imageWater = UIGraphicsGetImageFromCurrentImageContext();
// 4.关闭上下文
UIGraphicsEndImageContext();
return imageWater;
}
图片截取(待完善)
/**
* 这是主要逻辑,即在手势pan里面的逻辑
* @param _startP 起始点
* @param clipView 自定义UIView
*/
- (void)pan:(UIPanGestureRecognizer *)pan
{
CGPoint endA = CGPointZero;
if (pan.state == UIGestureRecognizerStateBegan) { // 一开始拖动的时候
// 获取一开始触摸点
_startP = [pan locationInView:self.view];
}else if(pan.state == UIGestureRecognizerStateChanged){ // 一直拖动
// 获取结束点
endA = [pan locationInView:self.view];
CGFloat w = endA.x - _startP.x;
CGFloat h = endA.y - _startP.y;
// 获取截取范围
CGRect clipRect = CGRectMake(_startP.x, _startP.y, w, h);
// 生成截屏的view
self.clipView.frame = clipRect;
}else if (pan.state == UIGestureRecognizerStateEnded){
// 图片裁剪,生成一张新的图片
// 开启上下文
// 如果不透明,默认超出裁剪区域会变成黑色,通常都是透明
UIGraphicsBeginImageContextWithOptions(_imageV.bounds.size, NO, 0);
// 设置裁剪区域
UIBezierPath *path = [UIBezierPath bezierPathWithRect:_clipView.frame];
[path addClip];
// 获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 把控件上的内容渲染到上下文
[_imageV.layer renderInContext:ctx];
// 生成一张新的图片
_imageV.image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
// 先移除
[_clipView removeFromSuperview];
// 截取的view设置为nil
_clipView = nil;
}
}
图片渐显
/**
* 图片现实增加渐显效果(分类里实现的)
*/
- (void)setFadeImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder {
if ([[QNAFNetworkReachabilityManager sharedManager] networkReachabilityStatus] == AFNetworkReachabilityStatusNotReachable) {
//网络不可用 增加网络判断主要是解决在断网情况下 不显示默认图的问题
[self sd_setImageWithURL:url placeholderImage:placeholder];
}
else{
[self sd_setImageWithURL:url placeholderImage:placeholder options:SDWebImageRetryFailed completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (cacheType == SDImageCacheTypeNone){
CATransition * animation = [CATransition animation];
[animation setDuration:0.35];
[animation setType:kCATransitionFade];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.layer addAnimation:animation forKey:@"transition"];
}
self.image = image ? : placeholder;
[self setNeedsLayout];
}];
}
}