
前言
本课以上节课的代码为基础
课程概要
- 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

从上节课知道,我们明明是在FaceView绘制的笑脸,为什么能够在 storyboard中显示,并且属性还可以在面板中更改。这里就需要使用IBDesignable和IBInspactable。通过将@IBDesignable添加到FaceView前,可以使FaceView显示在Interface Builder中。通过将@IBInspectable添加在每个属性前,可以在Interface Builder中显示属性。
IBDesignable
IBDesignable在Xcode6亮相。当应用到UIView或NSView子类中的时候,@IBDesignable让Interface 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中访问。

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
小结
英语水平有限,如有错误,欢迎指正。