iOS:iOS开发系列–打造自己的“美图秀秀”(中)
來(lái)源:?KenshinCui ??
鏈接:http://www.cnblogs.com/kenshincui/p/3959951.html
其他狀態(tài)設(shè)置
常用的圖形上下文狀態(tài)設(shè)置上面基本都用到了,我們不再一一解釋,這里著重說(shuō)一下疊加模式和填充模式,初學(xué)者對(duì)于這兩個(gè)狀態(tài)設(shè)置往往容易產(chǎn)生疑惑。
?
疊加模式
使用Quartz 2D繪圖時(shí)后面繪制的圖像會(huì)覆蓋前面的,默認(rèn)情況下如果前面的被覆蓋后將看不到后面的內(nèi)容,但是有時(shí)候這個(gè)結(jié)果并不是我們想要的,因此在Quartz 2D中提供了填充模式供開(kāi)發(fā)者配置調(diào)整。由于填充模式類(lèi)別特別多,因此下面以一個(gè)例子來(lái)說(shuō)明:
-(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); }運(yùn)行效果
?
相信大家對(duì)比代碼和顯示效果并不難發(fā)現(xiàn)每種疊加的效果。例子中只是使用UIKit的封裝方法進(jìn)行疊加模式設(shè)置,更一般的方法當(dāng)然是使用CGContextSetBlendMode(CGContextRef context, CGBlendMode mode)方法進(jìn)行設(shè)置。
?
填充模式
?前面的示例中已經(jīng)演示過(guò)純色填充、漸變填充,而有時(shí)我們需要按一定的自定義樣式進(jìn)行填充,這種方式有點(diǎn)類(lèi)似于貼瓷磚的方式。我們知道如果家里貼地板或瓷磚時(shí),通常我們會(huì)先選擇一種瓷磚樣式,根據(jù)房間面積我們購(gòu)買(mǎi)不同量的瓷磚。但是不管買(mǎi)多少,這些瓷磚的樣式都是一模一樣的。填充模式就是為了達(dá)到這種效果而產(chǎn)生的:我們只需要繪制一個(gè)瓷磚的樣式,然后讓程序自動(dòng)調(diào)用這種樣式填充指定大小的區(qū)域。
?Quartz 2D支持兩種填充模式:有顏色填充和無(wú)顏色填充。兩種模式使用起來(lái)區(qū)別很小,有顏色填充就是在繪制瓷磚時(shí)就指定顏色,在調(diào)用填充時(shí)就不用再指定瓷磚顏色;無(wú)顏色填充模式就是繪制瓷磚時(shí)不用指定任何顏色,在調(diào)用填充時(shí)再指定具體填充顏色。相比較無(wú)顏色填充模式而言,有顏色填充模式更加的靈活,推薦使用。
?
下面我們具體看一下如何按指定模式進(jìn)行圖形填充:
?1.在使用填充模式時(shí)首先要構(gòu)建一個(gè)符合CGPatternDrawPatternCallback簽名的方法,這個(gè)方法專(zhuān)門(mén)用來(lái)創(chuàng)建“瓷磚”。注意:如果使用有顏色填充模式,需要設(shè)置填充色。例如我們定義一個(gè)方法drawTile繪制以下瓷磚(有顏色填充):
?
2.接著需要指定一個(gè)填充的顏色空間,這個(gè)顏色空間跟前面繪制漸變的顏色空間不太一樣,前面創(chuàng)建漸變使用的顏色空間是設(shè)備無(wú)關(guān)的,我們需要基于這個(gè)顏色空間創(chuàng)建一個(gè)顏色空間專(zhuān)門(mén)用于填充(注意對(duì)于有顏色填充創(chuàng)建填充顏色空間參數(shù)為NULL,不用基于設(shè)備無(wú)關(guān)的顏色空間創(chuàng)建)。
3.然后我們就可以使用CGPatternCreate方法創(chuàng)建一個(gè)填充模式,創(chuàng)建填充模式時(shí)需要注意其中的參數(shù),在代碼中已經(jīng)做了一一解釋(這里注意對(duì)于有顏色填充模式isColored設(shè)置為true,否則為false)。
4.最后調(diào)用CGContextSetFillPattern方法給圖形上下文指定填充模式(這個(gè)時(shí)候注意最后一個(gè)參數(shù),如果是有顏色填充模式最后一個(gè)參數(shù)為透明度alpa的地址,對(duì)于無(wú)顏色填充模式最后一個(gè)參數(shù)是當(dāng)前填充顏色空間的顏色數(shù)組)。
5.繪制圖形,這里我們繪制一個(gè)矩形。
6.釋放資源。
下面是具體代碼(包含兩種填充模式代碼,可以一一運(yùn)行)
#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){//有顏色填充,這里設(shè)置填充色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{//設(shè)備無(wú)關(guān)的顏色空間 // CGColorSpaceRef rgbSpace= CGColorSpaceCreateDeviceRGB();//模式填充顏色空間,注意對(duì)于有顏色填充模式,這里傳NULLCGColorSpaceRef colorSpace=CGColorSpaceCreatePattern(NULL);//將填充色顏色空間設(shè)置為模式填充的顏色空間 CGContextSetFillColorSpace(context, colorSpace);//填充模式回調(diào)函數(shù)結(jié)構(gòu)體CGPatternCallbacks callback={0,&drawColoredTile,NULL};/*填充模式info://傳遞給callback的參數(shù)bounds:瓷磚大小matrix:形變xStep:瓷磚橫向間距yStep:瓷磚縱向間距tiling:貼磚的方法isClored:繪制的瓷磚是否已經(jīng)指定了顏色(對(duì)于有顏色瓷磚此處指定位true)callbacks:回調(diào)函數(shù)*/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;//注意最后一個(gè)參數(shù)對(duì)于有顏色瓷磚指定為透明度的參數(shù)地址,對(duì)于無(wú)顏色瓷磚則指定當(dāng)前顏色空間對(duì)應(yīng)的顏色數(shù)組CGContextSetFillPattern(context, pattern, &alpha);UIRectFill(CGRectMake(0, 0, 320, 568));// CGColorSpaceRelease(rgbSpace); CGColorSpaceRelease(colorSpace);CGPatternRelease(pattern); }#pragma mark - 無(wú)顏色填充模式 //填充瓷磚的回調(diào)函數(shù)(必須滿(mǎn)足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{//設(shè)備無(wú)關(guān)的顏色空間CGColorSpaceRef rgbSpace= CGColorSpaceCreateDeviceRGB();//模式填充顏色空間CGColorSpaceRef colorSpace=CGColorSpaceCreatePattern(rgbSpace);//將填充色顏色空間設(shè)置為模式填充的顏色空間 CGContextSetFillColorSpace(context, colorSpace);//填充模式回調(diào)函數(shù)結(jié)構(gòu)體CGPatternCallbacks callback={0,&drawTile,NULL};/*填充模式info://傳遞給callback的參數(shù)bounds:瓷磚大小matrix:形變xStep:瓷磚橫向間距yStep:瓷磚縱向間距tiling:貼磚的方法(瓷磚擺放的方式)isClored:繪制的瓷磚是否已經(jīng)指定了顏色(對(duì)于無(wú)顏色瓷磚此處指定位false)callbacks:回調(diào)函數(shù)*/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};//注意最后一個(gè)參數(shù)對(duì)于無(wú)顏色填充模式指定為當(dāng)前顏色空間顏色數(shù)據(jù) CGContextSetFillPattern(context, pattern, components);// CGContextSetStrokePattern(context, pattern, components);UIRectFill(CGRectMake(0, 0, 320, 568));CGColorSpaceRelease(rgbSpace);CGColorSpaceRelease(colorSpace);CGPatternRelease(pattern); } @end這里強(qiáng)調(diào)一點(diǎn),在drawTile回調(diào)方法中不要使用UIKit封裝方法進(jìn)行圖形繪制(例如UIRectFill等),由于這個(gè)方法由Core Graphics內(nèi)部調(diào)用,而Core Graphics考慮到跨平臺(tái)問(wèn)題,內(nèi)部是不允許調(diào)用UIKit方法的。
?
上下文變換
我們知道在UIKit開(kāi)發(fā)中UIView有一個(gè)transform屬性用于控件的形變,其實(shí)在繪圖中我們也經(jīng)常用到圖形形變,這個(gè)時(shí)候可以借助圖形上下文的形變方法來(lái)完成。在弄清形變之前我們要清楚圖形上下文的坐標(biāo)原點(diǎn),因?yàn)闊o(wú)論是位移還是旋轉(zhuǎn)都是相對(duì)于坐標(biāo)原點(diǎn)進(jìn)行的。其實(shí)Quartz 2D的坐標(biāo)系同UIKit并不一樣,它的坐標(biāo)原點(diǎn)在屏幕左下方,但是為了統(tǒng)一編程方式,UIKit對(duì)其進(jìn)行了轉(zhuǎn)換,坐標(biāo)原點(diǎn)統(tǒng)一在屏幕左上角。注意在設(shè)置圖形上下文形變之前一定要注意保存上下文的初始狀態(tài),在使用完之后進(jìn)行恢復(fù)。否則在處理多個(gè)圖形形變的時(shí)候很容易弄不清楚到底是基于怎樣的坐標(biāo)系進(jìn)行繪圖,容易找不到原點(diǎn)(做過(guò)html5 canvas繪圖的朋友對(duì)這一點(diǎn)應(yīng)該很熟悉,在html5中繪圖也經(jīng)常進(jìn)行狀態(tài)保存和恢復(fù))。下面通過(guò)一個(gè)圖片的變換演示一下圖形上下文的形變(其他圖形也是一樣的,就不再演示):
#import "KCView2.h"@implementation KCView2-(void)drawRect:(CGRect)rect{CGContextRef context=UIGraphicsGetCurrentContext();[self drawImage:context]; }#pragma mark 圖形上下文形變 -(void)drawImage:(CGContextRef)context{//保存初始狀態(tài) CGContextSaveGState(context);//形變第一步:圖形上下文向右平移40CGContextTranslateCTM(context, 100, 0);//形變第二步:縮放0.8CGContextScaleCTM(context, 0.8, 0.8);//形變第三步:旋轉(zhuǎn)CGContextRotateCTM(context, M_PI_4/4);UIImage *image=[UIImage imageNamed:@"photo1.jpg"];[image drawInRect:CGRectMake(0, 50, 240, 300)];//恢復(fù)到初始狀態(tài) CGContextRestoreGState(context); }@end最終運(yùn)行效果見(jiàn)第四幅截圖,下圖描繪出了整個(gè)程序的運(yùn)行過(guò)程(移動(dòng)->縮放->旋轉(zhuǎn)):
?
擴(kuò)展–使用Core Graphics繪制圖像?
在前面基本繪圖部分,繪制圖像時(shí)使用了UIKit中封裝的方法進(jìn)行了圖像繪制,我們不妨看一下使用Quartz 2D內(nèi)置方法繪制是什么效果。
-(void)drawImage2:(CGContextRef)context{UIImage *image=[UIImage imageNamed:@"image2.jpg"];//圖像繪制CGRect rect= CGRectMake(10, 50, 300, 450);CGContextDrawImage(context, rect, image.CGImage); }運(yùn)行效果:
?
看起來(lái)整個(gè)圖像是倒過(guò)來(lái)的,原因正是前面說(shuō)的:在Core Graphics中坐標(biāo)系的y軸正方向是向上的,坐標(biāo)原點(diǎn)在屏幕左下角,y軸方向剛好和UIKit中y軸方向相反。而使用UIKit進(jìn)行繪圖之所以沒(méi)有問(wèn)題是因?yàn)閁IKit中進(jìn)行了處理,事實(shí)上對(duì)于其他圖形即使使用Core Graphics繪制也沒(méi)有問(wèn)題,因?yàn)閁IKit統(tǒng)一了編程方式。但是使用Core Graphics中內(nèi)置方法繪制圖像是存在這種問(wèn)題的,如何解決呢?
?
其實(shí)圖形上下文只要沿著x軸旋轉(zhuǎn)180度,然后向上平移適當(dāng)?shù)母叨燃纯?#xff08;但是注意不要沿著z軸旋轉(zhuǎn),這樣得不到想要的結(jié)果)。可是通過(guò)前面介紹的CGContextRotateCTM方法只能通過(guò)沿著z軸旋轉(zhuǎn),此時(shí)不妨使用另外一種方法,那就是在y軸方向縮放-1,同樣可以達(dá)到想要的效果:
-(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相當(dāng)于沿著x張旋轉(zhuǎn)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:中繪制的圖形會(huì)在控件顯示的時(shí)候調(diào)用(而且顯示時(shí)會(huì)重繪所有圖形),有時(shí)候我們希望繪制內(nèi)容的顯示是實(shí)時(shí)的,此時(shí)我們就需要調(diào)用繪圖方法重新繪制,但是在iOS開(kāi)發(fā)中不允許開(kāi)發(fā)者直接調(diào)用drawRect:方法,刷新繪制內(nèi)容需要調(diào)用setNeedsDisplay方法。下面以一個(gè)調(diào)整字體大小的界面演示一下視圖的刷新。
#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:@"%@號(hào)字體",_fontSize[row] ]; } -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{_contentView.fontSize=[[_fontSize objectAtIndex:row] intValue];//刷新視圖 [_contentView setNeedsDisplay]; } @end?
轉(zhuǎn)載于:https://www.cnblogs.com/XYQ-208910/p/5291233.html
總結(jié)
以上是生活随笔為你收集整理的iOS:iOS开发系列–打造自己的“美图秀秀”(中)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 微pe工具箱 系统安装教程_装系统必备
- 下一篇: 利用NodeJs实现图片提取文字