【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记12 Custom Views视图绘制1

简介: 这一话来讲解一下视图的绘制,首先介绍一下相关的结构体视图中的所有coordinate(坐标)的类型都是CGFloat,CGFloat在Swift中是结构体,在处理视图绘制和手势识别的时候我们使用的都是CGFloat,不要用我们常规的Double和Float。

这一话来讲解一下视图的绘制,首先介绍一下相关的结构体


视图中的所有coordinate(坐标)的类型都是CGFloat,CGFloat在Swift中是结构体,在处理视图绘制和手势识别的时候我们使用的都是CGFloat,不要用我们常规的Double和Float。你可以通过使用CGFloat的初始化方法把Double或者Float类型的数据转换成CGFloat。

另外一个结构体是CGPoint,它由x和y两个CGFloat类型组成,用来定义坐标中的一个点。

还有一个结构体是CGSize,用来表示长和宽。

CGSize和CGPoint通常不会用到什么方法。


把一个CGPoint和一个CGSize组合起来就是一个CGRect。origin是CGPoint类型的表示原点,在区域的左上角。size是CGSize的表示宽和高。CGRect有很多属性和方法。比如minX返回左边界,midY返回垂直方向的中点。intersects传递另一个矩阵进去判断这两个矩阵有没有重叠。

intersect创建一个更小的矩阵,由两个矩阵重叠的部分组成。

contains传入一个point,判断这个点是否在矩阵中。

CGRect有很多有意思的方法,大家可以自己去尝试一下。


现在来讲解一下视图的坐标系统,首先坐标系的原点是在左上方的。比如这里有个点(500,35),那么它距离左边500,距离上边35.

我们在这用的单位是points(点)而不是pixels(像素)高分辨率的屏幕中一个点可能包含多个像素,这样可以用来绘制平滑的曲线和文本,并且具有抗锯齿能力。通常你不用在意点与像素的关联,因为系统会自己考虑一个点使用多少像素才能使绘制看起来优美。但有时候你需要注意,特别是你需要处理非常精细的边界的时候,你可以访问系统中的一个属性contentScaleFactor,它会告诉你每个点返回多少像素。在视网膜屏幕(Retina)中一个点占用两个像素,非视网膜屏幕只占用一个。

另外我们绘制图形的边界在哪里,你已经有一个宽和高了,这就涉及到属性bounds,它是CGRect类型的,它定义了坐标系中的绘制区域,需要注意的是绘制是相对于自身的,因为视图可以被拉伸、旋转或者变换,你使用bounds的时候你是在自身坐标系绘制,你知道这个矩形的确切位置。bounds的原点通常是(0,0),但是也有例外,比如scroll view中会更改它的原点到目前滚动的位置。大部分情况下你的原点就是(0,0),你需要关心的是它的长和宽,也就是我们绘制的区域面积。

这里有两个容易和bounds搞混的属性center和frame。center是你自身视图坐标的中点,但是它是相对于父视图的而不是视图本身的坐标。如果你想在视图中心绘制点东西使用了center,那么这样做是错误的,因为center基于父视图和绘制没有关系,它仅仅用来在父视图中定位。

frame同样是父视图中用来包含子视图的一个矩形,它相对于父视图,与绘制无关。绘制的时候我们使用bounds。

为了方便理解你可以认为frame的size和bounds的size总是相同的,代表一个矩形要完全包含另一个矩形,但是也有例外,因为视图是可以旋转的。


你可以看到如果发生旋转,那么frame的尺寸要比bounds大得多,所以一定要注意frame和center用来定位视图,而bounds才是用来绘制视图的。那么如何创建一个视图呢?


大部分视图是直接通过storyboard拖拽创建的,但是官方视图可能不能满足你的要求,这时候你就需要先拖拽一个通用的视图UIView。一旦你拖出这个视图,你就需要在你的Identity Inspector里把对应的类修改为你自己实现的类。只有在很少的情况下才通过纯代码来创建视图。你可以使用一个无参数的构造器,这样返回的是一个原点和尺寸都是0的空视图,你可以在稍后再给它赋值。

UILabel是UIView的一个子类,所以我们可以使用带参数frame的构造器,创建好之后把它加到父视图中,这里的父视图是我们之前讲的viewController中最顶层的view。可以通过纯代码这样做但是在IOS开发中我们几乎不这么做,我们使用storyboard。

那么我们什么时候需要自己创建一个视图呢,如果你只是需要使用一些常规的组件那么直接使用系统自带的就可以,如果你想要绘制一些特殊的图形,或者相对不同的触摸手势做出不同的反应的话,那么你需要自己定义一个视图。


要绘制一个视图,你需要重写drawRect方法,它只接受一个参数,在系统中它叫rect,但是我们已经把它重新命名为regionThatNeedsToBeDrawn,这个参数纯粹是起一个优化的效果,绘图时会重点关注参数中的区域。

需要注意:永远都不要调用drawRect方法!drawRect是被系统调用的,当你的视图需要重新绘制时,它会自动被系统调用,你可能会问系统是如何知道你想要重绘。在你的视图中有一个方法叫做setNeddDisplay方法,如果你需要重绘视图,那么调用它,系统会在适合的时机调用drawRect,但是首先它会设置一些东西,你周围的其他视图,它们必须先被组织起来。


那么我们如何实现drawRect方法呢你可以使用类似于C语言基于函数的API叫做Core Graphics,它是所有图像绘制的基础。或者使用一种面向对象的方法UIBezierPath,这是我们接下来要用到的方法,遇到底层一些的东西会降到Core Graphics的概念,它是构建UIBezierPath的基础和核心。

在Core Graphics中第一件很重要的事情是你需要拥有一个用来绘制的上下文(context),在drawRect中,当你准备绘制时,系统会调用drawRect并且为你建立一个绘制的context,它是自动建立的,并且被称之为当前的context,通过UIGraphicsGetCurrentContext方法,它将会返回这个cookie作为你的上下文,所有的类C API都是用上下文作为参数。

然后你创建路径,通过线条和弧线诸如此类的来创建路径。

接着你设置绘制的属性,你希望绘制的线条颜色、宽度等等。

最后你通过描边并且填充这些路径。

这就是你绘制的基础,类似于绘制文字之类的事情只需要知道字体并且如何获得一个完美的路径来挥之漂亮的字母,你的描边也将绘制字母的边界最后填充字母内部。

现在来介绍UIBezierPath这个面向对象的方法在最上面,通常在当前的context上绘制,它是将所有的Core Graphics放到一个类中。

下面我们来看看如何定义一个路径并且绘制一个三角形。


首先你要初始化一个路径UIBezierPath,然后你可以在周围移动,移动到点(80,50),然后添加一条线到(140,150)


然后再添加一条线到(10,150)


最后闭合这个路径,当然虽然示例中你看到了一个三角形,但实际这时候你在屏幕上是什么都看不到的。你需要继续设置它的属性:


比如我把填充色设置为绿色,把描边的颜色设置为红色,注意设置颜色用的是UIColor的方法而不是使用BezierPath的方法。但是线宽就需要和path来商议了,所以发消息给path告诉它线宽为3.0。全部完成后就可以开始填充了,使用方法fill()。


现在屏幕上出现了一个绿色三角形,然后再给它描边,就会出现红色边框:


我们会在接下来的几话中绘制更多更复杂的图形。

目录
相关文章
|
前端开发 API
【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记4 MVC enum Tuple Dictionary
 回顾一下我们上一话中的代码: @IBAction func operate(sender: UIButton) { let operation = sender.
790 0
|
前端开发 iOS开发
【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记3 Xcode、Auto Layout及MVC
   继续上一话中的计算器Demo,上一话讲到类必须被初始化,类中的属性也必须被初始化,所以你不能只声明而不给它一个处置,那么问题来了,我们从storyboard中拖拽的@IBOutlet为什么只有声明而不需要初始化呢,这是因为它的类型依旧是一个optional,在你初始化之前已经被赋值为nil了,这也就是为什么你不需要再初始化它的原因。
873 0
|
Unix iOS开发
【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记1 IOS8概述
  首先感谢网易公开课和SwiftV课堂的朋友们辛苦翻译,这个系列是我学习斯坦福IOS8公开课的个人心得体会和笔记,希望能给大家带来启发。
1062 0
|
Swift iOS开发
swift语言IOS8开发战记4.custom tableViewCell
第三话中讲解了如何利用系统内置的cell格式,这一话来谈谈如何自定义cell格式.在stroyboard中通过拖拽为cell添加内容,并且通过属性检测器修改样式,下面是我简单设置的一个自定义cell。
969 0
|
11天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
2月前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
118 1
|
2天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
4天前
|
存储 前端开发 Swift
探索iOS开发:从新手到专家的旅程
本文将带您领略iOS开发的奇妙之旅,从基础概念的理解到高级技巧的掌握,逐步深入iOS的世界。文章不仅分享技术知识,还鼓励读者在编程之路上保持好奇心和创新精神,实现个人成长与技术突破。
|
19天前
|
安全 数据处理 Swift
深入探索iOS开发中的Swift语言特性
本文旨在为开发者提供对Swift语言在iOS平台开发的深度理解,涵盖从基础语法到高级特性的全面分析。通过具体案例和代码示例,揭示Swift如何简化编程过程、提高代码效率,并促进iOS应用的创新。文章不仅适合初学者作为入门指南,也适合有经验的开发者深化对Swift语言的认识。
39 9
|
15天前
|
设计模式 Swift iOS开发
探索iOS开发:从基础到高级,打造你的第一款App
【10月更文挑战第40天】在这个数字时代,掌握移动应用开发已成为许多技术爱好者的梦想。本文将带你走进iOS开发的世界,从最基础的概念出发,逐步深入到高级功能实现,最终指导你完成自己的第一款App。无论你是编程新手还是有志于扩展技能的开发者,这篇文章都将为你提供一条清晰的学习路径。让我们一起开始这段旅程吧!