Swift学习笔记2 - Views

前言

这是斯坦福大学在线课程-Developing iOS 9 Apps with Swift 的学习内容,在iTunes上就可以搜到,有兴趣的小伙伴可以一起学习一起进步哈!这里我将一些我认为的关键知识点摘录在我的学习笔记系列中。之前用英文写了几篇,感觉没什么人看,其实个人认为用英文学再用英文写其实更简单方便一些。

Demo

首先,是一张萌蠢的笑脸,你要是看着不舒服,你可以从我的github中下载相应代码,或者自己敲哈,让它哭也成。

Swift学习笔记2 - Views_第1张图片
smile

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

有两种不同的方式:

  1. init(frame: CGRect) // 由代码创建生成
  2. 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的坐标系统

  • 左上是初始点。如下图:


    Swift学习笔记2 - Views_第2张图片
  • 注意,单位是,不是像素,点不是像素,点等于几个像素。比如在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的一些基本概念

  1. 使用UIGraphicsGetCurrentContext()来获取一些能在drawRect中使用的文本内容(context,打印的,屏幕外的缓存中的, etc.)
  2. 创建路径(线,圆)
  3. 设定一些相关属性,比如颜色,字体,线宽之类的。
  4. 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中,并不会显示什么。必须要设置相应的属性(颜色,线宽等等),然后strokefill,才能在屏幕上显示出来。
UIColor.greenColor().setFill() // 注意这是UIColor中的方法
UIColor.redColor().setStroke() // 注意这是UIColor中的方法
path.lineWidth = 3.0 // 这是UIBezierPath中的属性
path.fill() // UIBezierPath中的方法
path.stroke() // UIBezierPath中的方法
Swift学习笔记2 - Views_第3张图片
  • 你也可以用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的两个弊端
  1. 我们知道,var具有可变性(mutability),let没有。但是在NSAttributedString中,不管是var还是let,都是不可变的(immutable)。因为这是个objective-c的类,所以swift中还是有点缺陷。要想做到可变形,你可以使用另一个类,NSMutableAttributedString,如下语句:
let mutableString = NSMutableAttributedString("some text")

注意,NSAttributedString不是String,也不是NSString.

  1. 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中

欢迎转载,转载请注明出处。访问我的个人主页,了解更多。

你可能感兴趣的:(Swift学习笔记2 - Views)