之前做一些界面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];
}];
}
}