iOS:iOS开发系列–打造自己的“美图秀秀”(中)
來源:?KenshinCui ??
鏈接:http://www.cnblogs.com/kenshincui/p/3959951.html
其他狀態設置
常用的圖形上下文狀態設置上面基本都用到了,我們不再一一解釋,這里著重說一下疊加模式和填充模式,初學者對于這兩個狀態設置往往容易產生疑惑。
?
疊加模式
使用Quartz 2D繪圖時后面繪制的圖像會覆蓋前面的,默認情況下如果前面的被覆蓋后將看不到后面的內容,但是有時候這個結果并不是我們想要的,因此在Quartz 2D中提供了填充模式供開發者配置調整。由于填充模式類別特別多,因此下面以一個例子來說明:
-(void)drawRectByUIKitWithContext2:(CGContextRef)context{CGRect rect= CGRectMake(0, 130.0, 320.0, 50.0);CGRect rect1= CGRectMake(0, 390.0, 320.0, 50.0);CGRect rect2=CGRectMake(20, 50.0, 10.0, 250.0);CGRect rect3=CGRectMake(40.0, 50.0, 10.0, 250.0);CGRect rect4=CGRectMake(60.0, 50.0, 10.0, 250.0);CGRect rect5=CGRectMake(80.0, 50.0, 10.0, 250.0);CGRect rect6=CGRectMake(100.0, 50.0, 10.0, 250.0);CGRect rect7=CGRectMake(120.0, 50.0, 10.0, 250.0);CGRect rect8=CGRectMake(140.0, 50.0, 10.0, 250.0);CGRect rect9=CGRectMake(160.0, 50.0, 10.0, 250.0);CGRect rect10=CGRectMake(180.0, 50.0, 10.0, 250.0);CGRect rect11=CGRectMake(200.0, 50.0, 10.0, 250.0);CGRect rect12=CGRectMake(220.0, 50.0, 10.0, 250.0);CGRect rect13=CGRectMake(240.0, 50.0, 10.0, 250.0);CGRect rect14=CGRectMake(260.0, 50.0, 10.0, 250.0);CGRect rect15=CGRectMake(280.0, 50.0, 10.0, 250.0);CGRect rect16=CGRectMake(30.0, 310.0, 10.0, 250.0);CGRect rect17=CGRectMake(50.0, 310.0, 10.0, 250.0);CGRect rect18=CGRectMake(70.0, 310.0, 10.0, 250.0);CGRect rect19=CGRectMake(90.0, 310.0, 10.0, 250.0);CGRect rect20=CGRectMake(110.0, 310.0, 10.0, 250.0);CGRect rect21=CGRectMake(130.0, 310.0, 10.0, 250.0);CGRect rect22=CGRectMake(150.0, 310.0, 10.0, 250.0);CGRect rect23=CGRectMake(170.0, 310.0, 10.0, 250.0);CGRect rect24=CGRectMake(190.0, 310.0, 10.0, 250.0);CGRect rect25=CGRectMake(210.0, 310.0, 10.0, 250.0);CGRect rect26=CGRectMake(230.0, 310.0, 10.0, 250.0);CGRect rect27=CGRectMake(250.0, 310.0, 10.0, 250.0);CGRect rect28=CGRectMake(270.0, 310.0, 10.0, 250.0);CGRect rect29=CGRectMake(290.0, 310.0, 10.0, 250.0);[[UIColor yellowColor]set];UIRectFill(rect);[[UIColor greenColor]setFill];UIRectFill(rect1);[[UIColor redColor]setFill];UIRectFillUsingBlendMode(rect2, kCGBlendModeClear);UIRectFillUsingBlendMode(rect3, kCGBlendModeColor);UIRectFillUsingBlendMode(rect4, kCGBlendModeColorBurn);UIRectFillUsingBlendMode(rect5, kCGBlendModeColorDodge);UIRectFillUsingBlendMode(rect6, kCGBlendModeCopy);UIRectFillUsingBlendMode(rect7, kCGBlendModeDarken);UIRectFillUsingBlendMode(rect8, kCGBlendModeDestinationAtop);UIRectFillUsingBlendMode(rect9, kCGBlendModeDestinationIn);UIRectFillUsingBlendMode(rect10, kCGBlendModeDestinationOut);UIRectFillUsingBlendMode(rect11, kCGBlendModeDestinationOver);UIRectFillUsingBlendMode(rect12, kCGBlendModeDifference);UIRectFillUsingBlendMode(rect13, kCGBlendModeExclusion);UIRectFillUsingBlendMode(rect14, kCGBlendModeHardLight);UIRectFillUsingBlendMode(rect15, kCGBlendModeHue);UIRectFillUsingBlendMode(rect16, kCGBlendModeLighten);UIRectFillUsingBlendMode(rect17, kCGBlendModeLuminosity);UIRectFillUsingBlendMode(rect18, kCGBlendModeMultiply);UIRectFillUsingBlendMode(rect19, kCGBlendModeNormal);UIRectFillUsingBlendMode(rect20, kCGBlendModeOverlay);UIRectFillUsingBlendMode(rect21, kCGBlendModePlusDarker);UIRectFillUsingBlendMode(rect22, kCGBlendModePlusLighter);UIRectFillUsingBlendMode(rect23, kCGBlendModeSaturation);UIRectFillUsingBlendMode(rect24, kCGBlendModeScreen);UIRectFillUsingBlendMode(rect25, kCGBlendModeSoftLight);UIRectFillUsingBlendMode(rect26, kCGBlendModeSourceAtop);UIRectFillUsingBlendMode(rect27, kCGBlendModeSourceIn);UIRectFillUsingBlendMode(rect28, kCGBlendModeSourceOut);UIRectFillUsingBlendMode(rect29, kCGBlendModeXOR); }運行效果
?
相信大家對比代碼和顯示效果并不難發現每種疊加的效果。例子中只是使用UIKit的封裝方法進行疊加模式設置,更一般的方法當然是使用CGContextSetBlendMode(CGContextRef context, CGBlendMode mode)方法進行設置。
?
填充模式
?前面的示例中已經演示過純色填充、漸變填充,而有時我們需要按一定的自定義樣式進行填充,這種方式有點類似于貼瓷磚的方式。我們知道如果家里貼地板或瓷磚時,通常我們會先選擇一種瓷磚樣式,根據房間面積我們購買不同量的瓷磚。但是不管買多少,這些瓷磚的樣式都是一模一樣的。填充模式就是為了達到這種效果而產生的:我們只需要繪制一個瓷磚的樣式,然后讓程序自動調用這種樣式填充指定大小的區域。
?Quartz 2D支持兩種填充模式:有顏色填充和無顏色填充。兩種模式使用起來區別很小,有顏色填充就是在繪制瓷磚時就指定顏色,在調用填充時就不用再指定瓷磚顏色;無顏色填充模式就是繪制瓷磚時不用指定任何顏色,在調用填充時再指定具體填充顏色。相比較無顏色填充模式而言,有顏色填充模式更加的靈活,推薦使用。
?
下面我們具體看一下如何按指定模式進行圖形填充:
?1.在使用填充模式時首先要構建一個符合CGPatternDrawPatternCallback簽名的方法,這個方法專門用來創建“瓷磚”。注意:如果使用有顏色填充模式,需要設置填充色。例如我們定義一個方法drawTile繪制以下瓷磚(有顏色填充):
?
2.接著需要指定一個填充的顏色空間,這個顏色空間跟前面繪制漸變的顏色空間不太一樣,前面創建漸變使用的顏色空間是設備無關的,我們需要基于這個顏色空間創建一個顏色空間專門用于填充(注意對于有顏色填充創建填充顏色空間參數為NULL,不用基于設備無關的顏色空間創建)。
3.然后我們就可以使用CGPatternCreate方法創建一個填充模式,創建填充模式時需要注意其中的參數,在代碼中已經做了一一解釋(這里注意對于有顏色填充模式isColored設置為true,否則為false)。
4.最后調用CGContextSetFillPattern方法給圖形上下文指定填充模式(這個時候注意最后一個參數,如果是有顏色填充模式最后一個參數為透明度alpa的地址,對于無顏色填充模式最后一個參數是當前填充顏色空間的顏色數組)。
5.繪制圖形,這里我們繪制一個矩形。
6.釋放資源。
下面是具體代碼(包含兩種填充模式代碼,可以一一運行)
#import "KCView.h" #define TILE_SIZE 20@implementation KCView-(void)drawRect:(CGRect)rect{CGContextRef context=UIGraphicsGetCurrentContext();[self drawBackgroundWithColoredPattern:context]; // [self drawBackgroundWithPattern:context]; }#pragma mark - 有顏色填充模式 void drawColoredTile(void *info,CGContextRef context){//有顏色填充,這里設置填充色CGContextSetRGBFillColor(context, 254.0/255.0, 52.0/255.0, 90.0/255.0, 1);CGContextFillRect(context, CGRectMake(0, 0, TILE_SIZE, TILE_SIZE));CGContextFillRect(context, CGRectMake(TILE_SIZE, TILE_SIZE, TILE_SIZE, TILE_SIZE)); } -(void)drawBackgroundWithColoredPattern:(CGContextRef)context{//設備無關的顏色空間 // CGColorSpaceRef rgbSpace= CGColorSpaceCreateDeviceRGB();//模式填充顏色空間,注意對于有顏色填充模式,這里傳NULLCGColorSpaceRef colorSpace=CGColorSpaceCreatePattern(NULL);//將填充色顏色空間設置為模式填充的顏色空間 CGContextSetFillColorSpace(context, colorSpace);//填充模式回調函數結構體CGPatternCallbacks callback={0,&drawColoredTile,NULL};/*填充模式info://傳遞給callback的參數bounds:瓷磚大小matrix:形變xStep:瓷磚橫向間距yStep:瓷磚縱向間距tiling:貼磚的方法isClored:繪制的瓷磚是否已經指定了顏色(對于有顏色瓷磚此處指定位true)callbacks:回調函數*/CGPatternRef pattern=CGPatternCreate(NULL, CGRectMake(0, 0, 2*TILE_SIZE, 2*TILE_SIZE), CGAffineTransformIdentity,2*TILE_SIZE+ 5,2*TILE_SIZE+ 5, kCGPatternTilingNoDistortion, true, &callback);CGFloat alpha=1;//注意最后一個參數對于有顏色瓷磚指定為透明度的參數地址,對于無顏色瓷磚則指定當前顏色空間對應的顏色數組CGContextSetFillPattern(context, pattern, &alpha);UIRectFill(CGRectMake(0, 0, 320, 568));// CGColorSpaceRelease(rgbSpace); CGColorSpaceRelease(colorSpace);CGPatternRelease(pattern); }#pragma mark - 無顏色填充模式 //填充瓷磚的回調函數(必須滿足CGPatternCallbacks簽名) void drawTile(void *info,CGContextRef context){CGContextFillRect(context, CGRectMake(0, 0, TILE_SIZE, TILE_SIZE));CGContextFillRect(context, CGRectMake(TILE_SIZE, TILE_SIZE, TILE_SIZE, TILE_SIZE)); } -(void)drawBackgroundWithPattern:(CGContextRef)context{//設備無關的顏色空間CGColorSpaceRef rgbSpace= CGColorSpaceCreateDeviceRGB();//模式填充顏色空間CGColorSpaceRef colorSpace=CGColorSpaceCreatePattern(rgbSpace);//將填充色顏色空間設置為模式填充的顏色空間 CGContextSetFillColorSpace(context, colorSpace);//填充模式回調函數結構體CGPatternCallbacks callback={0,&drawTile,NULL};/*填充模式info://傳遞給callback的參數bounds:瓷磚大小matrix:形變xStep:瓷磚橫向間距yStep:瓷磚縱向間距tiling:貼磚的方法(瓷磚擺放的方式)isClored:繪制的瓷磚是否已經指定了顏色(對于無顏色瓷磚此處指定位false)callbacks:回調函數*/CGPatternRef pattern=CGPatternCreate(NULL, CGRectMake(0, 0, 2*TILE_SIZE, 2*TILE_SIZE), CGAffineTransformIdentity,2*TILE_SIZE+ 5,2*TILE_SIZE+ 5, kCGPatternTilingNoDistortion, false, &callback);CGFloat components[]={254.0/255.0,52.0/255.0,90.0/255.0,1.0};//注意最后一個參數對于無顏色填充模式指定為當前顏色空間顏色數據 CGContextSetFillPattern(context, pattern, components);// CGContextSetStrokePattern(context, pattern, components);UIRectFill(CGRectMake(0, 0, 320, 568));CGColorSpaceRelease(rgbSpace);CGColorSpaceRelease(colorSpace);CGPatternRelease(pattern); } @end這里強調一點,在drawTile回調方法中不要使用UIKit封裝方法進行圖形繪制(例如UIRectFill等),由于這個方法由Core Graphics內部調用,而Core Graphics考慮到跨平臺問題,內部是不允許調用UIKit方法的。
?
上下文變換
我們知道在UIKit開發中UIView有一個transform屬性用于控件的形變,其實在繪圖中我們也經常用到圖形形變,這個時候可以借助圖形上下文的形變方法來完成。在弄清形變之前我們要清楚圖形上下文的坐標原點,因為無論是位移還是旋轉都是相對于坐標原點進行的。其實Quartz 2D的坐標系同UIKit并不一樣,它的坐標原點在屏幕左下方,但是為了統一編程方式,UIKit對其進行了轉換,坐標原點統一在屏幕左上角。注意在設置圖形上下文形變之前一定要注意保存上下文的初始狀態,在使用完之后進行恢復。否則在處理多個圖形形變的時候很容易弄不清楚到底是基于怎樣的坐標系進行繪圖,容易找不到原點(做過html5 canvas繪圖的朋友對這一點應該很熟悉,在html5中繪圖也經常進行狀態保存和恢復)。下面通過一個圖片的變換演示一下圖形上下文的形變(其他圖形也是一樣的,就不再演示):
#import "KCView2.h"@implementation KCView2-(void)drawRect:(CGRect)rect{CGContextRef context=UIGraphicsGetCurrentContext();[self drawImage:context]; }#pragma mark 圖形上下文形變 -(void)drawImage:(CGContextRef)context{//保存初始狀態 CGContextSaveGState(context);//形變第一步:圖形上下文向右平移40CGContextTranslateCTM(context, 100, 0);//形變第二步:縮放0.8CGContextScaleCTM(context, 0.8, 0.8);//形變第三步:旋轉CGContextRotateCTM(context, M_PI_4/4);UIImage *image=[UIImage imageNamed:@"photo1.jpg"];[image drawInRect:CGRectMake(0, 50, 240, 300)];//恢復到初始狀態 CGContextRestoreGState(context); }@end最終運行效果見第四幅截圖,下圖描繪出了整個程序的運行過程(移動->縮放->旋轉):
?
擴展–使用Core Graphics繪制圖像?
在前面基本繪圖部分,繪制圖像時使用了UIKit中封裝的方法進行了圖像繪制,我們不妨看一下使用Quartz 2D內置方法繪制是什么效果。
-(void)drawImage2:(CGContextRef)context{UIImage *image=[UIImage imageNamed:@"image2.jpg"];//圖像繪制CGRect rect= CGRectMake(10, 50, 300, 450);CGContextDrawImage(context, rect, image.CGImage); }運行效果:
?
看起來整個圖像是倒過來的,原因正是前面說的:在Core Graphics中坐標系的y軸正方向是向上的,坐標原點在屏幕左下角,y軸方向剛好和UIKit中y軸方向相反。而使用UIKit進行繪圖之所以沒有問題是因為UIKit中進行了處理,事實上對于其他圖形即使使用Core Graphics繪制也沒有問題,因為UIKit統一了編程方式。但是使用Core Graphics中內置方法繪制圖像是存在這種問題的,如何解決呢?
?
其實圖形上下文只要沿著x軸旋轉180度,然后向上平移適當的高度即可(但是注意不要沿著z軸旋轉,這樣得不到想要的結果)。可是通過前面介紹的CGContextRotateCTM方法只能通過沿著z軸旋轉,此時不妨使用另外一種方法,那就是在y軸方向縮放-1,同樣可以達到想要的效果:
-(void)drawImage2:(CGContextRef)context{UIImage *image=[UIImage imageNamed:@"image2.jpg"];CGSize size=[UIScreen mainScreen].bounds.size;CGContextSaveGState(context);CGFloat height=450,y=50;//上下文形變CGContextScaleCTM(context, 1.0, -1.0);//在y軸縮放-1相當于沿著x張旋轉180CGContextTranslateCTM(context, 0, -(size.height-(size.height-2*y-height)));//向上平移//圖像繪制CGRect rect= CGRectMake(10, y, 300, height);CGContextDrawImage(context, rect, image.CGImage);CGContextRestoreGState(context); }視圖刷新
在UIView的drawRect:中繪制的圖形會在控件顯示的時候調用(而且顯示時會重繪所有圖形),有時候我們希望繪制內容的顯示是實時的,此時我們就需要調用繪圖方法重新繪制,但是在iOS開發中不允許開發者直接調用drawRect:方法,刷新繪制內容需要調用setNeedsDisplay方法。下面以一個調整字體大小的界面演示一下視圖的刷新。
#import <UIKit/UIKit.h>@interface KCView : UIView@property (nonatomic,copy) NSString *title;@property (nonatomic,assign) CGFloat fontSize;@endKCView.m// KCView.m // RefreshView // // Created by Kenshin Cui on 14-3-17. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "KCView.h"@implementation KCView-(void)drawRect:(CGRect)rect{NSString *str=_title;UIFont *font=[UIFont fontWithName:@"Marker Felt" size:_fontSize];UIColor *foreignColor=[UIColor redColor];[str drawInRect:CGRectMake(100, 120, 300, 200) withAttributes:@{NSFontAttributeName:font,NSForegroundColorAttributeName:foreignColor}]; }@endKCMainViewController.m// KCMainViewController.m // RefreshView // // Created by Kenshin Cui on 14-3-17. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" #import "KCView.h"@interface KCMainViewController (){KCView *_contentView;NSArray *_fontSize; }@end@implementation KCMainViewController- (void)viewDidLoad {[super viewDidLoad];[self initLayout];[self addPickerView]; }-(void)initLayout{_fontSize=@[@15,@18,@20,@22,@25,@28,@30,@32,@35,@40];_contentView=[[KCView alloc]initWithFrame:CGRectMake(0, 0, 320, 300)];_contentView.backgroundColor=[UIColor whiteColor];_contentView.title=@"Hello world!";_contentView.fontSize=[_fontSize[0] intValue];[self.view addSubview:_contentView]; }-(void)addPickerView{UIPickerView *picker=[[UIPickerView alloc]initWithFrame:CGRectMake(0, 300, 320, 268)];picker.dataSource=self;picker.delegate=self;[self.view addSubview:picker]; }-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{return 1; } -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{return _fontSize.count; }-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{return [NSString stringWithFormat:@"%@號字體",_fontSize[row] ]; } -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{_contentView.fontSize=[[_fontSize objectAtIndex:row] intValue];//刷新視圖 [_contentView setNeedsDisplay]; } @end?
轉載于:https://www.cnblogs.com/XYQ-208910/p/5291233.html
總結
以上是生活随笔為你收集整理的iOS:iOS开发系列–打造自己的“美图秀秀”(中)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微pe工具箱 系统安装教程_装系统必备
- 下一篇: 利用NodeJs实现图片提取文字