2017-04-17 1 views
1

Bon, je souhaite avoir un UITableViewCell personnalisé dans un UITableView.Utilisation d'un UITableViewCell personnalisé avec DataSource externe et UITableView dans un ViewController

J'ai besoin tous les composants comme modulaire et réutilisable que possible, alors j'ai décidé de les mettre tous dans les différentes classes:

Ma configuration ressemble maintenant à ceci: J'ai un fichier rapide pour mon DataSoure, un fichier mon CustomTableViewCell et dans mon storyboard j'ai un UITableView à côté d'autres UIViees et j'ai déclaré utiliser la cellule personnalisée.

Storyboard ressemble à ceci:

TableView (attributs inspecteur): storyboard setup and table view attributes inspector

TableView (inspecteur d'identité): table view identity inspector

TableView (inspecteur de la taille): table view size inspector

TableViewCell (inspecteur d'identité): table view cell identity inspector

TableViewCell (Inspecteur des attributs): table view cell attributes inspector

TableViewCell (Inspecteur de la taille): table view cell size inspector

Ma classe ViewController ressemble à ceci:

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 
    } 
} 

classe Mon 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 
    } 
} 

Et enfin mon DataSource:

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 
    } 
} 

Je ne sais pas pourquoi cela ne fonctionne pas, probablement le DataSource ne fonctionne pas comme prévu ou assigner la source de données au TableView ...

Le CustomTableViewCell ne devrait pas être un problème, comme cela a fonctionné avant et j'ai changé le code que mes vues sont ajoutées à self.contentView.

sortie actuelle: actual output

Sortie prévue: expected output

+0

Vous semblez être intéressé par le codage des composants réutilisables. Peut-être que ce lien est d'intérêt pour vous: http://stackoverflow.com/a/43426337/6595536 – ObjectAlchemist

+0

C'est un moyen très intéressant de coder une application: D Je vais le garder à l'esprit pour mes prochains projets :) Et –

Répondre

1

La source de données est définie comme faible:

weak open var dataSource: UITableViewDataSource? 

Votre code:

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

Vous faites pas tenir de référence, donc il sera de nouveau nul après la fin de la méthode.

Solution: Définissez une classe var et maintenez-la aussi longtemps que nécessaire.

var dataSource: UITableViewDataSource! 

et:

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

en passant: vous ne définissez pas 'importantTableView.delegate = self'. – ObjectAlchemist

+0

Oh bon point: D Je l'avais là depuis un certain temps :) Mais j'ai utilisé une prise à la place parce que j'ai essayé tant de choses pour le faire fonctionner et j'ai pensé que cela pourrait résoudre le problème, comme je l'ai vu dans d'autres projets. Devinez quoi: Il n'a pas –

+0

Merci beaucoup, je n'ai même pas pensé à ce fait. Tu m'as fait sauter jeter ma chambre parce que ça a finalement marché pour moi: D –