2017-03-08 22 views
0

我正在设计一个UITableView使用子视图来填充它的可重用单元,我希望对此有一些看法。按照我的测试,它运作良好。但是,我不知道这是否是一个好的解决方案。设计UITableView /单元 - iOS

这种情况是:我有一个tableview与不同种类的单元格(布局)。当我设计时,它增长得很快(我的控制器代码),因为我必须注册很多单元并处理cellForRow。然后我想出了这个想法,为一个独特的可重用单元实例化不同的子视图,并使用'Presenter'来处理委托/数据源。你认为这是一个问题?这是一个好方法吗?

在此先感谢!

Ps .:抱歉有任何英文错误!

编辑:

这是其次是德代码项目的会议: bundle image

代码为:

  • OrderDetailCell

    class OrderDetailCell: UITableViewCell { 
    
    //MARK: Outlets 
    @IBOutlet weak var cellHeight: NSLayoutConstraint! 
    @IBOutlet weak var viewContent: UIView! 
    
    //Variables 
    var didUpdateLayout = false 
    
    
    internal func setupLayoutWith(view: UIView){ 
    cellHeight.constant = view.frame.height 
    viewContent.frame = view.frame 
    
    viewContent.addSubview(view) 
    
    updateConstraints() 
    layoutIfNeeded() 
    
    didUpdateLayout = true 
    } 
    } 
    
  • OrderDetailSubview

    class OrderDetailSubview: UIView { 
    
    var type: OrderDetailsSubViewType? 
    var height: CGFloat = 1 
    
    class func instanceFromNib(withType type: OrderDetailsSubViewType) -> OrderDetailSubview { 
    let view = UINib(nibName: type.rawValue, bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! OrderDetailSubview 
    
    switch type { 
    case .OrderDetailSubviewStatus: 
        view.height = 258 
    
    case .OrderDetailSubViewItem: 
        view.height = 129 
    
    case .OrderDetailSubViewStoreInformation: 
        view.height = 317 
    
    case .OrderDetailSubViewEvaluation: 
        view.height = 150 
    } 
    
    view.updateConstraints() 
    view.layoutIfNeeded() 
    
    return view 
    } 
    } 
    
  • OrderDetailPresenter

    enum OrderDetailsSubViewType: String { 
    
    case OrderDetailSubviewStatus = "OrderDetailSubviewStatus", 
    OrderDetailSubViewItem = "OrderDetailSubViewItem", 
    OrderDetailSubViewStoreInformation = "OrderDetailSubViewStoreInformation", 
    OrderDetailSubViewEvaluation = "OrderDetailSubViewEvaluation" 
    
    static let types = [OrderDetailSubviewStatus, OrderDetailSubViewItem, OrderDetailSubViewStoreInformation, OrderDetailSubViewEvaluation] 
        } 
    
    class OrderDetailPresenter { 
    
    //Constants 
    let numberOfSections = 4 
    
    //Variables 
    // var order: Order? 
    
    func setup(reusableCell: UITableViewCell, forRowInSection section: Int) -> OrderDetailCell { 
    
    let cell = reusableCell as! OrderDetailCell 
    for sub in cell.viewContent.subviews { 
        sub.removeFromSuperview() 
        } 
    
        let subView = OrderDetailSubview.instanceFromNib(withType: OrderDetailsSubViewType.types[section]) 
    cell.setupLayoutWith(view: subView) 
    
    return cell 
    
    } 
    
    func numberOfRowsForSection(_ section: Int) -> Int { 
    switch section { 
    case 1: 
        //TODO: count de offerList 
        return 4 
    default: 
        return 1 
        } 
    } 
    } 
    
  • OrderDetailViewController

    class OrderDetailViewController: BaseViewController { 
    
    //MARK: Outlets 
    @IBOutlet weak var tableView: UITableView! 
    
    var presenter = OrderDetailPresenter() 
    
    override func setupView() { 
        setupTableView() 
    
        } 
    } 
    
    
    extension OrderDetailViewController: UITableViewDataSource, UITableViewDelegate { 
    
    internal func setupTableView() { 
    
    tableView.delegate = self 
    tableView.dataSource = self 
    tableView.estimatedRowHeight = 600 
    tableView.rowHeight = UITableViewAutomaticDimension 
    
    tableView.register(UINib(nibName: "OrderDetailCell", bundle: nil), forCellReuseIdentifier: "OrderDetailCell") 
    
    } 
    
    func numberOfSections(in tableView: UITableView) -> Int { 
    return presenter.numberOfSections 
    } 
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return presenter.numberOfRowsForSection(section) 
    } 
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    
    let reusableCell = tableView.dequeueReusableCell(withIdentifier: "OrderDetailCell") as! OrderDetailCell 
    
    let cell = presenter.setup(reusableCell: reusableCell, forRowInSection: indexPath.section) 
    
    
    return cell 
    
    } 
    } 
    

*对不起,这里缩进...

完蛋了!你怎么看?

+1

如果你已经遵循了适当的iOS编码习惯(比如'出列'单元格)并且你的代码没有错误,那么很难说你的代码不好。如果您的代码存在问题(如崩溃,逻辑错误或性能问题),请编辑您的问题以包含代码并询问具体问题。如果你想让别人查看你的代码,那么你可以试试'codereview.stackexchange.com' –

+0

谢谢@RoboticCat,我按照建议遵循。事情是,我有多种细胞类型。所以,相反,创建很多单元格,我只创建了一个单元格,现在我正在为具有相同单元格的每行实例化子视图,并更新布局。运作良好,我只是想要一些意见。也感谢codereview建议..从来没有听说过。我会尽力! – Gehlen

回答

0
let dynamicCellID: String = "dynamicCellID" //One Cell ID for resuse 
class dynamicCell: UITableViewCell { 

    var sub: UIView // you just need to specify the subview 

    init(sub: UIView) { 
     self.sub = sub 
     super.init(style: .default, reuseIdentifier: dynamicCellID) 

     self.addSubview(sub) 
     self.sub.frame = CGRect(x: 0, y: 0, width: sub.frame.width, height: sub.frame.height) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

} 

而且你需要创建一个视图阵列

let views: [UIView] = [] 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ 

        return views.count 
    } 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

        let v = views[indexPath.row] 
        return dynamicCell(sub: v) 
    } 

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 

        let v = views[indexPath.row] 
        return v.frame.height + 10 //offset is 10 point 
    } 
+0

是的!我正在做这样的事情!但是使用xib文件和'View Presenter'来处理每个行的实例。事情是:这样做,是一个好方法吗?我的意思是,仍在重复使用单元格,我正在处理每个实例(要删除以及)..我只是想尽量减少代码行数。 – Gehlen

+0

如果您希望重用单元格以获得良好性能。您需要尽可能减少不同的细胞。就像我上面给出的解决方案一样。您的视图始终在您的阵列中作为实例。如果你有很多观点,它需要很多记忆。 –

+0

唯一的区别是,我实例化cellForRow中的视图和(肯定)我从我的细胞的内容删除子视图,也许降低性能有点..但仍然干净的代码..而滚动仍然顺利..我'现在就保持这种方式,直到出现一些问题。谢谢! – Gehlen

1

在这里,你希望拥有多个UITableViewCell子类实现你想要的不同的布局,即查看到每一个细胞委托给予,然后在你的表格视图数据源中选择相关的一个。

class Cell1: UITableViewCell { 

    let label = UILabel() 

    override init(style: UITableViewCellStyle, reuseIdentifier: String) { 
     super.init(style: style, reuseIdentifier: reuseIdentifier) 
     self.contentView.addSubview(label) 
    } 

    ... whatever other setup/layout you need to do in the class ... 

} 

class Cell2: UITableViewCell { 

    let imageView = UIImageView() 

    override init(style: UITableViewCellStyle, reuseIdentifier: String) { 
     super.init(style: style, reuseIdentifier: reuseIdentifier) 
     self.contentView.addSubview(imageView) 
    } 

    ... whatever other setup/layout you need to do in the class ... 

} 

然后在您的视图控制器

override func viewDidLoad() { 
    super.viewDidLoad() 
    tableView.register(Cell1.self, forCellReuseIdentifier: "cell1Identifier") 
    tableView.register(Cell2.self, forCellReuseIdentifier: "cell2Identifier") 
} 

... 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    if indexPath.row % 2 == 0 { // just alternating rows for example 
     let cell = tableView.dequeueReusableCell(withIdentifier: "cell1Identifier", for: indexPath) as! Cell1 
     // set data on cell 
     return cell 
    } else { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "cell2Identifier", for: indexPath) as! Cell2 
     // set data on cell 
     return cell 
    } 
} 

所以这只是一个例子,但使用两种不同的细胞亚类在表视图交替行。

+0

谢谢@George!我是这样做的。但事情是,因为我有多个单元格,我不想全部注册,然后在cellForRow中创建该逻辑。所以,相反,创建很多单元格,我只创建了一个单元格,现在我正在为具有相同单元格的每行实例化子视图,并更新布局。我可以分享我的代码,如果你想.. – Gehlen

+0

@Gehlen请分享你的代码,如果你可以。这听起来像是一个糟糕的计划,因为您将不得不重新实现UITableView免费提供的视图重用系统。这引出了一个问题,为什么要使用表视图,而不仅仅是一个滚动视图?为什么自定义的'UIView'具有不同的布局并在它们之间切换比简单一些,而不是具有不同的'UITableViewCell'? –

+0

我已经更新了问题...我感谢您的意见!谢谢! – Gehlen