V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
banxi1988
V2EX  ›  iDev

[Swift] UITableView:静态 TableView 的简化之道

  •  
  •   banxi1988 ·
    banxi1988 · 2016-12-29 22:21:17 +08:00 · 4452 次点击
    这是一个创建于 2887 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    首先以 "微信" 应用我的界面为例, 怎么让快速的实现如下的界面呢? 可以先猜一下,我会给出什么样的简化方案. wx

    我的解决方案

    好了, 废话不多话, 步骤也省了. 直接上结果: StaticTableViewAdapter

    直接以一个 Adapter 作为 UITableViewCell 的容器.

    public protocol StaticHeightAware{
      var staticHeight: CGFloat{ get }
    }
    
    public class StaticTableViewAdapter: NSObject, UITableViewDataSource, UITableViewDelegate{
      public private(set) var cells:[UITableViewCell] = []
      private weak var tableView: UITableView?
      public var didTapCell: ((UITableViewCell) -> Void)?
      
      init(cells: [UITableViewCell]){
        self.cells = cells
      }
      
      public func bind(to tableView: UITableView){
        self.tableView = tableView
        tableView.dataSource = self
        tableView.delegate = self
      }
      
      public func staticCell(atIndexPath indexPath: IndexPath) -> UITableViewCell{
        return cells[indexPath.row]
      }
      
      public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cells.count
      }
      
      public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return cells[indexPath.row]
      }
    
      // MARK: UITableViewDelegate
      public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        let cell = staticCell(atIndexPath: indexPath)
        if let heightAware = cell as? StaticHeightAware{
          return heightAware.staticHeight
        }
        return tableView.rowHeight
      }
      
      public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        didTapCell?(staticCell(atIndexPath: indexPath))
        tableView.deselectRow(at: indexPath, animated: true)
      }
      
    }
    
    

    空白的间隔可以以一个 EmptyCell 来实现.作为空白的 Hack. 可以指定高度.

    public class EmptyCell: UITableViewCell, StaticHeightAware{
      public var staticHeight: CGFloat = 15
      public init(height: CGFloat = 15){
        super.init(style: .default, reuseIdentifier: "emptyCell")
        staticHeight = height
        contentView.backgroundColor = UIColor(white: 0.932, alpha: 1.0)
      }
      
      required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
    }
    
    

    实现此列表

    func makeEntryCell(title:String) -> UITableViewCell{
      let cell = UITableViewCell(style: .default, reuseIdentifier: "entryCell")
      cell.textLabel?.text = title
      return cell
    }
    
    
    let albumCell = makeEntryCell(title: "相册")
    let favoriteCell = makeEntryCell(title: "收藏")
    let walletCell = makeEntryCell(title: "钱包")
    let cardCell = makeEntryCell(title: "卡包")
    let emotionCell = makeEntryCell(title: "表情")
    let settingsCell = makeEntryCell(title: "设置")
    
    let adapter = StaticTableViewAdapter(cells: [
      albumCell, favoriteCell, EmptyCell(), walletCell, cardCell, EmptyCell(), emotionCell, EmptyCell(),settingsCell
      ])
    
    
    let tableView = UITableView(frame: CGRect(x:0,y:0,width:320,height:480), style: .plain)
    tableView.backgroundColor = UIColor(white: 0.932, alpha: 1.0)
    tableView.tableFooterView = UIView()
    adapter.bind(to: tableView)
    
    adapter.didTapCell = { cell in
      switch cell {
      case albumCell:
        NSLog("Did Tap Cell albumCell")
      default:
        break
      }
    }
    
    

    最后,我这只是抛砖引玉, 各位可以根据自己的需要再进一步扩展. 有什么不足,敬请指正. 实例截图:

    wx_static_cells

    9 条回复    2017-04-11 17:01:36 +08:00
    aaronlam
        1
    aaronlam  
       2016-12-29 22:32:09 +08:00
    为什么截图是个安卓?这很不苹果!
    banxi1988
        2
    banxi1988  
    OP
       2016-12-29 23:08:30 +08:00
    @aaronlam Sorry, 我没苹果手机.
    aaronlam
        3
    aaronlam  
       2016-12-30 00:19:17 +08:00
    @banxi1988 O(∩_∩)O 开个玩笑。
    free9fw
        4
    free9fw  
       2016-12-30 00:50:38 +08:00
    还是太复杂了,用同一个 cell 大概只要 60 行代码搞定
    CommandZi
        5
    CommandZi  
       2016-12-30 10:16:44 +08:00
    很明显微信用的是 UITableViewStyleGrouped 样式的 UITableView 。
    你用空白 Cell 代表作为中间的间隔已经很不优雅了,而且你的分割线都没处理好。
    我觉得你把简单的问题复杂化了。
    banxi1988
        6
    banxi1988  
    OP
       2016-12-30 11:19:30 +08:00
    @CommandZi
    首先感谢你的回复.

    这里再谈谈我的想法

    一: 为什么说用 GroupTableView 不好.
    1. 使用 Group TableView 其实对于 heightForHeaderInSection 感觉很难控制高度, 我有时搞得对, 现在又忘记了. 系统默认的高度要高一些. 但是国内应用好像普通要矮一些.

    2. 如果使用 Group TableView 相当于是使用多维数组了. 二维的比一维的复杂. 这个道理比较简单.

    3. 你说到分割线没有处理好, 这个我承认. 但是我这个 Demo 主要目的是 简化这个静态的处理.
    **但是** 但是, 如果使用 Group TableView 这个分隔线的处理也麻烦. 对于我来说,他们的解决方案是一样的:
    你需要 1) 使用 `tableView.separatorStyle = .none` 分隔线隐藏. 但是同一个 Section 中的分隔线又需要显示.
    2) 对于中间的 Cell 在下面 添加一个 ShapeLayer 来当作分隔线.



    二: 如果确实需要 GroupTableView

    也可以封装一个 `GroupTableViewAdapter` 它不是 Cell 数组, 而是 `GroupSection` 数组.

    ```swift
    public struct GroupSection{
    let cells:[UITableViewCell]
    }
    ```
    然后:

    ```swift
    let adapter = GroupTableViewAdapter(sections: [
    GroupSection(cells: [albumCell, favoriteCell]),
    GroupSection(cells: [walletCell, cardCell]),
    GroupSection(cells: [emotionCell]),
    GroupSection(cells: [settingsCell]),
    ])
    ```
    当然, 我觉得这比不使用 GroupSection 复杂了.

    三:
    综上: 对于这种场景, 不使用 GroupTableView 挺好的.

    对了,使用 EmptyCell 作为中间间隔其实挺好的啊. 没什么不优雅. 方便灵活.
    如果需要你也可以当. TableViewSectionHeaderFooterView 来用
    yfmir
        7
    yfmir  
       2016-12-30 11:25:55 +08:00
    Storyboard+static cell 路过
    banxi1988
        8
    banxi1988  
    OP
       2016-12-30 12:09:45 +08:00
    @yfmir 我觉得代码写起来更方便快捷,修改更方便.
    再者,Storyboard 打开都得半天. 我已经不喜欢 Storyboard 了.
    C90
        9
    C90  
       2017-04-11 17:01:36 +08:00
    @banxi1988 只能说明你需要换台电脑。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4213 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 05:29 · PVG 13:29 · LAX 21:29 · JFK 00:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.