Swift Core Graphics教程之Gradients 与 Context
更新时间 04/15/2015 为Xcode 6.3 和 Swift1.2更新 欢迎回到我们的Swift核心绘图教程系列! 在第一部分中,你学习到了使用storyboard绘制线条和矩形. 在第二部部分中,你将深入核心绘图,使用CGContext实现渐变效果 核心绘图你现在已经从简单的UIKit深入到核心绘图。 下图是各个框架的关系图: UIKit是在最顶层,使用最友好的框架。你使用过UIBezierPath的就是在UIKit层中对Core Graphics层中CGPath的封装。 你可以看到 Core Graphics 的对象和方法都是CG开头的,非常容易辨认。 另外CG方法都是C方法,在调用的时候不需要明确的指定参数名,和一般Swift调用方法不一样。 从Graph View开始本次的目标就是使用历史数据创建一个图表。 在绘图之前,你需要创建一个storyboard,写一些显示图表的代码。 完成后的视图结构如下图: 如果你还没有完成,从这里下载开始的项目。 打开 FileNewFile…,选择 iOSSourceCocoa Touch Class 打开 Main.storyboard 拖一个 UIView 到控制器的视图。 视图将包含一个 此时目录结构应该是这样的: 在 Size Inspector,设置 X=150,Y=50,Width=300, 创建自动布局约束非常简单,在第一部分中有讲到。
当创建了视图,通常我们我们会设置一个临时的背景颜色,这样做非常有用,可以让我们清楚的看到我们做了什么。 在 Attributes Inspector,将背景颜色设置为黄色. 再拖一个 UIView 到黄色的视图作为它的子视图. 在 Identity Inspector,将新创建的视图的class设置为GraphView. 在 Size Inspector,设置 X=0,Y=25, 在Document Outline,将 Counter View拖到黄色的视图中作为它的子视图,这里需要注意需要放置在Graph View的后方。 在移动 Counter View之后,自动布局约束会变红. 选择 Counter View,在storyboard 右下方找到并点击 Resolve Auto Layout Issues,选择 你可以重置为默认的约束,因为现在 在 Document Outline 双击黄色视图来重命名为 Container View. 现在 Document Outline 是这样子的: 你需要一个 打开 ViewController.swift,为
这一步为 打开 Main.storyboard, 将 Graph View Container View 和 outlets关联起来: 设置渐变动画仍然在 Main.storyboard中,从Object Library 拖一个UITapGestureRecognizer 到 Container View: 打开 ViewController.swift 在开头添加属性:
这个将简单的标记用于判断当前 为点击事件添加过渡效果的方法:
在btnPushButton(_:)的最后添加以下代码:
这是为了防止在图标正在显示的过程中点击,将闪回计数器视图。 最后,为了让这个效果生效,打开 Main.storyboard,将点击手势与 构建并运行程序,你可以看到 分析Graph View还记得第一部分的绘图模型嘛?它描述了用Core Graphics绘图从里到外的过程,你需要明白这里的顺序在你写代码之前:
绘制渐变现在我们在 打开 GraphView.swift 将里面带代码替换为以下:
这里有以下步骤
通过 在Xcode你通过设置代码或者在storyboard的Assistant Editor调节,可以直接在 在storyboard中,选择 在 Main.storyboard,一次选择所有的视图,除了控制器自带的,将他们的BackgroundColor 设置为clear color. 现在已经不需要黄色背景了,同样将按钮的背景颜色设置为透明. 运行程序,你会发现现在变得好看很多。 裁剪区域你刚才用渐变填充了整个上下文的区域。现在你可以创建路径来裁剪当前的绘图区域。 打开GraphView.swift,在
这个将创建一个裁剪区域来限制渐变效果,你可以用相同的方式绘制渐变效果在在折线上。 构建运行程序,你会发现有漂亮的圆角效果: 注意: 绘制静态的图像使用 除了使用裁剪路径,你还可以通过使用CALayer的 计算坐标点现在可以短暂了停一下画图,我们需要绘制7个点,横坐标为一周的七天,纵坐标为 首先,设置几个简单的值。 在 GraphView.swift,在顶部添加属性:
这里简单的数据代表了七天的数据。 接着,在
横坐标点包括了7个等距离的点。上述代码在一个闭包表达式中,应该是要独立的封装成一个方法,但是对于这个小的运算量,是可以内嵌在代码之中。
接着,在
因为起始点为左上角,但是你是从左下角开始绘制, 继续在
在这个代码快中,你创建了图标的路径, 现在,storyboard中的图标看起来是这样的: 现在你验证了线已经正确绘制,从
这行代码让你检查线在 图表渐变现在在这个折线的路径之下来绘制渐变效果. 首先设置裁剪路径在
通过上述代码让块于块之间分割:
现在storyboard中的图标看起来应该是这样的: 下一步,你会将可爱的绿色换成你为背景创建的渐变的效果 移除
在这里,你将找到最大的数字作为渐变的起点。 You can’t fill the whole 你不能填充这个 注意CGContextRestoreState的注释,你在绘制之后需要取消注释。 在
这里绘制了原始的路径 现在图标看起来是这样的: 在
绘制小圆点的代码并不是新的。这里将为每一个数组中的元素的位置绘制一个圆点。 现在为什么不好看呢,对了,小圆点。没事,我们一会加上去。 上下文状态图形上下文可以保存状态。当你设置了许多上下文属性,如填充颜色,色域,变换矩阵,或裁剪区域,你实际上设置为当前图形状态。 你可以使用 在 GraphView.swift的 现在的图标和圆点看起来更加的清晰: 在
没有新的代码,你需要做的只是移动到一个点然后水平画线。 添加图标的标签现在你可以添加标签来让图标的用户体验更好。
这两个标签将会动态的改变内容(饮水量的平均值和最大值)。 在 Main.storyboard 添加以下的 UILabels 作为 Graph View的子视图:
通过Shift全选所有标签,改变字体为Avenir Next Condensed,Medium style. 在Main.storyboard关联 对于每天得标签来说,在Attributes Inspector 改变 View’s Tag 属性,分别食从1到7 现在已经完成了图标的设置,在Main.storyboard 选择 Graph View并选择Hidden,让程序第一次出现的时候不显示图标。 在 ViewController.swift 添加以下方法来设置标签: func setupGraphDisplay() {
//Use 7 days for graph - can use any number,
//but labels and sample data are set up for 7 days
let noOfDays:Int = 7
//1 - replace last day with today's actual data
graphView.graphPoints[graphView.graphPoints.count-1] = counterView.cou
nter
//2 - indicate that the graph needs to be redrawn
graphView.setNeedsDisplay()
maxLabel.text = "(maxElement(graphView.graphPoints))"
//3 - calculate average from graphPoints
let average = graphView.graphPoints.reduce(0,combine: +)
/ graphView.graphPoints.count
averageWaterDrunk.text = "(average)"
//set up labels
//day of week labels are set up in storyboard with tags
//today is last day of the array need to go backwards
//4 - get today's day number
let dateFormatter = NSDateFormatter()
let calendar = NSCalendar.currentCalendar()
let componentOptions:NSCalendarUnit = .CalendarUnitWeekday
let components = calendar.components(componentOptions,fromDate: NSDate())
var weekday = components.weekday
let days = ["S","S","M","T","W","F"]
//5 - set up the day name labels with correct day
for i in reverse(1...days.count) {
if let labelView = graphView.viewWithTag(i) as? UILabel {
if weekday == 7 {
weekday = 0
}
labelView.text = days[weekday--]
if weekday < 0 {
weekday = days.count - 1
}
}
}
}
This looks a little burly,but it’s required to set up the calendar and retrieve the current day of the week. Take it in sections: 这看起来有点粗鲁的,但它需要设置日历和知道今天是星期几:
还是在ViewController.swift,在 “` “` 运行程序,点击计数器,万岁,图表将显示所有的数据。 掌握矩阵现在程序看起来有点突兀,我们子啊第一部分创建的计数器还需要提升一下,在饮水量上添加指示。 现在已经有CG方法绘图的一些经验了,你将会使用旋转和平移。 和在上下文绘图一样,你可以通过旋转,缩放,和平移来进行矩阵变幻。 一开始这可能是令你费解的,但是在经过一些练习之后,将会变得更有意义,变换的顺序非常重要,我先说画出你需要做的示意图。 黑色的矩形食旋转前的上下文。然后是绿的,再是红得。有两件事需要注意。
当你绘制计数器的标志的时候,你需要先旋转上下文,然后再绘制它。 在这个示意图中,矩形的标记在左上方,蓝色轮廓就是变换的上下文,然后上下文旋转(红色虚线),然后再次旋转。 最后当红色的标识被绘制完之后,它的角度如图所示: 在上下文旋转和平移得到红色标记之后,它需要回到中心来进行下一次的变换得到绿的标志。 就像你在裁剪的时候保存上下文一样,你需要保存和恢复上下文状态在每次矩阵变换的时候。 打开CounterView.swift 在 //Counter View markers
let context = UIGraphicsGetCurrentContext()
//1 - save original state
CGContextSaveGState(context)
outlineColor.setFill()
let markerWidth:CGFloat = 5.0
let markerSize:CGFloat = 10.0
//2 - the marker rectangle positioned at the top left
var markerPath = UIBezierPath(rect:
CGRect(x: -markerWidth/2,y: 0,width: markerWidth,height: markerSize))
//3 - move top left of context to the previous center position
CGContextTranslateCTM(context,rect.width/2,rect.height/2)
for i in 1...NoOfGlasses {
//4 - save the centred context
CGContextSaveGState(context)
//5 - calculate the rotation angle
var angle = arcLengthPerGlass * CGFloat(i) + startAngle - π/2
//rotate and translate
CGContextRotateCTM(context,angle)
CGContextTranslateCTM(context,0,rect.height/2 - markerSize)
//6 - fill the marker rectangle
markerPath.fill()
//7 - restore the centred context for the next rotate
CGContextRestoreGState(context)
}
//8 - restore the original state in case of more painting
CGContextRestoreGState(context)
这里你做了下面几点:
喔,干的不错,现在来运行程序,欣赏这个漂亮的界面。 接下来该做什么?这里, 现在你已经学会了绘制路径,渐变效果和通过上下文的矩阵变化 在第三部分的核心绘图教程中,你将创建图案的背景和绘制矢量图。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |