2017-04-17 108 views
1

好吧,我想在UITableView中有一个自定义的UITableViewCell。在ViewController中使用自定义的UITableViewCell w/external DataSource和UITableView

我需要每一个部件的模块化和可重用的可能,所以我决定把他们都在不同的班级:

我的设置,现在看起来是这样的: 我有一个快速的文件我DataSoure,一个文件我的CustomTableViewCell和我的故事板我有一个UITableView旁边其他UIViees,我宣布要使用自定义单元格。

故事板是这样的:

的TableView(属性检查器): storyboard setup and table view attributes inspector

的TableView(身份检查员): table view identity inspector

的TableView(尺寸检查): table view size inspector

TableViewCell (身份检查员): table view cell identity inspector

TableViewCell(属性检查器): table view cell attributes inspector

TableViewCell(尺寸检查): table view cell size inspector

我的ViewController类看起来是这样的:

import UIKit 

class MyShitViewController: UIViewController, UITableViewDelegate { 

    @IBOutlet weak var importantTableView: UITableView! 
    var importantItems = [ContentItem]() 

    override func viewWillAppear(_ animated: Bool) { 
     super.viewWillAppear(animated) 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Test data 
     importantItems.append(ContentItem(contentType: 1, image: #imageLiteral(resourceName: "ContentIcon"), title: "SQL - Basics", subject: "informatics", grade: 11, progress: 35, action: ContentItem.ACTION_MORE)) 
     importantItems.append(ContentItem(contentType: 1, image: #imageLiteral(resourceName: "ContentIcon"), title: "SQL - Pros", subject: "informatics", grade: 12, progress: 0, action: ContentItem.ACTION_MORE)) 
     // Data source 
     let dataSource = ContentItemDataSource(items: importantItems) 
     importantTableView.rowHeight = 75 
     importantTableView.dataSource = dataSource 
     importantTableView.reloadData() 
    } 

    //MARK: Table view delegate 
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
     // For debugging, never get's called, when some one clicks on any cell 
     let row = indexPath.row 
     print(row) 
    } 

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 
     print("height") 
     return 48 
    } 

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { 
     print("estimated height") 
     return 48 
    } 
} 

我CustomTableViewCell类:

import UIKit 

class ContentItemView: UITableViewCell { 

    //MARK: Properties 
    var contentItem: ContentItem? 

    private var contentImageView: UIImageView? 
    private var primaryTextView: UILabel? 
    private var secondaryTextView: UILabel? 
    private var progressView: UILabel? 
    private var actionView: UIButton? 
    private var verifiedIcon: UIImageView? 

    private var layoutConstraints: [NSLayoutConstraint] = [] 

    //MARK: Initialisation 
    func setContent(item: ContentItem) { 
     self.contentItem = item 
     setContent() 
    } 

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 
     super.init(style: style, reuseIdentifier: reuseIdentifier) 
     print(style) 
     setUpView() 
    } 

    required init?(coder: NSCoder) { 
     super.init(coder: coder) 
     print("coder") 
     setUpView() 
    } 

    //MARK: Set Up 
    private func setUpView() { 
     self.backgroundView?.backgroundColor = Colors.biology 
     self.textLabel?.text = "Test" 
     // Create views 
     contentImageView = UIImageView() 
     primaryTextView = UILabel() 
     secondaryTextView = UILabel() 
     progressView = UILabel() 
     actionView = UIButton() 
     verifiedIcon = UIImageView() 
     // Add Content to views 
     primaryTextView?.font = getFont(withSize: 14) 
     primaryTextView?.textColor = Colors.toolbarColor 
     secondaryTextView?.font = getFont(withSize: 12) 
     secondaryTextView?.textColor = Colors.toolbarColor 
     progressView?.font = getFont(withSize: 12) 
     progressView?.textColor = Colors.toolbarColor 
     // Add sub views 
     self.contentView.addSubview(contentImageView!) 
     self.contentView.addSubview(primaryTextView!) 
     self.contentView.addSubview(secondaryTextView!) 
     self.contentView.addSubview(progressView!) 
     self.contentView.addSubview(actionView!) 
     self.contentView.addSubview(verifiedIcon!) 
     // Apply Constraints 
     makeViewConstraints() 
    } 

    // MARK: Layout 
    private func setContent() { 
     contentImageView?.image = contentItem?.image 
     primaryTextView?.text = contentItem?.title 
     secondaryTextView?.text = (contentItem?.done)! ? "DONE" : (contentItem?.subject)! + " - " + getLocalizedGrade(_for: (contentItem?.grade)!) 
     progressView?.text = contentItem?.progress != nil ? "\(String(describing: contentItem?.progress))%" : "" 
     if (contentItem?.verified)! { verifiedIcon?.image = #imageLiteral(resourceName: "verified") } 
     else { verifiedIcon?.image = nil } 
     let actionImage = getActionImage() 
     actionView?.setImage(actionImage, for: .normal) 
    } 

    private func makeViewConstraints() { 
     // Clear constraints 
     self.contentView.removeConstraints(layoutConstraints) 
     layoutConstraints.removeAll() 
     // Force elements to exist 
     let imageView = self.contentImageView! 
     let primaryTextView = self.primaryTextView! 
     let secondaryTextView = self.secondaryTextView! 
     let progressView = self.progressView! 
     let actionView = self.actionView! 
     imageView.translatesAutoresizingMaskIntoConstraints = false 
     imageView.widthAnchor.constraint(equalToConstant: 48) 
     imageView.heightAnchor.constraint(equalToConstant: 48) 
     layoutConstraints.append(
      NSLayoutConstraint(item: imageView, attribute: .leading, relatedBy: .equal, 
          toItem: self.contentView, attribute: .leading, multiplier: 1, constant: 0)) 
     layoutConstraints.append(
      NSLayoutConstraint(item: imageView, attribute: .centerY, relatedBy: .equal, 
          toItem: self.contentView, attribute: .centerY, multiplier: 1, constant: 0)) 
     primaryTextView.translatesAutoresizingMaskIntoConstraints = false 
     layoutConstraints.append(
      NSLayoutConstraint(item: primaryTextView, attribute: .leading, relatedBy: .equal, 
          toItem: imageView, attribute: .trailing, multiplier: 1, constant: 16)) 
     layoutConstraints.append(
      NSLayoutConstraint(item: primaryTextView, attribute: .top, relatedBy: .equal, 
          toItem: self.contentView, attribute: .top, multiplier: 1, constant: 8)) 
     secondaryTextView.translatesAutoresizingMaskIntoConstraints = false 
     layoutConstraints.append(
      NSLayoutConstraint(item: secondaryTextView, attribute: .leading, relatedBy: .equal, 
          toItem: imageView, attribute: .trailing, multiplier: 1, constant: 16)) 
     layoutConstraints.append(
      NSLayoutConstraint(item: secondaryTextView, attribute: .bottom, relatedBy: .equal, 
          toItem: self.contentView, attribute: .bottom, multiplier: 1, constant: -8)) 
     progressView.translatesAutoresizingMaskIntoConstraints = false 
     layoutConstraints.append(
      NSLayoutConstraint(item: progressView, attribute: .centerX, relatedBy: .equal, 
          toItem: imageView, attribute: .centerX, multiplier: 1, constant: 0)) 
     layoutConstraints.append(
      NSLayoutConstraint(item: progressView, attribute: .centerY, relatedBy: .equal, 
          toItem: imageView, attribute: .centerY, multiplier: 1, constant: 0)) 
     actionView.translatesAutoresizingMaskIntoConstraints = false 
     layoutConstraints.append(
      NSLayoutConstraint(item: actionView, attribute: .trailing, relatedBy: .equal, 
          toItem: self.contentView, attribute: .trailing, multiplier: 1, constant: 0)) 
     layoutConstraints.append(
      NSLayoutConstraint(item: actionView, attribute: .centerY, relatedBy: .equal, 
          toItem: self.contentView, attribute: .centerY, multiplier: 1, constant: 0)) 
     self.contentView.addConstraints(layoutConstraints) 
    } 

    // MARK: Additional Helpers 
    private func getActionImage() -> UIImage? { 
     if contentItem?.action == ContentItem.ACTION_MORE { 
      return #imageLiteral(resourceName: "ic_more_horiz_white") 
     } 
     if contentItem?.action == ContentItem.ACTION_ADD { 
      return #imageLiteral(resourceName: "ic_add_circle_outline_white") 
     } 
     if contentItem?.action == ContentItem.ACTION_REMOVE { 
      return #imageLiteral(resourceName: "ic_remove_circle_outline_white") 
     } 
     return nil 
    } 
} 

最后我的数据源:

import UIKit 

class ContentItemDataSource: NSObject, UITableViewDataSource { 
    var items = [ContentItem]() 

    init(items: [ContentItem]) { 
     self.items = items 
    } 

    // MARK: - Table view data source 

    func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
     return 1 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return items.count 
    } 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let item = items[indexPath.row] 
     guard let cell = tableView.dequeueReusableCell(withIdentifier: Config.CONTENT_ITEM_CELL, for: indexPath) as? ContentItemView else { 
      fatalError("The dequeued cell is not an instance of ContentItemView.") 
     } 
     cell.setContent(item: item) 
     return cell 
    } 
} 

我不知道为什么它不工作,可能是因为预期或指定数据源到TableView中的数据源不工作...

的CustomTableViewCell应该没有问题,因为它之前的工作原理,我更改了我的视图添加到self.contentView的代码。

实际输出: actual output

预期输出: expected output

+0

你似乎是有意编码可重用的组件。也许这个链接是你感兴趣的:http://stackoverflow.com/a/43426337/6595536 – ObjectAlchemist

+0

这是一个非常有趣的方式来编写一个应用程序:D 我会记住我的下一个项目:) –

回答

1

数据源定义为弱:

weak open var dataSource: UITableViewDataSource? 

您的代码:

let dataSource = ContentItemDataSource(items: importantItems) 
importantTableView.dataSource = dataSource 

你做没有提供参考,因此方法结束后再次为零。

解决方案:定义一个类var并按需要保存它。

var dataSource: UITableViewDataSource! 

和:

let dataSource = ContentItemDataSource(items: importantItems) 
importantTableView.dataSource = dataSource 
self.dataSource = dataSource 
+0

和顺便说一下:你不设置'importantTableView.delegate = self'。 – ObjectAlchemist

+0

噢好点:D我有它在那里一段时间:)但我用了一个插座,因为我尝试了很多事情来让它工作,并认为这可能解决问题,因为我在其他项目中看到它。猜猜是什么:它没有 –

+0

非常感谢,我甚至没有想到这个事实。你让我跳投我的房间,因为它终于为我解决:D –

相关问题