前言
这是斯坦福大学在线课程-Developing iOS 9 Apps with Swift 的学习内容,在iTunes上就可以搜到,有兴趣的小伙伴可以一起学习一起进步哈!这里我将一些我认为的关键知识点摘录在我的学习笔记系列中。之前用英文写了几篇,感觉没什么人看,其实个人认为用英文学再用英文写其实更简单方便一些。
Demo
首先,是一张萌蠢的笑脸,你要是看着不舒服,你可以从我的github中下载相应代码,或者自己敲哈,让它哭也成。
Views
-
先乱入一条(别打我),swift的命名规范:在swift中,所有类型的名称的首字母大写。
比如private enum Eye
,private struct Ratios
- 一个view(比如:UIView)表示的是一个矩形的区域,定义了一个坐标空间。它可以用来画图(比如这个demo),也可以用来处理点击事件。
- view在swift中是分级的,也就是说
- 一个view只能有一个superview,
var superview: UIView?
- 一个view可以有很多个subview,
var subviews: [UIView]
- subview的范围甚至可以在他老爸view的范围之外。
- view是有顺序之分的,后来者居上。
- UIWindow在view(分级)中处在非常高级的位置,在一个app中一般只有一个。
初始化一个UIView
有两种不同的方式:
- init(frame: CGRect) // 由代码创建生成
- init(coder: NSCoder) // 由storyboard生成
如果你需要一个初始化程序,那这两种初始化都需要执行:
func setup() { ... }
override init(frame: CGRect) { // a designed initializer
super.init(frame: frame)
setup()
}
required init(coder aDecoder: NSCoder) { // a required initializer
super.init(coder: aDecoder)
setup()
}
另一个初始化方式:使用awakeFromNib()
,这只能用于storyboard上创建的UIView。注意这不是一个初始化器,它是“初始化完成之后立马被调用”。
坐标系统数据结构
- CGFloat
在UIView的坐标系统中,使用CGFloat类型的数据而不是Double或者Float。你可以将Double或者Float转换成CGFloat, 比如:let cgf = CGFloat(aDouble)
- CGPoint
比如:var point = CGPoint(x: 37.0, y: 52.0)
其实就是由两个CGFloat类型的数组成的一个简单结构。 - CGSize
和CGPoint差不多,也是由两个CGFloat类型的数组成的简单结构。
比如:
var size = CGSize(width: 100.0, height: 50.0)
size.width += 10
size.height += 5
- CGRect
由CGPoint和CGSize组成的结构
struct CGRect {
var origin: CGPoint
var size: CGSize
}
let rect = CGRect(origin: aCGPoint, size: aCGSize) //当然可以用别的初始化方式
这结构里自带了很多好东西:
-
var minX: CGFloat //最小的x
-
var midY: CGFloat //中间点的y
-
intersects(CGRect) -> Bool //判断和别的CGRect有没有相交
-
intersect(CGRect) //返回相交的部分
-
contains(CGRect) -> Bool //判断是否包含了另一个CGRect
-
View的坐标系统
-
左上是初始点。如下图:
-
!注意,单位是点,不是
像素,点不是像素,点等于几个像素。比如在6 plus上,每个点有3个像素;有些手机则是2个像素一个点。
你可以通过这条语句知道你的设备一个点有多少像素,var contentScaleFactor: CGFloat
-
当你需要画图的时候,使用
var bounds: CGRect
,这是一个包含了你自己的坐标系统的画图空间的矩形,也就是说,它在你自己的画图空间里,由你在view中的代码实现来定义bounds.origin。 -
那么UIView在哪里?
var center: CGPoint // UIView的中心坐标(在它的superview的坐标系统中)
var frame: CGRect // 包含UIView的矩形(在它的superview的坐标系统中)
。 frame指的是你的view在superview中的位置,也就是说这是放在superview的坐标系统中的,而不是你的画图坐标系统中。
。 center相应的,也是指的superview中的center,和你的画图空间并没有毛线关系~当你画图的时候用bounds就好啦。看代码理解也许会比较清晰一点,可以以上面提到的demo为例,
。 frame和bounds的宽高也不同,因为view可以旋转。
创建一个view
在上面提到的demo中,我们做的是一个笑脸,而iOS并没有smileview这个东西,所以我们要自己建。我们使用的是一般view(generic view),就当是一般类吧,可以拿来随意发挥。
你可以在object library里轻松找到它,或者搜“view“
e.g.
// 假设这段代码在UIViewController中
let labelRect = CGRect(x: 20, y: 20, width: 10, height: 10)
let label = UILabel(frame: labelRect) // UILabel是UIView的子类,所以那些UILabel中的那些字也是一笔一画画出来的。。
label.text = "hello"
view.addSubview(label)
自定义Views
-
何时需要自定义UIView的子类
-
我想自定义绘图
-
我想以一些特殊的方式处理点击事件(这里不同于button或者slider)
-
至于画图,只需要创建一个UIView的子类,然后override drawRect:
-
override func drawRect(regionThatNeedsToBeDrawn: CGRect)
-
如之前所说,你可以画在regionThatNeedsToBeDrawn的范围之外。
- UIView的边界定义了我们整个画图区域,region只是一个子区域 -
!!!绝对不能直接调用drawRect,它是系统的专属天使。但是当你需要画图怎么办呢?告诉系统,你要用这个方法了,用以下的语句:
setNeedsDisplay()
setNeedsDisplayInRect(regionThatNeedsToBeRedrawn: CGRect)
iOS会在一个适当的时机调用drawRect,比如你的破事全部决定了之后,一次性将要重画(redraw)的东西全部drawRect。
-
那么我怎么实现drawRect呢?
-
你可以使用一个类C的API(不是面向对象的),叫Core Graphics,swift是完全面相对象的,掺和进来这玩意应该不是好事吧 ==
-
你还可以使用面向对象的类-UIBezierPath,这也是我们在demo中所使用的。
-
Core Graphics的一些基本概念
- 使用
UIGraphicsGetCurrentContext()
来获取一些能在drawRect中使用的文本内容(context,打印的,屏幕外的缓存中的, etc.) - 创建路径(线,圆)
- 设定一些相关属性,比如颜色,字体,线宽之类的。
-
stroke
或者fill
以上创建的路径。
-
UIBezierPath
和上面那个家伙差不多,只是UIBezierPath自动知道context。 -
定义一个路径
-
创建一个UIBezierPath
let path = UIBezierPath()
- 加几条线,或者圆弧
path.moveToPoint(CGPoint(x: 80, y: 50))
path.addLineToPoint(CGPoint(x:140, y: 150))
path.addLineToPoint(CGPoint(x: 10, y: 150))
- 可以闭合路径
path.closePath()
此时就已经得到了一个可爱的三角形。但是并没有画出来
-
注意, 你仅仅将上面创建的线条放在drawRect中,并不会显示什么。必须要设置相应的属性(颜色,线宽等等),然后
stroke
/fill
,才能在屏幕上显示出来。
UIColor.greenColor().setFill() // 注意这是UIColor中的方法
UIColor.redColor().setStroke() // 注意这是UIColor中的方法
path.lineWidth = 3.0 // 这是UIBezierPath中的属性
path.fill() // UIBezierPath中的方法
path.stroke() // UIBezierPath中的方法
- 你也可以用UIBezierPath画很多其它类型的图,比如:
let roundRect = UIBezierPath(roundedRect: CGRect, cornerRadius: CGFloat)
let oval = UIBezierPath(ovalInRect: aCGRect)
- 也可以圆滑夹角,就是给每个角增加一个弧度。使用
addClip()
- 也可以进行碰撞监测,就是检测一个点是不是在闭合路径里面。
func containsPoint(CGPoint) -> Bool
UIColor
- 对于很多普通颜色来讲,有很多类方法可以使用,比如
let green = UIColor.greenColor()
,可以用RGB, HSB, 甚至可以使用某些样式(比如图片)。 - UIView的背景色,
var backgroundColor: UIColor
- 颜色可以有alpha,可以设置透明度
let transparentYellow = UIColor.yellowColor().colorWithAlphaComponent(0.5) // 这是个instance method, 不是type method
alpha: 0.0(完全透明) - 1.0(完全不透明)
-
如果想要在程序中设置颜色的透明度,必须设置
var opaque = false
, 来让系统知道这些都不是不透明的,也就是你要开始设置透明度了。 -
也可以设置整个UIView的透明度
var alpha: CGFloat
通过alpha,可是设计一个渐出(慢慢消失)的动画。
- 也可以隐藏一个view,通过
var hidden: Bool
显示(画)文本
- 一般我们使用UILabel来显示文本,但我们有时候还是需要在drawRect中直接显示文本
- 在drawRect中,可以使用NSAttributedString
AttributedString就是每个string中的字符,都有一个字典存储相应的每个字符的属性信息,比如颜色,字体等。
let text = NSAttributedString("hello")
text.drawAtPoint(aCGPoint)
let textSize: CGSize = text.size //这个字符串需要多少空间
- NSAttributedString的两个弊端
- 我们知道,var具有可变性(mutability),let没有。但是在NSAttributedString中,不管是var还是let,都是不可变的(immutable)。因为这是个objective-c的类,所以swift中还是有点缺陷。要想做到可变形,你可以使用另一个类,NSMutableAttributedString,如下语句:
let mutableString = NSMutableAttributedString("some text")
注意,NSAttributedString不是String,也不是NSString.
- swift的string是unicode的,比oc的强大太多,所以它们的string也不一样,在NSAttributedString中,需要使用NSRange,注意这不是Range,这是oc里的NSRange。所以在使用的时候,需要将range转换成NSRange(可自动完成),然后才能在NSAttributedString中用NSRange。
func setAttributes(attributes: Dictionary, range: NSRange)
func addAttributes(attributes: Dictionary, range: NSRange)
在Attributes中可以放以下这些dictionary:
NSForegroundColorAttributeName: UIColor
NSStrokeWidthAttributeName: UIFloat
NSFontAttributeName: UIFont
字体
字体在苹果的产品中占有非常重要的地位,毕竟艺术品。
- 使用字体的最好的方式
- 对于文本内容,采用preferred font
static func preferredFontForTextStyle(UIFontTextStyle) -> UIFont
UIFontTextStyle.Headline
UIFontTextStyle.Body
UIFontTextStyle.Footnote
- 对于按钮之类的,使用系统字体(system fonts)
static func systemFontOfSize(pointSize: CGFloat) -> UIFont
static func boldSystemFontOfSize(pointSize: CGFloat) -> UIFont
在用户的文本信息中,不要使用这些系统字体
- 其它方式:UIFont和UIFontDescriptor
显示图片
有个UILabel相类似的类,UIImageView,当然你还是有可能想在drawRect中直接显示图片的,那么。。。
- 创建UIImage -
let image: UIImage? = UIImage(named: "foo")
,optional是因为有可能没有图片 - 从系统文件中创建(files in the file system)
let image: UIImage? = UIImage(contentsOfFile: aString)
let image: UIImage? = UIImage(data: anNSData) // jpg, png, tiff, etc.
- 开始画
let image: UIImage = ...
image.drawAtPoint(aCGPoint) // 图片的左上角
image.drawInRect(aCGRect) // 将图片按比例扩充到aCGRect中
image.drawAsPatternInRect(aCGRect) //将图片平铺到aCGRect中
欢迎转载,转载请注明出处。访问我的个人主页,了解更多。
网友评论