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):
TableView (inspecteur d'identité):
TableView (inspecteur de la taille):
TableViewCell (inspecteur d'identité):
TableViewCell (Inspecteur des attributs):
TableViewCell (Inspecteur de la taille):
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
.
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
C'est un moyen très intéressant de coder une application: D Je vais le garder à l'esprit pour mes prochains projets :) Et –