接着上面的文章看看这个 TODO 应用的代码,接下来看下 TableViewCell
类。git
在 Cell 里首先是定义了一个委托,用来对 Cell 进行操做:github
protocol TableViewCellDelegate { func toDoItemDeleted(todoItem: ToDoItem) func cellDidBeginEditing(editingCell: TableViewCell) func cellDidEndEditing(editingCell: TableViewCell) }
Cell 的数据来源是这个 todoItem 对象。定义以下:swift
var toDoItem: ToDoItem? { didSet { label.text = toDoItem!.text label.strikeThrough = toDoItem!.completed itemCompleteLayer.hidden = !label.strikeThrough } }
能够看到这个属性在 didSet 以后会刷新 UI。app
注意在 init 中有这么几个点:ide
由于右侧的打钩按钮和左侧的打叉按钮除了内容不一样,基本的形式 (背景颜色、字体、文字颜色) 是同样的,而除了当前方法又不会有其余方法调用这个生产 UILabel 的方法,因此定义了一个内部方法生产 UILabel :字体
func createCueLabel() -> UILabel { let label = UILabel(frame: CGRect.nullRect) label.textColor = UIColor.whiteColor() label.font = UIFont.boldSystemFontOfSize(32.0) label.backgroundColor = UIColor.clearColor() return label }
高亮效果并非用切图实现的,而是经过代码设置色值和色值所在的位置实现的。每一个 Cell 的高亮效果是这样写的:code
gradientLayer.frame = bounds let color1 = UIColor(white: 1.0, alpha: 0.2).CGColor as CGColorRef let color2 = UIColor(white: 1.0, alpha: 0.1).CGColor as CGColorRef let color3 = UIColor.clearColor().CGColor as CGColorRef let color4 = UIColor(white: 0.0, alpha: 0.1).CGColor as CGColorRef gradientLayer.colors = [color1, color2, color3, color4] gradientLayer.locations = [0.0, 0.01, 0.95, 1.0] layer.insertSublayer(gradientLayer, atIndex: 0)
若是搞不懂这些代码的做用,改为这样再运行就能够理解了:对象
// gradient layer for cell gradientLayer.frame = bounds let color1 = UIColor(white: 1.0, alpha: 1.0).CGColor as CGColorRef let color2 = UIColor(white: 1.0, alpha: 0.0).CGColor as CGColorRef gradientLayer.colors = [color1, color2] gradientLayer.locations = [0.0, 1.0] layer.insertSublayer(gradientLayer, atIndex: 0)
当一个 item 完成的时候,会把它的颜色设置为绿色标记为已经完成。这个绿色也是经过 CALayer 实现的,一开始初始化的时候设置为隐藏:get
// add a layer that renders a green background when an item is complete itemCompleteLayer = CALayer(layer: layer) itemCompleteLayer.backgroundColor = UIColor(red: 0.0, green: 0.6, blue: 0.0, alpha: 1.0).CGColor itemCompleteLayer.hidden = true layer.insertSublayer(itemCompleteLayer, atIndex: 0)
手势应该算是这个应用的一个亮点,在 init 里面定义了手势的识别:animation
var recognizer = UIPanGestureRecognizer(target: self, action: "handlePan:") recognizer.delegate = self addGestureRecognizer(recognizer)
首先先经过委托判断是否应该识别这个手势:
override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool { if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer { let translation = panGestureRecognizer.translationInView(superview!) if fabs(translation.x) > fabs(translation.y) { return true } return false } return false }
能够看到是 X 偏移量大于 Y 的偏移量便可继续识别。
而后看下具体的识别过程:
//MARK: - 横向手势识别 func handlePan(recognizer: UIPanGestureRecognizer) { // 1 if recognizer.state == .Began { // 刚开始的时候,记录手势的位置 originalCenter = center } // 2 if recognizer.state == .Changed { let translation = recognizer.translationInView(self) center = CGPointMake(originalCenter.x + translation.x, originalCenter.y) // 判断是否达到屏幕的一半,从而选择是否触发 deleteOnDragRelease = frame.origin.x < -frame.size.width / 2.0 completeOnDragRelease = frame.origin.x > frame.size.width / 2.0 // 隐藏左右标记 let cueAlpha = fabs(frame.origin.x) / (frame.size.width / 2.0) tickLabel.alpha = cueAlpha crossLabel.alpha = cueAlpha // 根据判断结果刷新界面 tickLabel.textColor = completeOnDragRelease ? UIColor.greenColor() : UIColor.whiteColor() crossLabel.textColor = deleteOnDragRelease ? UIColor.redColor() : UIColor.whiteColor() } // 3 if recognizer.state == .Ended { let originalFrame = CGRect(x: 0, y: frame.origin.y, width: bounds.size.width, height: bounds.size.height) if deleteOnDragRelease { if delegate != nil && toDoItem != nil { // 通知委托删除 delegate!.toDoItemDeleted(toDoItem!) } } else if completeOnDragRelease { if toDoItem != nil { toDoItem!.completed = true } label.strikeThrough = true itemCompleteLayer.hidden = false UIView.animateWithDuration(0.2, animations: {self.frame = originalFrame}) } else { UIView.animateWithDuration(0.2, animations: {self.frame = originalFrame}) } } }