Swift 聯動-TableView 與 CollectionView 之間的聯動

rhqq0256 7年前發布 | 32K 次閱讀 Swift Apple Swift開發 UITableView

前言

之前用 Objective-C 寫了一篇聯動的 demo 和文章,后來有小伙伴私信我有沒有 Swfit 語言的,最近趁晚上和周末學習了一下 Swift 3.0 的語法,寫了一個 Swift 的 demo。

思路和 Objective-C 版本的聯動文章 一樣,實現的效果也是一樣。先來看下效果圖。

聯動.gif

正文

一、TableView 與 TableView 之間的聯動

下面來說下實現兩個 TableView 之間聯動的主要思路:

先解析數據裝入模型。

// 數據校驗
guard let path = Bundle.main.path(forResource: "meituan", ofType: "json") else { return }

guard let data = NSData(contentsOfFile: path) as? Data else { return }

guard let anyObject = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) else { return }

guard let dict = anyObject as? [String : Any] else { return }

guard let datas = dict["data"] as? [String : Any] else { return }

guard let foods = datas["food_spu_tags"] as? [[String : Any]] else { return }

for food in foods {

let model = CategoryModel(dict: food)
categoryData.append(model)

guard let spus = model.spus else { continue }
var datas = [FoodModel]()
for fModel in spus {
    datas.append(fModel)
}
foodData.append(datas)

}</code></pre>

定義兩個 TableView:LeftTableView 和 RightTableView。

fileprivate lazy var leftTableView : UITableView = {
   let leftTableView = UITableView()
   leftTableView.delegate = self
   leftTableView.dataSource = self
   leftTableView.frame = CGRect(x: 0, y: 0, width: 80, height: ScreenHeight)
   leftTableView.rowHeight = 55
   leftTableView.showsVerticalScrollIndicator = false
   leftTableView.separatorColor = UIColor.clear
   leftTableView.register(LeftTableViewCell.self, forCellReuseIdentifier: kLeftTableViewCell)
   return leftTableView
}()

fileprivate lazy var rightTableView : UITableView = { let rightTableView = UITableView() rightTableView.delegate = self rightTableView.dataSource = self rightTableView.frame = CGRect(x: 80, y: 64, width: ScreenWidth - 80, height: ScreenHeight - 64) rightTableView.rowHeight = 80 rightTableView.showsVerticalScrollIndicator = false rightTableView.register(RightTableViewCell.self, forCellReuseIdentifier: kRightTableViewCell) return rightTableView }()

func tableView( tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if leftTableView == tableView { let cell = tableView.dequeueReusableCell(withIdentifier: kLeftTableViewCell, for: indexPath) as! LeftTableViewCell let model = categoryData[indexPath.row] cell.nameLabel.text = model.name return cell } else { let cell = tableView.dequeueReusableCell(withIdentifier: kRightTableViewCell, for: indexPath) as! RightTableViewCell let model = foodData[indexPath.section][indexPath.row] cell.setDatas(model) return cell }
}</code></pre>

先將左邊的 TableView 關聯右邊的 TableView:點擊左邊的 TableViewCell,右邊的 TableView 跳到相應的分區列表頭部。

func tableView( tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
   if leftTableView == tableView {
       return nil
   }
   let headerView = TableViewHeaderView(frame: CGRect(x: 0, y: 0, width: ScreenWidth, height: 20))
   let model = categoryData[section]
   headerView.nameLabel.text = model.name
   return headerView
}</code></pre> 
  

再將右邊的 TableView 關聯左邊的 TableView:標記一下RightTableView 的滾動方向,然后分別在 TableView 分區標題即將展示和展示結束的代理函數里面處理邏輯。

  • 1.在 TableView 分區標題即將展示里面,判斷當前的 tableView 是 RightTableView,RightTableView 滑動的方向向上,RightTableView 是用戶拖拽而產生滾動的(主要判斷RightTableView 是用戶拖拽的,還是點擊 LeftTableView 滾動的),如果三者都成立,那么 LeftTableView 的選中行就是 RightTableView 的當前 section。
  • 2.在 TableView 分區標題展示結束里面,判斷當前的 tableView 是 RightTableView,滑動的方向向下,RightTableView 是用戶拖拽而產生滾動的,如果三者都成立,那么 LeftTableView 的選中行就是 RightTableView 的當前 section-1。
// 標記一下 RightTableView 的滾動方向,是向上還是向下
func scrollViewDidScroll(_ scrollView: UIScrollView) {

let tableView = scrollView as! UITableView if rightTableView == tableView { isScrollDown = lastOffsetY < scrollView.contentOffset.y lastOffsetY = scrollView.contentOffset.y } }

// TableView分區標題即將展示 func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { // 當前的tableView是RightTableView,RightTableView滾動的方向向上,RightTableView是用戶拖拽而產生滾動的((主要判斷RightTableView用戶拖拽而滾動的,還是點擊LeftTableView而滾動的) if (rightTableView == tableView) && !isScrollDown && rightTableView.isDragging { selectRow(index: section) } }

// TableView分區標題展示結束 func tableView(_ tableView: UITableView, didEndDisplayingHeaderView view: UIView, forSection section: Int) { // 當前的tableView是RightTableView,RightTableView滾動的方向向下,RightTableView是用戶拖拽而產生滾動的((主要判斷RightTableView用戶拖拽而滾動的,還是點擊LeftTableView而滾動的) if (rightTableView == tableView) && isScrollDown && rightTableView.isDragging { selectRow(index: section + 1) } }

// 當拖動右邊TableView的時候,處理左邊TableView private func selectRow(index : Int) { leftTableView.selectRow(at: IndexPath(row: index, section: 0), animated: true, scrollPosition: .top) }</code></pre>

這樣就實現了兩個 TableView 之間的聯動,是不是很簡單。

二、TableView 與 CollectionView 之間的聯動

TableView 與 CollectionView 之間的聯動與兩個 TableView 之間的聯動邏輯類似。

下面說下實現 TableView 與 CollectionView 之間的聯動的主要思路:

還是一樣,先解析數據裝入模型。

// 數據校驗
guard let path = Bundle.main.path(forResource: "liwushuo", ofType: "json") else { return }

guard let data = NSData(contentsOfFile: path) as? Data else { return }

guard let anyObject = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) else { return }

guard let dict = anyObject as? [String : Any] else { return }

guard let datas = dict["data"] as? [String : Any] else { return }

guard let categories = datas["categories"] as? [[String : Any]] else { return }

for category in categories { let model = CollectionCategoryModel(dict: category) dataSource.append(model)

guard let subcategories = model.subcategories else { continue }

var datas = SubCategoryModel for subcategory in subcategories { datas.append(subcategory) } collectionDatas.append(datas) }</code></pre>

定義一個 TableView,一個 CollectionView。

fileprivate lazy var tableView : UITableView = {
   let tableView = UITableView()
   tableView.delegate = self
   tableView.dataSource = self
   tableView.frame = CGRect(x: 0, y: 0, width: 80, height: ScreenHeight)
   tableView.rowHeight = 55
   tableView.showsVerticalScrollIndicator = false
   tableView.separatorColor = UIColor.clear
   tableView.register(LeftTableViewCell.self, forCellReuseIdentifier: kLeftTableViewCell)
   return tableView
}()

fileprivate lazy var flowlayout : LJCollectionViewFlowLayout = { let flowlayout = LJCollectionViewFlowLayout() flowlayout.scrollDirection = .vertical flowlayout.minimumLineSpacing = 2 flowlayout.minimumInteritemSpacing = 2 flowlayout.itemSize = CGSize(width: (ScreenWidth - 80 - 4 - 4) / 3, height: (ScreenWidth - 80 - 4 - 4) / 3 + 30) flowlayout.headerReferenceSize = CGSize(width: ScreenWidth, height: 30) return flowlayout }()

fileprivate lazy var collectionView : UICollectionView = { let collectionView = UICollectionView(frame: CGRect.init(x: 2 + 80, y: 2 + 64, width: ScreenWidth - 80 - 4, height: ScreenHeight - 64 - 4), collectionViewLayout: self.flowlayout) collectionView.delegate = self collectionView.dataSource = self collectionView.showsVerticalScrollIndicator = false collectionView.showsHorizontalScrollIndicator = false collectionView.backgroundColor = UIColor.clear collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: kCollectionViewCell) collectionView.register(CollectionViewHeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: kCollectionViewHeaderView) return collectionView }()

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: kLeftTableViewCell, for: indexPath) as! LeftTableViewCell let model = dataSource[indexPath.row] cell.nameLabel.text = model.name return cell }

func collectionView( collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kCollectionViewCell, for: indexPath) as! CollectionViewCell let model = collectionDatas[indexPath.section][indexPath.row] cell.setDatas(model) return cell }</code></pre>

先將 TableView 關聯 CollectionView,點擊 TableViewCell,右邊的 CollectionView 跳到相應的分區列表頭部。

func tableView( tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        selectIndex = indexPath.row
   collectionView.scrollToItem(at: IndexPath(row: 0, section: selectIndex), at: .top, animated: true)
   tableView.scrollToRow(at: IndexPath(row: selectIndex, section: 0), at: .top, animated: true)
}</code></pre> 
  

再將 CollectionView 關聯 TableView,標記一下 RightTableView 的滾動方向,然后分別在 CollectionView 分區標題即將展示和展示結束的代理函數里面處理邏輯。

  • 1.在 CollectionView 分區標題即將展示里面,判斷 當前 CollectionView 滾動的方向向上, CollectionView 是用戶拖拽而產生滾動的(主要是判斷 CollectionView 是用戶拖拽而滾動的,還是點擊 TableView 而滾動的),如果二者都成立,那么 TableView 的選中行就是 CollectionView 的當前 section。
  • 2.在 CollectionView 分區標題展示結束里面,判斷當前 CollectionView 滾動的方向向下, CollectionView 是用戶拖拽而產生滾動的,如果二者都成立,那么 TableView 的選中行就是 CollectionView 的當前 section-1。
// 標記一下 CollectionView 的滾動方向,是向上還是向下
func scrollViewDidScroll(_ scrollView: UIScrollView) {
   if collectionView == scrollView {
       isScrollDown = lastOffsetY < scrollView.contentOffset.y
       lastOffsetY = scrollView.contentOffset.y
   }
}

// CollectionView 分區標題即將展示 func collectionView(_ collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, at indexPath: IndexPath) { // 當前 CollectionView 滾動的方向向上,CollectionView 是用戶拖拽而產生滾動的(主要是判斷 CollectionView 是用戶拖拽而滾動的,還是點擊 TableView 而滾動的) if !isScrollDown && collectionView.isDragging { selectRow(index: indexPath.section) } }

// CollectionView 分區標題展示結束 func collectionView(_ collectionView: UICollectionView, didEndDisplayingSupplementaryView view: UICollectionReusableView, forElementOfKind elementKind: String, at indexPath: IndexPath) { // 當前 CollectionView 滾動的方向向下,CollectionView 是用戶拖拽而產生滾動的(主要是判斷 CollectionView 是用戶拖拽而滾動的,還是點擊 TableView 而滾動的) if isScrollDown && collectionView.isDragging { selectRow(index: indexPath.section + 1) } }

// 當拖動 CollectionView 的時候,處理 TableView private func selectRow(index : Int) { tableView.selectRow(at: IndexPath(row: index, section: 0), animated: true, scrollPosition: .middle) }</code></pre>

TableView 與 CollectionView 之間的聯動就這么實現了,是不是也很簡單。

TableView 與 CollectionView 之間的聯動

最后

由于筆者水平有限,文中如果有錯誤的地方,或者有更好的方法,還望大神指出。

附上本文的所有 demo 下載鏈接, 【GitHub - Swift 版】【GitHub - OC 版】 ,配合 demo 一起看文章,效果會更佳。

如果你看完后覺得對你有所幫助,還望在 GitHub 上點個 star。贈人玫瑰,手有余香。

 

來自:http://www.jianshu.com/p/236f800e9d01

 

 本文由用戶 rhqq0256 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!