iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

时间:2022-09-12 14:38:28

原博地址:http://blog.csdn.net/hello_hwc/article/details/49507881

Shadow

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

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

shadow 主要有三个影响因素

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

其中不同的blur效果的图

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

注意:

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

相关函数

CGContextSetShadow
CGContextSetShadowWithColor//唯一区别是设置了阴影颜色

参数

context 绘制画板

offset阴影偏移量,参考context的坐标系

blur 非负数,决定阴影的模糊程度

示例代码

- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
//填充边框 当然你可以用layer设置
CGContextSetStrokeColorWithColor(context, [UIColor darkGrayColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, rect);
CGContextStrokeRect(context, rect); CGContextAddArc(context, , , , , M_2_PI, );
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 3.0);
CGContextSetShadow(context, CGSizeMake(4.0, 4.0), 1.0);
//CGContextSetShadowWithColor(context, CGSizeMake(4.0, 4.0), 1.0, [UIColor blueColor].CGColor); CGContextStrokePath(context);
}

效果

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)


Gradient 渐变色

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

Quartz提供了两个不透明数据odgago创建渐变:CGShadingRef 和 CGGradientRef.我们可以使用任何一个来创建轴向(axial)或径向(radial)渐变。一个 渐变是从一个颜色到另外一个颜色的填充。

一个轴向渐变(也称为线性渐变)沿着两个端点连接的轴线渐变。所有位于垂直于轴线的的某条线上的点都具有相同的颜色值。

一个径向渐变也是沿着两个端点连接的轴线渐变,不过路径通常由两个圆来定义。

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

例如:

轴向渐变由橙色向黄色渐变 在这个例子中渐变轴相对于远点倾斜了四十五度角。

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

Quartz 也允许我们设置一系列的颜色值和位置值,以沿着轴来创建更复杂的轴向渐变。如下图所示,起始点的颜色设置为红色(可以看一下Quartz 的坐标系 零点默认就是左下角),结束点的颜色是紫罗兰色。同时,在轴上有5个位置,它们的颜色分别设置为橙 黄 绿 蓝 和 靛蓝。我们可以把它看成沿着同一轴线的六段连续的线性渐变。另外轴线的角度 有我们设置的两个端点来定义。

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

2> radial gradient(径向渐变)

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

如下图所示,他从一个小的明亮的红色圆渐变到一个大小黑色的圆,

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

我们可以把一个圆放置到一个径向渐变中来创建各种形状。如果一个圆是另一个的一部分或者完全在另一个的外面,则Quartz创建了圆锥和一个圆柱。径向渐变的一个通常用法就是创建一个球体阴影

一个单一的点(半径为0的圆)位于一个大圆以内。

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

CGShading 和 CGGradient对象的对比

我们有两个对象类型用于创建渐变,你可能想知道哪一个更好用,看了下面你就会知道了。

CGshadingRef这个不透明的数据类型给我们更多的控制权,以确定如何计算每个端点的颜色,在我们创建CGShading对象之前,我们必须创建一个CGFunction对象(CGFunctionRef),这个对象定义了一个用于计算渐变色的函数。写一个自定义的函数让我们创建平滑的渐变。

当我们创建一个CGShading对象时,我们指定其是轴向还是径向,除了计算函数以外,我们还需要提供一个颜色空间。起始点 结束点 或者是半径,这取决于绘制轴向还是径向渐变。在绘制时,我们只是简单的传递CGShading对象以及绘制上下文给CGContextDrawShading函数,Quartz为渐变上的每个点调用渐变计算函数。

一个CGGRadient对象是CGShading对象的子集,其更容易使用,CGGradientRef不透明类型抑郁作用,因为Quartz在渐变的每一点上计算颜色值。我们不需要提供一个渐变计算函数。当创建好一个渐变对象的时候,我们提供一个位置和颜色的数组。quartz使用对应的颜色值来计算每个梯度的渐变。我们可以使用单一的气势与结束点来设置一个渐变对象。或者提供一组断电来创建一个多颜色渐变的效果。使用CGShading对象可以提供多于两个位置的能力。

当我们创建一个CGGradient对象时,我们需要设置一个颜色空间、位置、和每个位置对应的颜色值。当使用一个渐变对象绘制上下文时,我们指定Quartz是绘制一个轴向还是径向渐变。在绘制时,我们指定开始结束点或半径,这取决于我们是绘制轴向还是径向渐变。而CGShading的几何形状是在创建时定义的,而不是绘制时。

扩展渐变端点外部的颜色

当我们创建一个渐变时,我们可以选择使用纯色来填充渐变端点外部的空间。Quartz使用使用渐变边界上的颜色作为填充颜色。我们可以扩展渐变起点、终点或两端的颜色。我们可以扩展使用CGShading对象或CGGradient对象创建的轴向或径向渐变。

图演示了一个轴向渐变,它扩展了起点和终点两侧的区域。图片中的线段显示了渐变的轴线。我们可以看到,填充颜色与起点和终点的颜色是对应的。

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

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


渐变的两种绘制模型

CGShading -使用这种数据类型需要自己定义CFFunction来计算每一个点的渐变色,较为复杂,但是能够灵活的绘制。

CGGradient-使用这种数据类型只需要制定两个顶点的颜色,以及绘制模式,其余的Quartz会给绘制,但是渐变的数学模型不灵活。


使用CGGradient对象:

一个CGGradient 对象是一个渐变的抽象定义 他简单的质地昂了颜色值和位置,但没有指定任何几何形状,我们可以在轴向和径向几何形状中使用这个对象,作为一个轴向定义,CGGradient对象可能比CGShading对象更容易重用。没有讲任何几何形状存储在CGGradient对象中。这样允许我们使用相同的颜色方案来绘制不同的几何图形,而不需要为多个图形创建多个CGGadient对象。

因为Quartz为我们计算渐变,使用一个CGGradient对象来创建和绘制一个渐变则更直接,只需要以下几步:

1>创建一个CGGradient对象,提供一个颜色空间,一个饱含两个或更多颜色组件的数组,一个包含两个或多个位置的数组,和两个数组中元素的个数。

2>使用CGContextDrawLinearGradient或者CGContentDrawRadialGradient绘制。

3>释放CGGradient对象

一个位置是一个值区间在0.0到1.0之间的CGFloat值,他指定了沿着渐变的轴线的标准化距离值0.0的值指定轴线的起点,1.0的值指定了轴线的重点。其他值指定了一个距离的比例。最低限度情况下,Quartz使用两个位置值。如果我们传递NULL值作为位置数组参数,则Quartz使用0作为第一个位置,1作为第二个位置。

每个颜色的颜色组件的数目取决于颜色空间。对于离屏绘制,我们使用一个RGB颜色空间。因为Quartz使用alpha来绘制,每个离屏颜色都有四个组件—红、绿、蓝和alpha。所以,对于离屏绘制,我们提供的颜色组件数组的元素的数目必须是位置数目的4倍。Quartz的RGBA颜色组件可以在0.0到1.0之间改变。

代码

- (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();
//使用CGGradient绘制
CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
size_t num_of_locations = ;
  //注意每个位置对应一个颜色
CGFloat locations[] = {0.0,1.0};
CGFloat components[] = {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(, );
CGPoint endPoint = CGPointMake(rect.size.width, rect.size.height);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, );
CGColorSpaceRelease(deviceRGB);
CGGradientRelease(gradient);
}

效果

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)

径向渐变

CGContextRef context = UIGraphicsGetCurrentContext();
//颜色空间
CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
//位置数组和颜色数组包含元素的个数
size_t num_of_locations = ;
CGFloat locations[] = {0.0,1.0};
CGFloat components[] = {0.0,0.0,1.0,1.0,//白色
0.0,1.0,0.0,1.0};//黑色
CGGradientRef gradient = CGGradientCreateWithColorComponents(deviceRGB, components, locations, num_of_locations);
CGPoint startCenter = CGPointMake(, );
CGPoint endCenter = CGPointMake(, );
CGFloat startRadius = 0.0;
CGFloat endRadius = 50.0;
CGContextDrawRadialGradient(context, gradient, startCenter, startRadius, endCenter, endRadius, );
CGColorSpaceRelease(deviceRGB);
CGGradientRelease(gradient);

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)


使用CGShading对象

我们通过调用函数CGShadingCreateAxial或者CGShadingCreateRadial创建一个CGShading对象来设置一个渐变,调用这些函数需要提供以下参数。

1.CGColorSpace 对象:颜色空间

2.起始点和终点。对于轴向渐变,有轴向的起始点和和终点的坐标,对于径向渐变,有起始圆和终点圆的中心坐标

3.用于定义渐变区域的圆的启示半径和终止半径

4.一个CGFunction对象,可以通过CGFunctionCreate函数来获取。这个回调例程必须返回绘制到特定点的颜色值。

5.一个布尔值用于指定是否适用纯色来绘制起始点和终点的扩展区域

我们提供给CGShading创建函数的CGFunction对象包含一个回调结构体,及Quartz需要实现这个回调的所有信息。也许设置CGShasing对象的最棘手的部分是创建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的数据(就是指向回调所需要的数据的指针),注意他的生命周期可能不只是方法的生命周期

domainDimesion 输入的数量,quart中,就是1。(回调输入值的个数,Quartz要求回调携带一个输入值)

domain 一组数据 确定输入的有效间隔,在Quartz中是0到1,0表示开始,1表示结束 (一个浮点数的数组。Quartz只会提供数组中的一个元素给回调函数。一个转入值的范围是0(渐变的开始点的颜色)到1(渐变的结束点的颜色)。)

rangDimension 输出的数量:(回调提供的输出值的数目,对于每一个输入值,我们的回调必须为每个颜色组件提供一个值,以及一个alpha值来指定透明度,颜色组件值由Quartz提供的颜色空间来解释,并提供给CGShading创建函数。例如如果我们使用RGB颜色空间,则我们提供4作为输出值(R,G,B,A)的数目)

rang 输出的有效间隔 (一个浮点数的数组,用于指定每个颜色组件的值及alpha值)

callbacks 用来计算的实际方法 (一个回调数据结构,包含结构体的版本(设置为0)、生成颜色组件值的回调、一个可选的用于释放回调中info参数表示的数据。)格式如下 格式如下void myCalculateShadingValues (void *info, const CGFloat *in, CGFloat *out)


在创建CGShading对象后,如果需要我们可以设置额外的裁减操作。然后调用CGContextDrawShading函数来使用渐变来绘制上下文的裁减区域。当调用这个函数时,Quartz调用回调函数来获取从起点到终点这个范围内的颜色值。

当不再需要CGShading对象时,我们调用CGShadingRelease来释放它。

首先设置CGFunction对象来计算颜色值

我们可以以我们想要的方式来计算颜色值,我们的颜色计算函数包含以下三个参数:

1.void *info 这个值可以为NULL 或者是一个指向传递给CGShading创建函数的数据

2.const CGFloat *in  Quartz传递in数组给回调。数组中的值必须在为CGFunction对象定义的输入值范围内

3.我们的回调函数传递out数组给Quartz。它包含用于颜色空间中每个颜色组件的元素及一个alpha值。输出值应该在CGFunction对象中定义的输出值的范围内

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

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

创建一个CGFuction

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

其中,每一行分别为

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

用CGShading绘制Axial Gradient

CGPoint     startPoint,
endPoint;
CGFunctionRef myFunctionObject;
CGShadingRef myShading;
startPoint = CGPointMake(,0.5);
endPoint = CGPointMake(,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[] = { , , , };
components = (size_t)info;
for (k = ; k < components - ; k++)
*out++ = ( + sin(*in * frequency[k]))/;
*out++ = ; // alpha
}
CGPoint startPoint, endPoint;
CGFloat startRadius, endRadius;
startPoint = CGPointMake(0.25,0.3);
startRadius = .;
endPoint = CGPointMake(.,0.7);
endRadius = .;
colorspace = CGColorSpaceCreateDeviceRGB();
myShadingFunction = myGetFunction (colorspace);
CGShadingCreateRadial (colorspace,
startPoint,
startRadius,
endPoint,
endRadius,
myShadingFunction,
false,
false)
CGContextDrawShading (myContext, shading);
CGShadingRelease (myShading);
CGColorSpaceRelease (colorspace);
CGFunctionRelease (myFunctionObject);

具体效果请看 这里 http://www.tuicool.com/articles/biieum

我的水平还是有点看不懂啊

iOS 2D绘图 (Quartz2D)之阴影和渐变(shadow,Gradient)的更多相关文章

  1. iOS 2D绘图详解(Quartz 2D)之阴影和渐变&lpar;Shadow&comma;Gradient&rpar;

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

  2. iOS 2D绘图 &lpar;Quartz2D&rpar;之Transform&lpar;CTM,Translate,Rotate,scale&rpar;

    前言:Quartz默认采用设备无关的user space来进行绘图,当context(画板)建立之后,默认的坐标系原点以及方向也就确认了,可以通过CTM(current transformation ...

  3. iOS 2D绘图 &lpar;Quartz2D&rpar;之路径&lpar;stroke,fill,clip,subpath&comma;blend&rpar;

    像往常一样 这个系列的博客是跟着大神的脚步来的.按照往例 在此贴出原博客的出处: http://blog.csdn.net/hello_hwc?viewmode=list我对大神的崇拜之情 如滔滔江水 ...

  4. iOS 2D绘图 &lpar;Quartz2D&rpar;之路径&lpar;点,直线,虚线,曲线,圆弧,椭圆,矩形&rpar;

    博客原地址:http://blog.csdn.net/hello_hwc?viewmode=list 让我们继续跟着大神的脚步前进吧.这一次 我们学习一些Quartz 2D 最基本的一些用法. 前言: ...

  5. iOS 2D绘图详解(Quartz 2D)之路径&lpar;点&comma;直线&comma;虚线&comma;曲线&comma;圆弧&comma;椭圆&comma;矩形&rpar;

    前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...

  6. iOS 2D绘图 &lpar;Quartz 2D&rpar; 概述

    本篇博客原文地址:http://blog.csdn.net/hello_hwc?viewmode=list 由于自己的项目需要,从网络上下载了许多关于绘制图形的demo,只是用在自己的项目中,很多地方 ...

  7. iOS 2D绘图详解(Quartz 2D)之概述

    前言:最近在研究自定义控件,由于想要彻底的定制控件的视图还是要继承UIView,虽然对CALayer及其子类很熟练,但是对Quartz 2D这个强大的框架仍然概念模棱两可.于是,决定学习下,暂定7篇文 ...

  8. iOS 2D绘图详解(Quartz 2D)之Bitmap

    什么是Bitmap? Bitmap叫做位图,每一个像素点由1-32bit组成.每个像素点包括多个颜色组件和一个Alpha组件(例如:RGBA). iOS中指出如下格式的图片 JPEG, GIF, PN ...

  9. iOS 2D绘图详解(Quartz 2D)之Transform&lpar;CTM&comma;Translate&comma;Rotate&comma;Scale&rpar;

    前言:Quartz默认采用设备无关的user space来进行绘图,当context(画板)建立之后,默认的坐标系原点以及方向也就确认了,可以通过CTM(current transformation ...

随机推荐

  1. C&num;中用radio单选Repeater循环数据&comma;js实现

    <asp:Repeater ID="rpt" runat="server"> <ItemTemplate> <tr data-id ...

  2. HttpClient入门

    HttpClient入门 HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 H ...

  3. Liunx小白须知

    最近在学习Liunx,从装虚拟机到敲命令出了一些问题,95%的问题从搜索引擎都可以找到.本来想写个虚拟机安装步骤结果忘记截图了,不过没事,网上一大把.写写博文勒就是记录下自己的成长,虽然现在还是个小白 ...

  4. Linux之文本编辑器Vim

    一.什么是vim vi是一种模式编辑器.vi 是Unix世界里极为普遍的全屏幕文本编辑器,几乎可以说任何一台Unix机器都会提供这套软体,其他的文本编辑器则不一定会存在,但是目前我们使用比较多的是 v ...

  5. 结对作业&lowbar;core组

    github地址:https://github.com/ljw-wakeup/expression_project2 对于这种结对的工作,由于有过电子设计实践的基础,大概知道建一个工程需要做的事,有点 ...

  6. &lbrack;转&rsqb;OmniLayer &sol; omnicore API 中文版

    本文转自:https://www.codetd.com/article/1692438 JSON-RPC API Omni Core是Bitcoin Core的一个分支,其Omni协议功能支持作为顶层 ...

  7. 个人整理的数组splay板子,指针的写的太丑了就不放了。。

    splay的板子.. 由于被LCT榨干了..所以昨天去学了数组版的splay,现在整理一下板子.. 以BZOJ3224和3223为例题..暂时只有这些,序列的话等有时间把维修序列给弄上来!! BZOJ ...

  8. PHP去调用jenkins

    背景说明:目前公司用到 jenkins(持续集成开源工具)更多情况下,通过配置,可以在gitlab上通过webhooks去调度jenkins 或者通过 jenkins管理后台,去手动执行“立即构建”去 ...

  9. 作为phper既然了解共享内存函数shmop的使用方法,那么就必须要了解一下信号量是什么,以及信号量使用的代码案例

    在单独的一个PHP进程中读写.创建.删除共享内存方面上你应该没有问题了.但是实际运行中不可能只是一个PHP进程在运行中.如果在多个进程的情况下你还是沿用单个进程的处理方法,你一定会碰到问题--著名的并 ...

  10. ORM sqlachemy学习

    内容: 1.ORM介绍 2.SQLAlchemy介绍 3.SQLAlchemy内部处理 4.SQLAlchemy使用 参考: http://www.cnblogs.com/wupeiqi/articl ...