前言
本课以上节课的代码为基础
课程概要
- 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
小结
英语水平有限,如有错误,欢迎指正。