来源: KenshinCui

链接:http://www.cnblogs.com/kenshincui/p/3959951.html

其他状态设置

常用的图形上下文状态设置上面基本都用到了,我们不再一一解释,这里着重说一下叠加模式和填充模式,初学者对于这两个状态设置往往容易产生疑惑。

叠加模式

使用Quartz 2D绘图时后面绘制的图像会覆盖前面的,默认情况下如果前面的被覆盖后将看不到后面的内容,但是有时候这个结果并不是我们想要的,因此在Quartz 2D中提供了填充模式供开发者配置调整。由于填充模式类别特别多,因此下面以一个例子来说明:

-(void)drawRectByUIKitWithContext2:(CGContextRef)context{
CGRect rect= CGRectMake(, 130.0, 320.0, 50.0);
CGRect rect1= CGRectMake(, 390.0, 320.0, 50.0); CGRect rect2=CGRectMake(, 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, );
CGContextFillRect(context, CGRectMake(, , TILE_SIZE, TILE_SIZE));
CGContextFillRect(context, CGRectMake(TILE_SIZE, TILE_SIZE, TILE_SIZE, TILE_SIZE));
}
-(void)drawBackgroundWithColoredPattern:(CGContextRef)context{
//设备无关的颜色空间
// CGColorSpaceRef rgbSpace= CGColorSpaceCreateDeviceRGB();
//模式填充颜色空间,注意对于有颜色填充模式,这里传NULL
CGColorSpaceRef colorSpace=CGColorSpaceCreatePattern(NULL);
//将填充色颜色空间设置为模式填充的颜色空间
CGContextSetFillColorSpace(context, colorSpace); //填充模式回调函数结构体
CGPatternCallbacks callback={,&drawColoredTile,NULL};
/*填充模式
info://传递给callback的参数
bounds:瓷砖大小
matrix:形变
xStep:瓷砖横向间距
yStep:瓷砖纵向间距
tiling:贴砖的方法
isClored:绘制的瓷砖是否已经指定了颜色(对于有颜色瓷砖此处指定位true)
callbacks:回调函数
*/
CGPatternRef pattern=CGPatternCreate(NULL, CGRectMake(, , *TILE_SIZE, *TILE_SIZE), CGAffineTransformIdentity,*TILE_SIZE+ ,*TILE_SIZE+ , kCGPatternTilingNoDistortion, true, &callback); CGFloat alpha=;
//注意最后一个参数对于有颜色瓷砖指定为透明度的参数地址,对于无颜色瓷砖则指定当前颜色空间对应的颜色数组
CGContextSetFillPattern(context, pattern, &alpha); UIRectFill(CGRectMake(, , , )); // CGColorSpaceRelease(rgbSpace);
CGColorSpaceRelease(colorSpace);
CGPatternRelease(pattern);
} #pragma mark - 无颜色填充模式
//填充瓷砖的回调函数(必须满足CGPatternCallbacks签名)
void drawTile(void *info,CGContextRef context){
CGContextFillRect(context, CGRectMake(, , 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={,&drawTile,NULL};
/*填充模式
info://传递给callback的参数
bounds:瓷砖大小
matrix:形变
xStep:瓷砖横向间距
yStep:瓷砖纵向间距
tiling:贴砖的方法(瓷砖摆放的方式)
isClored:绘制的瓷砖是否已经指定了颜色(对于无颜色瓷砖此处指定位false)
callbacks:回调函数
*/
CGPatternRef pattern=CGPatternCreate(NULL, CGRectMake(, , *TILE_SIZE, *TILE_SIZE), CGAffineTransformIdentity,*TILE_SIZE+ ,*TILE_SIZE+ , 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(, , , )); 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); //形变第一步:图形上下文向右平移40
CGContextTranslateCTM(context, , ); //形变第二步:缩放0.8
CGContextScaleCTM(context, 0.8, 0.8); //形变第三步:旋转
CGContextRotateCTM(context, M_PI_4/); UIImage *image=[UIImage imageNamed:@"photo1.jpg"];
[image drawInRect:CGRectMake(, , , )]; //恢复到初始状态
CGContextRestoreGState(context);
} @end

最终运行效果见第四幅截图,下图描绘出了整个程序的运行过程(移动->缩放->旋转):

扩展–使用Core Graphics绘制图像

在前面基本绘图部分,绘制图像时使用了UIKit中封装的方法进行了图像绘制,我们不妨看一下使用Quartz 2D内置方法绘制是什么效果。

-(void)drawImage2:(CGContextRef)context{
UIImage *image=[UIImage imageNamed:@"image2.jpg"];
//图像绘制
CGRect rect= CGRectMake(, , , );
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=,y=;
//上下文形变
CGContextScaleCTM(context, 1.0, -1.0);//在y轴缩放-1相当于沿着x张旋转180
CGContextTranslateCTM(context, , -(size.height-(size.height-*y-height)));//向上平移
//图像绘制
CGRect rect= CGRectMake(, y, , 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;

@end

KCView.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(, , , ) withAttributes:@{NSFontAttributeName:font,NSForegroundColorAttributeName:foreignColor}];
} @end KCMainViewController.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=@[@,@,@,@,@,@,@,@,@,@];
_contentView=[[KCView alloc]initWithFrame:CGRectMake(, , , )];
_contentView.backgroundColor=[UIColor whiteColor];
_contentView.title=@"Hello world!";
_contentView.fontSize=[_fontSize[] intValue];
[self.view addSubview:_contentView];
} -(void)addPickerView{
UIPickerView *picker=[[UIPickerView alloc]initWithFrame:CGRectMake(, , , )];
picker.dataSource=self;
picker.delegate=self; [self.view addSubview:picker];
} -(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return ;
}
-(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

iOS:iOS开发系列–打造自己的“美图秀秀”(中)的更多相关文章

  1. iOS开发系列--打造自己的“美图秀秀”

    --绘图与滤镜全面解析 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz ...

  2. iOS开发系列--打造自己的“美图秀秀”

    概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz 2D绘制2D图形和Co ...

  3. iOS:iOS开发系列–打造自己的“美图秀秀”(下)

    来源: KenshinCui 链接:http://www.cnblogs.com/kenshincui/p/3959951.html 运行效果: 其他图形上下文 前面我们也说过,Quartz 2D的图 ...

  4. iOS:iOS开发系列–打造自己的“美图秀秀”(上)

    来源: KenshinCui 链接:http://www.cnblogs.com/kenshincui/p/3959951.html 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功 ...

  5. 移动开发在路上-- IOS移动开发系列 多线程二

    最近太忙没太多的时间,忙碌的码农生活空下来一点时间,都会挤出来看一些技术或者咨询的文章,废话不多说,直奔主题. 接着上一次的继续说. 定时器在多线程的使用 NSRunLoop 是线程相关的基础框架的一 ...

  6. Android 快速开发系列 打造万能的ListView GridView 适配器

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38902805 ,本文出自[张鸿洋的博客] 1.概述 相信做Android开发的写 ...

  7. iOS 图片部分模糊,类似于美图秀秀

    代码地址如下:http://www.demodashi.com/demo/14277.html 演示效果 演示效果 代码结构 项目结构截图如下: 该模块的核心源码部分为 MBPartBlurView, ...

  8. 美图秀秀 web开发图片编辑器

    美图秀秀web开发平台 http://open.web.meitu.com/wiki/ 1.环境配置 1.1.设置crossdomain.xml 下载crossdomain.xml文件,把解压出来的c ...

  9. 利用Photos 框架搭建美图秀秀相册选择器

    简介:Photos框架是iOS8.0后推出的一个新的用于对系统相册进行相关操作的,在iOS8.0之前,开发中只能使用AssetsLibrary框架来访问移动设备的图片库.本文中不再对AssetsLib ...

随机推荐

  1. Objective-C字符串处理的函数

    Objective-C字符串处理的函数 NSLog(@"字符串处理"); //获得字符串长度 NSString* str1=@"MAC OS Pro"; NSL ...

  2. connect-falsh的用法

    借鉴博客 http://yunkus.com/connect-flash-usage/

  3. hdu 1065(贪心)

    Wooden Sticks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20938   Accepted: 8872 De ...

  4. Elements in iteration expect to have 'v-bind:key' directives.' 提示错误如何解决?

    在学习vue过程中遇到Elements in iteration expect to have 'v-bind:key' directives.' 这个错误,查阅资料得知Vue 2.2.0+的版本里, ...

  5. AC日记——「SCOI2016」幸运数字 LiBreOJ 2013

    「SCOI2016」幸运数字 思路: 线性基: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 20005 # ...

  6. CSS 规范

    不能写得一手好字是一个遗憾.不能写得一手好看的代码更是一种遗憾.——致青春 1. 为选择器分组时,将单独的选择器单独放在一行. 2. 为了代码的易读性,在每个声明块的左花括号前添加一个空格. 3. 声 ...

  7. 前端读者 | 从一行代码里面学点JavaScript

    本文来自 @张小俊128:链接:http://www.html-js.com/article/A-day-to-learn-from-a-line-of-code-inside-the-JavaScr ...

  8. javascript大神修炼记(2)——运算符

    读者朋友们好,前面我已经大概的了解了Javascript的作用以及一些基本的函数声明与变量声明,今天我们就接着前面的内容讲解,我们就来看一下javscript的逻辑(正序,分支,循环)以及一些简单的运 ...

  9. js判断网络连接情况:navigator.onLine

    <body> <h1 id="text">websong</h1> </body> <script> var text= ...

  10. 2t3ik、ddgs与Linux异常文件下载处理

    异常1: 这样的邮件发生了两周了,烦得很.进入服务器,用top看来下进程. 解决办法 首先 kill 相关PID 进入/tmp/   删除相关文件 rm -rf 2t3ik相关文件 不给相关文件修改权 ...