斯坦福iOS9公开课总结五:InterfaceBuilder

前言

本课以上节课的代码为基础

课程概要

  • Interface Builder Demo
    storyboard中,绘制和编写你的UIViews
  • The FaceViewController MVC`s Model
  • Gestures
    获取手势输入。
  • Demo: Modifying the facial expression
    滑动,轻拍,旋转等。
  • Multiple MVCs
    tabBar, Navigation and Split View Controllers

Interface Builder Demo

补充

本课在上节课的demo基础上进行编写,如有疑问请看上篇文章。上节课完成笑脸的绘制,现在我们给笑脸加眉毛,实现原理跟画眼睛一样,主要是计算坐标位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
     *  @brief 画眉毛
     *
     *  @param eye枚举类型,表示左右眼
     *
     *  @return 返回贝塞尔曲线
     */
    private func pathForBrow(eye: Eye) -> UIBezierPath {
        var tilt = eyeBrowTilt;
        switch eye {
        case .Left:
            tilt *= -1.0
        case .Right:
            break
        }
        var browCenter = getEyeCenter(eye: eye)
        browCenter.y -= skullRadius / Ratios.SkullRadiusToBrowOffset
        let eyeRadius = skullRadius / Ratios.SkullRadiusToEyeRadius
        let tiltOffset = CGFloat(max(-1, min(tilt, 1))) * eyeRadius / 2
        let browStart = CGPoint(x: browCenter.x - eyeRadius, y: browCenter.y - tiltOffset)
        let browEnd = CGPoint(x: browCenter.x + eyeRadius, y: browCenter.y + tiltOffset)
        let path = UIBezierPath()
        path.move(to: browStart)
        path.addLine(to: browEnd)
        path.lineWidth = lineWidth;
        return path
    }

注意需要在Ratios中添加SkullRadiusToBrowOffset。另外,更新后的代码将一些变量定义为属性。例如:线条宽度,线条颜色,眉毛形状,眼睛,嘴巴形状等。

IBDesignable & IBInspactable

FaceIt.gif

从上节课知道,我们明明是在FaceView绘制的笑脸,为什么能够在 storyboard中显示,并且属性还可以在面板中更改。这里就需要使用IBDesignableIBInspactable。通过将@IBDesignable添加到FaceView前,可以使FaceView显示在Interface Builder中。通过将@IBInspectable添加在每个属性前,可以在Interface Builder中显示属性。

IBDesignable

IBDesignableXcode6亮相。当应用到UIViewNSView子类中的时候,@IBDesignableInterface Builder直接渲染视图。每次更改完视图不必编译运行就可以直接显示。
使用很简单只要在类名前添加@IBDesignable前缀(Objective-C里的IB_DESIGNABLE宏)。
此外,一些问题可以避免在编译和运行整个程序来调试。调试方法,在代码中设置断点,在Interface Builder中选择视图,并选择Editor -> Debug Selected Views

有时我们需要使用模拟数据,可以使用方法:

  • prepareForInterfaceBuilder(): 此方法与你代码的其余部分一起编译,但只有当视图正在准备在 Interface Builder 显示时执行。
  • TARGET_INTERFACE_BUILDER:#if TARGET_INTERFACE_BUILDER
     预处理宏在 Objective-C 或 Swift 下都是工作的,它会视情况编译正确代码:

 

1
2
3
4
5
#if !TARGET_INTERFACE_BUILDER 
// this code will run in the app itself
#else
// this code will execute only in IB
#endif

IBInspectable

IBInspectable属性提供了访问自定义运行时属性的方法。在Identity inspector中访问。

identity inspector.png

FacialExpression

上面我们已经设计FaceView(View),现在我们来设计FacialExpression(Model)。以下是FacialExpression全部代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import Foundation

struct FacialExpression {
    
    // 眼睛样式
    enum Eyes: Int {
        case Open
        case Closed
        case Squinting
    }
    //眉毛样式
    enum EyeBrows: Int {
        case Relaxed
        case Normal
        case Furrowed
        
        func moreRelaxedBrow() -> EyeBrows {
            return EyeBrows(rawValue: rawValue - 1) ?? .Relaxed
        }
        func moreFurrowBrow() -> EyeBrows {
            return EyeBrows(rawValue: rawValue + 1) ?? .Furrowed
        }
    }
    //嘴巴样式
    enum Mouth: Int {
        case Frown
        case Smirk
        case Neutral
        case Grin
        case Smile
        func sadderMouth() -> Mouth {
            return Mouth(rawValue: rawValue - 1) ?? .Frown
        }
        func happierMouth() -> Mouth {
            return Mouth(rawValue: rawValue + 1) ?? .Smile
        }
    }
    
    var eyes: Eyes
    var eyebrows: EyeBrows
    var mouth: Mouth
}

FaceViewController

接下来实现FaceViewController(Controller)。在Controller中通过Model提供的数据更改View中的显示样式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import UIKit

class FaceViewController: UIViewController {
    //创建expression对象,当内容改变是更新UI
    var expression = FacialExpression(eyes: .Closed, eyebrows: .Normal, mouth: .Smirk) {
        didSet {
            updateUI()
        }
    }
    
    //获取storyboard中的View
    @IBOutlet weak var faceView: FaceView! {
        didSet {
            updateUI()
        }
    }
    
    private var mouthCurvature = [FacialExpression.Mouth.Frown: -1.0, .Grin: 0.5, .Smile: 1.0, .Smirk: -0.5, .Neutral: 0.0]
    private var eyeBrowTilts = [FacialExpression.EyeBrows.Relaxed: 0.5, .Furrowed: -0.5, .Normal: 0.0]
    
    //更新UI, 眼睛,眉毛,嘴巴
    private func updateUI() {
        switch expression.eyes {
        case .Open:
            faceView.eyeOpen = true
        case .Closed:
            faceView.eyeOpen = false
        case .Squinting:
            faceView.eyeOpen = false
        }
        faceView.mouthCurvature = mouthCurvature[expression.mouth] ?? 0.0
        faceView.eyeBrowTilt = eyeBrowTilts[expression.eyebrows] ?? 0.0
        
    }
}

Guestures && Demo

iOS系统在3.2以后,提供了一些常用手势:

  • UITapGestureRecognizer(轻拍)
  • UISwipeGestureRecognizer(轻扫)
  • UIPinchGestureRecognizer(捏合)
  • UIPanGestureRecognizer (拖动)

拖动手势三个方法

  • func translation(UIView) ->CGPoint

  • func setTranslation(CGPoint, UIView) //允许我们reset

  • func velocity(UIView) -> CGPoint //移动速度(points/second)

  • UIRotationGestureRecognizer (旋转)

  • UILongPressGestureRecognizer (长按)
    另外,我们可以通过UIGestureRecognizer类,实现自定义的手势。

UIGestureRecognizer类中,提供state如下:
possible, began,changed,ended,cancelled,failed

Demo中,只添加了捏合,轻扫,轻拍手势。其他手势自行练习。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//获取storyboard中的View
    @IBOutlet weak var faceView: FaceView! {
        didSet {
            // 捏合手势,缩放笑脸大小
            faceView.addGestureRecognizer(UIPinchGestureRecognizer(target: faceView, action: #selector(FaceView.changeScale(recognizer:))))
            
            //轻扫手势,向上笑脸
            let happierSwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(FaceViewController.increaseHappiness))
            happierSwipeGestureRecognizer.direction = .up
            faceView.addGestureRecognizer(happierSwipeGestureRecognizer)
            
            //向下哭脸
            let sadderSwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(FaceViewController.reduceSadder))
            sadderSwipeGestureRecognizer.direction = .down
            faceView.addGestureRecognizer(sadderSwipeGestureRecognizer)
            
            updateUI()
        }
    }
 // 添加轻拍手势,更改眼睛形状, 通过在Interface Builder中添加手势
    @IBAction func toggleEyes(_ recognizer: UITapGestureRecognizer) {
        if recognizer.state == .ended {
            switch expression.eyes {
            case .Closed:
                expression.eyes = .Open
            case .Open:
                expression.eyes = .Closed
            case .Squinting:
                break
            }
        }
    }
    func increaseHappiness() {
        expression.mouth = expression.mouth.happierMouth()
    }
    func reduceSadder() {
        expression.mouth = expression.mouth.sadderMouth()
    }

Multiple MVC`s

  • UITabBarViewController
  • UINavigationViewController
  • UISplitViewController

小结

英语水平有限,如有错误,欢迎指正。