博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS 2D绘图详解(Quartz 2D)之阴影和渐变(Shadow,Gradient)
阅读量:6528 次
发布时间:2019-06-24

本文共 6087 字,大约阅读时间需要 20 分钟。

前言:这个系列写道这里已经是第五篇了,本文会介绍下阴影和渐变的基础知识,以及一些基本的Demo Code展示,应该还会有两篇,介绍下Bitmap绘制以及Pattern等知识。


Shadow

shadow(阴影)的目的是为了使UI更具有立体感,如图

shadow主要有三个影响因素

  • x off-set 决定阴影沿着x的偏移量
  • y off-set 决定阴影沿着y的偏移量
  • blur value 决定了阴影的边缘区域是不是模糊的

其中不同的blur效果如图

注意

Shadow也是绘制状态相关的,意味着如果仅仅要绘制一个subpath的shadow,要注意save和restore状态。

相关函数

CGContextSetShadowCGContextSetShadowWithColor//位移区别是设置了阴影颜色

参数

  • context 绘制画板
  • offset 阴影偏移量,参考context的坐标系
  • blur 非负数,决定阴影的模糊程度
    示例代码
- (void)drawRect:(CGRect)rect {    CGContextRef context = UIGraphicsGetCurrentContext();    CGContextAddArc(context,40, 40, 20, 0,M_2_PI,0); CGContextSetLineCap(context, kCGLineCapRound); CGContextSetLineWidth(context,3.0); CGContextSetShadow(context,CGSizeMake(4.0, 4.0),1.0); CGContextStrokePath(context); } -(instancetype)initWithFrame:(CGRect)frame{ if(self = [super initWithFrame:frame]){ self.opaque = NO; self.layer.borderColor = [UIColor lightGrayColor].CGColor; self.layer.borderWidth = 1.0; } return self; }

 

效果

关于状态保存会在最后和gradient一起再讲解一次


Gradient

渐变无非就是从一种颜色逐渐变换到另一种颜色,quart提供了两种渐变模型。

  • axial gradient,线性渐变,使用的时候设置好两个顶点的颜色(也可以设置中间过渡色)

    例如
    只设置两个颜色,和顶点
    设置中间过渡色

  • radial gradient

    这种模式的渐变允许,一个圆到另一个圆的渐变
    一个点到一个圆的渐变

注意,可以对渐变结束或者开始的额外区域使用指定颜色填充

,效果

通过这两种渐变的嵌套使用,Quartz 2D能够绘制出非常漂亮的图形


渐变的两种绘制模型

  • CGShading - 使用这种数据类型需要自己定义CFFunction来计算每一个点的渐变颜色,较为复杂,但是能够更灵活的绘制。
  • CGGradient- 使用这种数据类型只需要制定两个顶点的颜色,以及绘制模式,其余的Quartz会给绘制,但是渐变的数学模型不灵活。

CGGradient的例子

使用步骤

  • 创建一个CGGradient对象,指定颜色域(一般就是RGB),指定颜色变化的数组,指定对应颜色位置的数组,指定每个数组数据的个数
  • 用CGContextDrawLinearGradient或者CGContextDrawRadialGradient绘制
  • 释放CGGradient对象

代码

CGContextRef context = UIGraphicsGetCurrentContext();    //用CGGradient绘制    CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();    size_t num_of_locations = 2;    CGFloat locations[2] = {
0.0,1.0}; CGFloat components[8] = { 1.0, 0.0, 0.0, 1.0, // 红色 0.0, 1.0, 0.0, 1.0};//绿色 CGGradientRef gradient = CGGradientCreateWithColorComponents(deviceRGB, components, locations,num_of_locations); CGPoint startPoint = CGPointMake(0, 0); CGPoint endPoint = CGPointMake(100, 100); CGContextDrawLinearGradient(context,gradient,startPoint, endPoint,0); CGColorSpaceRelease(deviceRGB); CGGradientRelease(gradient);

 

效果

然后,我们绘制一个RadialGradient,

代码

CGContextRef context = UIGraphicsGetCurrentContext();    //用CGGradient绘制    CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();    size_t num_of_locations = 2;    CGFloat locations[2] = {
0.0,1.0}; CGFloat components[8] = { 1.0, 1.0, 1.0, 1.0, // 白色 0.0, 0.0, 0.0, 1.0};//黑色 CGGradientRef gradient = CGGradientCreateWithColorComponents(deviceRGB, components, locations,num_of_locations); CGPoint startCenter = CGPointMake(30, 30); CGPoint endCenter = CGPointMake(50, 50); CGFloat startRadius = 0.0; CGFloat endRadius = 40.0; CGContextDrawRadialGradient(context,gradient, startCenter,startRadius, endCenter, endRadius, 0); CGColorSpaceRelease(deviceRGB); CGGradientRelease(gradient);

效果


CGShading绘制

使用CGShadingCreateAxial或者CGShadingCreateRadial来创建对象,传入的参数如下

  • Color Space,处理的颜色域,在iOS通畅就是device RGB
  • 开始的点和结束的点
  • 对于 radial gradient要传入开始和结束的半径
  • CGFunction 对象来计算每个点的显示值
  • 一个bool值,来确定是否要填充没有被渐变覆盖的区域

这里面最复杂的就是创建一个CGFunction对象,使用CGFunctionCreate来创建,我们线看看这个函数

CGFunctionRef _Nullable CGFunctionCreate (   void * _Nullable info,   size_t domainDimension,   const CGFloat * _Nullable domain,   size_t rangeDimension,   const CGFloat * _Nullable range, const CGFunctionCallbacks * _Nullable callbacks );

乍一看是不是不想再学了?当然,CGGradient对象足矣满足大部分时候的需求,不过有空的话还是耐心下来看看吧。我们先看看参数

  • info 用来传递到callback的数据,注意,它的生命周期有可能不只是方法的生命周期
  • domainDimension 输入的数量,quart中,就是1
  • domain 一组数据,确定输入的有效间隔。quart中是0到1,0表示开始,1表示结束
  • rangeDimension 输出的数量
  • range 输出的有效间隔
  • callbacks 用来计算的实际方法,格式如下void myCalculateShadingValues (void *info, const CGFloat *in, CGFloat *out)

可能这样讲还是不清楚,看个例子就明白了(例子来自官方文档,我只是翻译过来的)


首先定义callback来计算实际像素值

static void myCalculateShadingValues (void *info,                            const CGFloat *in, CGFloat *out) { CGFloat v; size_t k, components; static const CGFloat c[] = { 1, 0, 0.5, 0 }; components = (size_t)info; v = *in; for (k = 0; k < components -1; k++) *out++ = c[k] * v; *out++ = 1; }

这里的三个参数,函数很简单out的值(r,g,b,a)分别为(in*1,in*0.in*0.5,1)


创建一个CGFunction

static CGFunctionRef myGetFunction (CGColorSpaceRef colorspace) //1 {size_t numComponents;static const CGFloat input_value_range [2] = { 0, 1 }; static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 }; static const CGFunctionCallbacks callbacks = { 0, //2 &myCalculateShadingValues, NULL }; numComponents = 1 + CGColorSpaceGetNumberOfComponents (colorspace); //3 return CGFunctionCreate ((void *) numComponents, 1, input_value_range, numComponents, output_value_ranges, &callbacks); }

其中,每一行分别为

  1. 以colorspace作为参数
  2. 定义callback函数
  3. 计算颜色域中的颜色组建的个数,例如RGB就是三个,然后加一,表示alpha通道

用CGShading绘制Axial Gradient

CGPoint     startPoint,            endPoint;CGFunctionRef myFunctionObject; CGShadingRef myShading; startPoint = CGPointMake(0,0.5); endPoint = CGPointMake(1,0.5); colorspace = CGColorSpaceCreateDeviceRGB(); myFunctionObject = myGetFunction (colorspace); myShading = CGShadingCreateAxial (colorspace, startPoint, endPoint, myFunctionObject, false, false) CGContextDrawShading (myContext, myShading); CGShadingRelease (myShading); CGColorSpaceRelease (colorspace); CGFunctionRelease (myFunctionObject);

 


用CGShading绘制Radial Gradient

原理类似

callback

static void  myCalculateShadingValues (void *info,                                const CGFloat *in, CGFloat *out) { size_t k, components; double frequency[4] = { 55, 220, 110, 0 }; components = (size_t)info; for (k = 0; k < components - 1; k++) *out++ = (1 + sin(*in * frequency[k]))/2; *out++ = 1; // alpha }

 

CGPoint startPoint, endPoint;      CGFloat startRadius, endRadius; startPoint = CGPointMake(0.25,0.3); startRadius = .1; endPoint = CGPointMake(.7,0.7); endRadius = .25; colorspace = CGColorSpaceCreateDeviceRGB(); myShadingFunction = myGetFunction (colorspace); CGShadingCreateRadial (colorspace, startPoint, startRadius, endPoint, endRadius, myShadingFunction, false, false) CGContextDrawShading (myContext, shading); CGShadingRelease (myShading); CGColorSpaceRelease (colorspace); CGFunctionRelease (myFunctionObject);

 

效果

你可能感兴趣的文章
linux下配置网络环境
查看>>
java Windows7 下环境变量设置
查看>>
NBU异构还原Oracle完整备份的一些总结
查看>>
freeBSD安装详细讲解
查看>>
WSFC2016 VM弹性与存储容错
查看>>
文档管理,文本编辑控件TX Text Control .NET for WPF
查看>>
复习 Python 匿名函数 内建函数
查看>>
Security Identifiers | Win SRV2016 SID Change 修改
查看>>
看看来自日本的扫描,做网站需要注意的
查看>>
JDK 1.7+Android SDK+IntelliJ IDEA 13+Genymotion 安卓开发环境部署
查看>>
钓鱼邮件***防范指南
查看>>
session_start()放置位置的不正确引发的ROOT常量 未定义的错误
查看>>
如何设定VDP同时备份的任务数?
查看>>
ipsec的***在企业网中的经典应用
查看>>
过来人谈《去360还是留在百度?》
查看>>
mysql备份工具innobackupex,xtrabackup-2.1安装,参数详解
查看>>
【复制】slave筛选复制之二(create/drop table语句)
查看>>
Movie Store OpenCart 自适应主题模板 ABC-0249
查看>>
mytop-MySQL监控工具
查看>>
RedHat linux YUM本地制作源
查看>>