1. 程式人生 > >[Swift通天遁地]二、表格表單-(7)電子郵件Mail:實現單元格左右滑動調出功能按鈕

[Swift通天遁地]二、表格表單-(7)電子郵件Mail:實現單元格左右滑動調出功能按鈕

本文將演示對單元格進行擴充套件,當手指在單元格左右滑動時,彈出不同的功能選單。

Github專案:【MGSwipeTableCell】

下載該專案的原始碼。資料夾【demo】->資料夾【MailAppDemoSwift】->資料夾【MailAppDemoSwift】

->雙擊檔案【MailAppDemoSwift。xcodeproj】開啟示例工程。

選擇該專案中的幾個檔案,拖動到自己的開發專案中。按住【Shift】,選擇

【MGSwipeButton.h】

【MGSwipeButton.m】

【MGSwipeTableCell.h】

【MGSwipeTableCell.m】

按下【Command】,以選擇其他不相鄰的檔案。

【MailViewController.swift】

【MailTableCell.swift】

【ObjCBridgingHeader.h】

將上面選擇的7個檔案拖動到自己的專案中。

->保持預設的設定選項,點選【Finish】

接著對專案進行一些設定,以引入橋接檔案。

點選專案名稱【DemoApp】->【Buildings】->橋接檔案配置區域【Object-C Bridging Header】

->在配置選項中雙擊,開啟配置視窗。

->在配置視窗中,輸入剛剛匯入的橋接檔案的名稱:【DemoApp/ObjCBridgingHeader.h】

在專案導航區,開啟檢視控制器的程式碼檔案【ViewController.swift】

現在開始編寫程式碼,建立一個可通過左右滑動,來調出功能按鈕的表格。

  1 import UIKit
  2 
  3 //新增一個郵件資料類,這個類將用來表示表格中的資料
  4 class MailData
  5 {
  6     //給類新增四個屬性:
  7     //1.來源
  8     var from: String!
  9     //2.主題
 10     var subject: String!
 11     //3.內容
 12     var message: String!
 13
//4.日期 14 var date: String! 15 //新增兩個屬性 16 //1.郵件是否已被閱讀 17 var read = false 18 //2.郵件是否擁有標記 19 var flag = false 20 } 21 22 //建立一個別名,表示功能按鈕被點選時所執行的方法的型別。 23 typealias MailActionCallback = (_ cancelled: Bool, _ deleted: Bool, _ actionIndex: Int) -> Void 24 25 //使當前的檢視控制器類,遵循: 26 //1.表格的資料來源協議UITableViewDataSource 27 //2.表格檢視代理協議UITableViewDelegate 28 //3.滑動表格單元格代理協議 29 //4.動作表單協議 30 class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, MGSwipeTableCellDelegate, UIActionSheetDelegate 31 { 32 //新增一個表格檢視型別的變數,作為當前類的一個屬性 33 var tableView: UITableView! 34 //建立一個郵件資料型別的陣列,作為表格的資料來源 35 var demoData = [MailData]() 36 //使用剛剛建立的別名,建立一個動作型別 37 var actionCallback: MailActionCallback? 38 39 //新增一個方法,用來設定表格的資料來源 40 func prepareDemoData() 41 { 42 //建立第一個字串陣列常量,作為郵件的來源 43 var from = [ 44 "Vincent", 45 "Mr Glass", 46 "Marsellus", 47 "Ringo", 48 "Sullivan" 49 ] 50 51 //建立第二個字串陣列常量,作為郵件的主題 52 var subjects = [ 53 "You think water moves fast?", 54 "They called me Mr Glass", 55 "The path of the righteous man", 56 "Do you see any Teletubbies in here?", 57 "Now that we know who you are" 58 ] 59 60 //建立第三個字串陣列常量,作為郵件的資訊 61 var messages = [ 62 "You should see ice. It moves like it has a mind. ", 63 "And I will strike down upon thee with great vengeance and furious anger.", 64 "Look, just because I don't be givin' no man a foot massage don't make it right.", 65 "No? Well, that's what you see at a toy store.", 66 "In a comic, you know how you can tell who the arch-villain's going to be?" 67 ] 68 69 //通過一個迴圈,遍歷資訊陣列 70 for i in 0 ..< messages.count 71 { 72 //建立一個郵件資料物件 73 let mail = MailData() 74 //從陣列中載入相應的內容 75 mail.from = from[i] 76 //並依次設定郵件資料物件的各個屬性 77 mail.subject = subjects[i] 78 mail.message = messages[i] 79 //設定郵件資料物件的時間屬性 80 mail.date = String(format: "11:%d", arguments: [43 - i]) 81 //將郵件資料物件,新增到表格的資料來源陣列當中 82 demoData.append(mail) 83 } 84 } 85 86 //新增一個方法 87 //用來從資料來源陣列中,根據單元格的位置獲得相應的資料 88 func mailForIndexPath(_ path: IndexPath) -> MailData 89 { 90 //根據單元格的行號,返回資料來源陣列中的資料 91 return demoData[(path as NSIndexPath).row] 92 } 93 94 //新增一個方法 95 //用來響應單元格中的刪除按鈕被點選時的事件 96 func deleteMail(_ path:IndexPath) 97 { 98 //從資料來源陣列中刪除指定位置的資料 99 demoData.remove(at: (path as NSIndexPath).row) 100 //從表格中刪除指定的單元格 101 tableView.deleteRows(at: [path], with: .left) 102 } 103 104 //新增一個方法 105 //當郵件的狀態改變時呼叫此方法 106 //例如郵件從未讀轉換為已讀 107 func updateCellIndicator(_ mail: MailData, cell: MailTableCell) 108 { 109 //建立兩個顏色變數,作為標識郵件狀態的圖示的顏色 110 var color: UIColor 111 var innerColor : UIColor? 112 113 //根據郵件不同的狀態,設定郵件不同的顏色 114 if !mail.read && mail.flag 115 { 116 //當郵件未讀並有標識時 117 //設定標識圖示的標識顏色 118 color = UIColor.init(red: 1.0, green: 149/255.0, blue: 0.05, alpha: 1.0) 119 //設定標識圖示內部的顏色 120 innerColor = UIColor.init(red: 0.0, green: 122/255.0, blue: 1.0, alpha: 1.0) 121 } 122 else if mail.flag 123 { 124 //當郵件具有標識時, 125 //設定標識圖示的標識顏色 126 color = UIColor.init(red: 1.0, green: 149/255.0, blue: 0.05, alpha: 1.0) 127 } 128 else if mail.read 129 { 130 //當郵件處於已讀狀態時, 131 //設定標識圖示的顏色為無色 132 //即在視覺上隱藏該圖示 133 color = UIColor.clear 134 } 135 else 136 { 137 //設定郵件在其他狀態下的預設顏色 138 color = UIColor.init(red: 0.0, green: 122/255.0, blue: 1.0, alpha: 1.0) 139 } 140 141 //設定標識圖示的顏色 142 cell.indicatorView.indicatorColor = color 143 //設定標識圖示內部的顏色 144 cell.indicatorView.innerColor = innerColor 145 } 146 147 //新增一個方法,用來彈出一個動作表單 148 func showMailActions(_ mail: MailData, callback: @escaping MailActionCallback) 149 { 150 //設定動作屬性的值 151 actionCallback = callback 152 153 //初始化一個動作表單,依次設定相關引數 154 let sheet = UIActionSheet.init(title: "Actions", //標題 155 delegate: self,//代理 156 cancelButtonTitle: "Cancel",//取消按鈕的標題 157 destructiveButtonTitle: "Trash")//銷燬按鈕的標題 158 159 //往動作表單中依次新增三個按鈕, 160 //並設定三個按鈕的標題文字 161 sheet.addButton(withTitle: "Mark as unread") 162 sheet.addButton(withTitle: "Mark as read") 163 sheet.addButton(withTitle: "Flag") 164 165 //在根檢視中顯示動作表單 166 sheet.show(in: self.view) 167 } 168 169 //新增一個代理方法,用來監聽動作表單中的選項被點選時的事件 170 func actionSheet(_ actionSheet: UIActionSheet, clickedButtonAt index: Int) 171 { 172 //獲得當前類的屬性的值 173 if let action = actionCallback 174 { 175 //根據點選的不同選項,執行不同的操作 176 action(index == actionSheet.cancelButtonIndex, 177 index == actionSheet.destructiveButtonIndex, 178 index) 179 actionCallback = nil 180 } 181 } 182 183 //新增一個方法,用來根據不同的標識狀態,返回不同的文字內容 184 func readButtonText(_ read:Bool) -> String 185 { 186 return read ? "Mark as\nunread" : "Mark as\nread" 187 } 188 189 190 override func viewDidLoad() 191 { 192 super.viewDidLoad() 193 194 //初始化一個矩形區域,作為表格的顯示區域 195 let frame = CGRect(x: 0, y: 20, width: 320, height: 548) 196 //建立一個指定顯示區域的表格檢視 197 tableView = UITableView(frame: frame, style: UITableViewStyle.plain) 198 199 //設定表格物件的資料來源為當前的檢視控制器物件 200 tableView.delegate = self 201 //設定表格物件的代理為當前的檢視控制器物件 202 tableView.dataSource = self 203 //將表格檢視新增到根檢視中 204 view.addSubview(tableView) 205 206 //呼叫方法,用來初始化表格的資料來源 207 prepareDemoData() 208 } 209 210 //新增一個代理方法,用來設定表格的行數 211 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 212 { 213 //在此設定表格的行數為陣列的長度 214 return demoData.count 215 } 216 217 //新增一個代理方法,用來初始化或複用表格中的單元格 218 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 219 { 220 //建立一個字串常量,作為單元格的複用標識 221 let identifier = "MailCell" 222 //根據複用標識,從表格中獲得可以複用的單元格 223 var cell: MailTableCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? MailTableCell 224 225 //如果沒有可以複用的單元格 226 if cell == nil 227 { 228 //則初始化一個預設樣式的單元格,並設定單元格的複用標識 229 cell = MailTableCell(style: UITableViewCellStyle.default, reuseIdentifier: identifier) 230 } 231 //設定單元格的代理物件為當前的檢視控制器物件 232 cell.delegate = self 233 234 //根據當前單元格的行號,獲得陣列中對應的郵件資料 235 let data: MailData = demoData[(indexPath as NSIndexPath).row] 236 //設定單元格的郵件來源標籤的文字內容 237 cell!.mailFrom.text = data.from 238 //依次設定其他標籤的相關內容 239 cell!.mailSubject.text = data.subject 240 cell!.mailMessage.text = data.message 241 cell!.mailTime.text = data.date 242 243 //呼叫方法,根據郵件的狀態,重新整理單元格的視覺效果 244 updateCellIndicator(data, cell: cell) 245 246 //最後返回設定好的單元格物件 247 return cell 248 } 249 250 //新增一個代理方法,用來設定單元格的高度為110 251 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 252 { 253 return 110 254 } 255 256 //新增一個代理方法,設定單元格允許滑動的手勢 257 func swipeTableCell(_ cell: MGSwipeTableCell, canSwipe direction: MGSwipeDirection) -> Bool 258 { 259 return true 260 } 261 262 //新增一個代理方法,設定當單元格上有滑動手勢時,所顯示的功能按鈕,以及功能按鈕顯示的視覺效果 263 func swipeTableCell(_ cell: MGSwipeTableCell, swipeButtonsFor direction: MGSwipeDirection, swipeSettings: MGSwipeSettings, expansionSettings: MGSwipeExpansionSettings) -> [UIView]? 264 { 265 //設定功能按鈕的顯示方式為三維旋轉效果。 266 //共有:邊緣、靜態、拖動、中心裁切、三維旋轉等五種效果 267 swipeSettings.transition = MGSwipeTransition.rotate3D 268 //設定功能按鈕的索引為0 269 expansionSettings.buttonIndex = 0 270 271 //獲得在當前單元格中,需要顯示的郵件內容 272 let mail = mailForIndexPath(tableView.indexPath(for: cell)!) 273 274 //處理當手勢為從左到右滑動時的情況 275 if direction == MGSwipeDirection.leftToRight 276 { 277 //設定在該手勢下,按鈕將以彈性的方式返回原來的位置 278 expansionSettings.fillOnTrigger = false 279 //設定觸發顯示功能按鈕的閾值大小,預設值為1.5 280 expansionSettings.threshold = 2 281 //初始化一個顏色常量,作為功能按鈕的背景顏色 282 let color = UIColor.init(red:0.0, green:122/255.0, blue:1.0, alpha:1.0) 283 284 //返回一個功能按鈕,並設定按鈕的標題、背景顏色和互動動作 285 return [ 286 MGSwipeButton(title: readButtonText(mail.read),//標題 287 backgroundColor: color,//背景顏色 288 callback: { (cell) -> Bool in//互動動作 289 //當該按鈕被點選時,將切換當前郵件的閱讀狀態 290 mail.read = !mail.read 291 //同時重新整理當前郵件所在單元格的外觀狀態 292 self.updateCellIndicator(mail, cell: cell as! MailTableCell) 293 //接著重新整理單元格的內容檢視 294 cell.refreshContentView() 295 //根據郵件的閱讀狀態的變化,重新整理被新增按鈕的標題文字 296 (cell.leftButtons[0] as! UIButton).setTitle(self.readButtonText(mail.read), for: UIControlState()) 297 298 //最後返回真,使功能按鈕自動隱藏,結束按鈕的點選事件 299 return true 300 }) 301 ] 302 } 303 else 304 { 305 //處理當手勢為從右到左滑動時的情況 306 307 //設定在該手勢下,按鈕將在觸發時填充單元格 308 expansionSettings.fillOnTrigger = true 309 //設定觸發顯示功能按鈕的閾值大小1.1,預設值為1.5 310 expansionSettings.threshold = 1.1 311 312 //設定按鈕的內邊距為15 313 let padding = 15 314 //初始化三個顏色常量,作為三個按鈕的背景顏色 315 let color1 = UIColor.init(red:1.0, green:59/255.0, blue:50/255.0, alpha:1.0) 316 let color2 = UIColor.init(red:1.0, green:149/255.0, blue:0.05, alpha:1.0) 317 let color3 = UIColor.init(red:200/255.0, green:200/255.0, blue:205/255.0, alpha:1.0) 318 319 //新增第一個功能按鈕,依次設定相關引數 320 let trash = MGSwipeButton(title: "Trash",//標題 321 backgroundColor: color1, //背景顏色 322 padding: padding, //內間距 323 callback: { (cell) -> Bool in//互動動作 324 //當該按鈕被點選時, 325 //將從表格中移除按鈕所在的單元格, 326 //並在陣列中移除該單元格的內容。 327 self.deleteMail(self.tableView.indexPath(for: cell)!) 328 return false 329 }) 330 331 //新增第二個功能按鈕,依次設定相關引數 332 let flag = MGSwipeButton(title: "Flag",//標題 333 backgroundColor: color2,//背景顏色 334 padding: padding, //內間距 335 callback: { (cell) -> Bool in//互動動作 336 //獲得在當前單元格中,需要顯示的郵件內容 337 let mail = self.mailForIndexPath(self.tableView.indexPath(for: cell)!) 338 //更改郵件的標識狀態 339 mail.flag = !mail.flag 340 //重新整理當前郵件所在單元格的外觀狀態 341 self.updateCellIndicator(mail, cell: cell as! MailTableCell) 342 //重新整理單元格的內容檢視 343 cell.refreshContentView() 344 345 return true 346 }) 347 348 //新增第三個功能按鈕,依次設定相關引數 349 let more = MGSwipeButton(title: "More", //標題 350 backgroundColor: color3,//背景顏色 351 padding: padding, //內間距 352 callback: { (cell) -> Bool in//互動動作 353 //獲得當前單元格在表格中的位置 354 let path = self.tableView.indexPath(for: cell)! 355 //獲得在當前單元格中,需要顯示的郵件內容 356 let mail = self.mailForIndexPath(path) 357 358 //建立一個動作表單,擁有:取消、刪除和索引三個選項 359 self.showMailActions(mail, callback: { (cancelled, deleted, index) in 360 //取消選項被點選時的情況 361 if cancelled 362 { 363 return 364 } 365 //刪除選項被點選時的情況 366 else if deleted 367 { 368 //此時刪除當前的單元格,以及陣列中的資料 369 self.deleteMail(path) 370 } 371 //索引選項被點選時的情況,當索引值為1時 372 else if index == 1 373 { 374 //更改郵件的閱讀狀態 375 mail.read = !mail.read 376 //根據更改後的閱讀狀態,重新整理當前單元格的標識圖示 377 self.updateCellIndicator(mail, cell: cell as! MailTableCell) 378 //同時重新整理單元格的內容檢視 379 cell.refreshContentView() 380 //根據郵件的閱讀狀態的變化,重新整理被新增按鈕的標題文字 381 (cell.leftButtons[0] as! UIButton).setTitle(self.readButtonText(mail.read), for: UIControlState()) 382 //然後以動畫的方式,隱藏功能按鈕 383 cell.hideSwipe(animated: true) 384 } 385 }) 386 //最後返回假,以保持功能按鈕的顯示狀態 387 return false 388 }) 389 //在方法的末尾,返回三個功能按鈕 390 return [trash, flag, more] 391 } 392 } 393 394 override func didReceiveMemoryWarning() { 395 super.didReceiveMemoryWarning() 396 // Dispose of any resources that can be recreated. 397 } 398 }