2017-04-17 44 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 –

相關問題