iOS 2D绘图详解(Quartz 2D)之阴影和渐变(Shadow,Gradient)
前言:这个系列写道这里已经是第五篇了,本文会介绍下阴影和渐变的基础知识,以及一些基本的Demo Code展示,应该还会有两篇,介绍下Bitmap绘制以及Pattern等知识。
Shadow
shadow(阴影)的目的是为了使UI更具有立体感,如图
shadow主要有三个影响因素
- x off-set 决定阴影沿着x的偏移量
- y off-set 决定阴影沿着y的偏移量
- blur value 决定了阴影的边缘区域是不是模糊的
其中不同的blur效果如图
注意
Shadow也是绘制状态相关的,意味着如果仅仅要绘制一个subpath的shadow,要注意save和restore状态。
相关函数
CGContextSetShadow
CGContextSetShadowWithColor//位移区别是设置了阴影颜色
参数
- 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);
}
其中,每一行分别为
- 以colorspace作为参数
- 定义callback函数
- 计算颜色域中的颜色组建的个数,例如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);
效果
iOS 2D绘图详解(Quartz 2D)之阴影和渐变(Shadow,Gradient)的更多相关文章
- iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)
前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...
- iOS 2D绘图详解(Quartz 2D)之概述
前言:最近在研究自定义控件,由于想要彻底的定制控件的视图还是要继承UIView,虽然对CALayer及其子类很熟练,但是对Quartz 2D这个强大的框架仍然概念模棱两可.于是,决定学习下,暂定7篇文 ...
- iOS开发 绘图详解
Quartz概述 Quartz是Mac OS X的Darwin核心之上的绘图层,有时候也认为是CoreGraphics.共有两种部分组成 Quartz Compositor,合成视窗系统,管理和合 ...
- iOS 2D绘图详解(Quartz 2D)之Bitmap
什么是Bitmap? Bitmap叫做位图,每一个像素点由1-32bit组成.每个像素点包括多个颜色组件和一个Alpha组件(例如:RGBA). iOS中指出如下格式的图片 JPEG, GIF, PN ...
- iOS 2D绘图详解(Quartz 2D)之Transform(CTM,Translate,Rotate,Scale)
前言:Quartz默认采用设备无关的user space来进行绘图,当context(画板)建立之后,默认的坐标系原点以及方向也就确认了,可以通过CTM(current transformation ...
- iOS 2D绘图详解(Quartz 2D)之路径(stroke,fill,clip,subpath,blend)
Stroke-描边 影响描边的因素 线的宽度-CGContextSetLineWidth 交叉线的处理方式-CGContextSetLineJoin 线顶端的处理方式-CGContextSetLine ...
- iOS中-Qutarz2D详解及使用
在iOS中Qutarz2D 详解及使用 (一)初识 介绍 Quartz 2D是二维绘图引擎. 能完成的工作有: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ...
- 【转】Android Canvas绘图详解(图文)
转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...
- 转载]IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本 )
原文地址:IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本作者:佐佐木小次郎 因为最近项目上要用有关LBS的功能.于是我便做一下预研. 一般说来LBS功能一般分为两块:一块是地理 ...
随机推荐
- .Net 学习
.Net 的微型Web框架Nancy ORM工具 Simple Data Ojbective-C 与 swift Xamarin for VisualStudio jQuery 1. 绝对的万金油,核 ...
- LeetCode ---Anagrams() 详解
Notice: Given an array of strings, return all groups of strings that are anagrams. Note: All inputs ...
- 设计模式 适配器-Adapter
适配器模式:将一个类的接口,转换成客户期望的另一个接口.适配器让原本接口不兼容的类可以合作无间. 直接上图.下面是对象适配器的类图.由于Java不支持多继承.所以这是Java的适配器实现方式. 结合H ...
- CentOS下挂在NTFS分区
本文参考自http://www.cnblogs.com/gbyukg/archive/2011/11/02/2232343.html centos下想访问NTFS分区,现在普遍的方法是利用ntfs-3 ...
- pyQt 每日一练习 -- 登录框
#coding=utf-8 #第一个练习,登录框 import sys from PyQt4 import QtGui,QtCore #登录框 class LoginBox(QtGui.QWidget ...
- TPARAMS和OLEVARIANT相互转换
所谓的“真3层”有时候是需要客户端上传数据集的TPARAMS到中间件的. 现在,高版本的DATASNAP的远程方法其实也是直接可以传输TPARAMS类型的变量,但是DELPHI7(七爷).六爷它们是不 ...
- ML 徒手系列 拉格朗日乘子法
拉格朗日乘子法是解决极值问题的方法. 本方法是计算多元函数在约束条件下的极值问题的方法. 1.多元函数与约束问题 如下图所示,f(x,y)为多元函数,g(x,y)=c为约束条件.目的是计算在约束条件下 ...
- 8.3 LIS LCS LCIS(完结了==!)
感觉这个专题真不好捉,伤心了,慢慢啃吧,孩纸 地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28195#overview 密码 ac ...
- CentOS6 下安装JDK7
1.下载JDK:http://www.oracle.com/technetwork/java/javase/archive-139210.html,选择Java SE 7,下载jdk-7u80-lin ...
- Mac生存手册
最近刚从Linux转到了Mac系统上,感觉好的地方是再也不折腾了,什么GNOME, KDE, XFCE,各种发行版本都远离我而去了.当然Mac下很多好软件都是要付费的,我只能绕着走了: 1. 命令行, ...