接着上面的文章看看這個 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}) } } }