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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/418801.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Validator 使用总结

https://blog.csdn.net/weixin_37509652/article/details/80676693

ubuntu ifconfig只有lo没有ens33的问题

如果ifconfig只显示了lo&#xff0c; ifconfig -a 却正常显示ens33。那么可以按照如下的操作&#xff1a; service network-manager stop rm /var/lib/NetworkManager/NetworkManager.state service network-manager start 即可恢复网络连接

Spring4.0学习笔记(3) —— Spring_Bean之间的关系

1、继承关系 bean-relation.xml <?xml version"1.0" encoding"UTF-8"?> <beansxmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:p"http://www.spring…

tftp ping 不通。无法访问目标主机

在开发板的烧录过程中&#xff0c;我们会使用tftp服务来下载.bin文件到开发板上&#xff0c;但是用网线把电脑和开发板连接起来&#xff0c;开发板ping不通电脑&#xff08;电脑连的是无线网&#xff0c;ping 无线网的ip&#xff09;。但是把无线网关闭后&#xff0c;设置电脑本…

作业3(学习进度表)【第四周】

第四周总结学习成长经历 周数 专业学习目标 专业学习时间 新增代码量 博客发表量 人文方面学习 知识技能总结 第四周 这学期新增了HTML5的课程&#xff0c;对这门课程挺感兴趣的&#xff0c;但是上课比较跟不上老师的节奏&#xff0c;而且基础理论课上的少有些基本…

Springboot@Configuration和@Bean详解

https://www.cnblogs.com/javafucker/p/10148464.html

踩坑记录--VScode编辑不同文件没有及时crtl+s,导致文件修改无效

谷粒商城P43 多次修改路由不生效&#xff0c;原来是修改了路由文件没有crtls保存

移动端去掉按钮点击热区

对于ios系统上的浏览器&#xff0c;如果某处实现了点击事件&#xff0c;则在点击该区域的时候&#xff0c;会有蓝边&#xff0c;而这种蓝边的效果有时候不是我们前端设计人员真正期望的点击效果 所以我们需要考虑将这样的蓝边去掉&#xff0c; .click_elm{ outline:none; -webk…

Java拦截器,过滤器,监听器(三大器)对比

https://blog.csdn.net/baidu_20876831/article/details/80405515

谷粒商城--API三级分类--查询--递归树形结构获取

是先把所有分类信息获取到内存&#xff0c;再递归处理&#xff0c;把分类数据封装成树形结构的数据&#xff0c;返回前台。 用到jdk1.8里面的流式编程和lamda表达式。要想理清这里的逻辑处理&#xff0c;先去把上面那两个东西学习一下。

lintcode: 跳跃游戏 II

跳跃游戏 II 给出一个非负整数数组&#xff0c;你最初定位在数组的第一个位置。 数组中的每个元素代表你在那个位置可以跳跃的最大长度。    你的目标是使用最少的跳跃次数到达数组的最后一个位置。 样例 给出数组A [2,3,1,1,4]&#xff0c;最少到达数组最后一个位置的跳跃…

谷粒商城--API三级分类--网关统一配置跨域

什么是跨域&#xff0c;为什么会有跨域问题的出现 一、什么是同源策略&#xff1f; 1、同源策略/SOP&#xff08;Same origin policy&#xff09;是一种约定&#xff0c;由Netscape公司1995年引入浏览器&#xff0c;它是浏览器最核心也最基本的安全功能&#xff0c;如果缺少了…

nodejs-循环

for循环for(var key in object){consol.log(wor : key);}来自为知笔记(Wiz)转载于:https://www.cnblogs.com/weloveshare/p/5297965.html

Spring Boot缓存注解@Cacheable、@CacheEvict、@CachePut使用

https://blog.csdn.net/dreamhai/article/details/80642010

【转】Xcode 7 真机调试详细步骤

原文网址&#xff1a;http://www.jianshu.com/p/fa5f90b61ad6 文&#xff0f;ldjhust&#xff08;简书作者&#xff09;原文链接&#xff1a;http://www.jianshu.com/p/fa5f90b61ad6著作权归作者所有&#xff0c;转载请联系作者获得授权&#xff0c;并标注“简书作者”。转载&a…

踩坑记录--mybatisplus模糊查询中文时 有数据但 like查不到

排查过程&#xff1a; 先去打印台查看SQL语句 接着输入英文可以查到&#xff0c;输入中文查不到 想到可能是编码原因 百度精准搜----发现最终原因&#xff1a; 原因是application.properties中数据库没有配置&characterEncodingutf-8