web-dev-qa-db-fra.com

UITableViewCell personnalisé de nib dans Swift

J'essaie de créer une cellule de vue de tableau personnalisée à partir d'une plume. Je fais référence à cet article ici . Je suis confronté à deux problèmes.

J'ai créé un fichier .xib avec un objet UITableViewCell. J'ai créé une sous-classe de UITableViewCell et l'ai définie en tant que classe de la cellule et Cell en tant qu'identificateur réutilisable.

import UIKit

class CustomOneCell: UITableViewCell {

    @IBOutlet weak var middleLabel: UILabel!
    @IBOutlet weak var leftLabel: UILabel!
    @IBOutlet weak var rightLabel: UILabel!

    required init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder)
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

Dans UITableViewController j'ai ce code,

import UIKit

class ViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {

    var items = ["Item 1", "Item2", "Item3", "Item4"]

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // MARK: - UITableViewDataSource
    override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        let identifier = "Cell"
        var cell: CustomOneCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomOneCell
        if cell == nil {
            tableView.registerNib(UINib(nibName: "CustomCellOne", bundle: nil), forCellReuseIdentifier: identifier)
            cell = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomOneCell
        }

        return cell
    }
}

Ce code ne respecte aucune erreur, mais lorsque je l'exécute dans le simulateur, il ressemble à ceci.

enter image description here

Dans UITableViewController du storyboard, je n'ai rien fait dans la cellule. Identificateur vide et pas de sous-classe. J'ai essayé d'ajouter l'identifiant Cell à la cellule prototype et je l'ai réexécuté, mais le résultat est identique.

Une autre erreur que j'ai rencontrée est lorsque j'ai essayé d'implémenter la méthode suivante dans UITableViewController.

override func tableView(tableView: UITableView!, willDisplayCell cell: CustomOneCell!, forRowAtIndexPath indexPath: NSIndexPath!) {

    cell.middleLabel.text = items[indexPath.row]
    cell.leftLabel.text = items[indexPath.row]
    cell.rightLabel.text = items[indexPath.row]
}

Comme indiqué dans l'article que j'ai mentionné, j'ai changé la forme du paramètre cell du formulaire UITableViewCell en CustomOneCell, qui est ma sous-classe de UITableViewCell. Mais j'obtiens l'erreur suivante,

Méthode de substitution avec le sélecteur 'tableView: willDisplayCell: forRowAtIndexPath:' a un type incompatible '(UITableView !, CustomOneCell !, NSIndexPath!) -> ()'

Quelqu'un at-il une idée de la façon de résoudre ces erreurs? Celles-ci semblaient bien fonctionner en Objective-C.

Je vous remercie.

EDIT: Je viens de remarquer que si je change l’orientation du simulateur par rapport au paysage et le retourne en portrait, les cellules apparaissent! Je ne pouvais toujours pas comprendre ce qui se passait. J'ai téléchargé un projet Xcode ici / démontrant le problème si vous avez le temps pour un rapide aperçu.

114
Isuru

Vous devriez essayer le code suivant pour votre projet: (Syntaxe pour Swift 3+)

CustomOneCell.Swift

import UIKit

class CustomOneCell: UITableViewCell {

    // Link those IBOutlets with the UILabels in your .XIB file
    @IBOutlet weak var middleLabel: UILabel!
    @IBOutlet weak var leftLabel: UILabel!
    @IBOutlet weak var rightLabel: UILabel!

}

TableViewController.Swift

import UIKit

class TableViewController: UITableViewController {

    let items = ["Item 1", "Item2", "Item3", "Item4"]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UINib(nibName: "CustomOneCell", bundle: nil), forCellReuseIdentifier: "CustomCellOne")    
    }

    // MARK: - UITableViewDataSource

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

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("CustomCellOne", forIndexPath: indexPath) as! CustomOneCell

        cell.middleLabel.text = items[indexPath.row]
        cell.leftLabel.text = items[indexPath.row]
        cell.rightLabel.text = items[indexPath.row]

        return cell
    }
}

L'image ci-dessous montre un ensemble de contraintes qui fonctionnent avec le code fourni sans le message d'ambiguïté de contraintes de Xcode.

 enter image description here

173
Imanou Petit

Voici mon approche utilisant Swift 2 et Xcode 7.3. Cet exemple utilisera un seul ViewController pour charger deux fichiers .xib - un pour un UITableView et un pour UITableCellView.

 enter image description here

Pour cet exemple, vous pouvez déposer un droit UITableView dans un fichier TableNib .xib vide. A l'intérieur, définissez le propriétaire du fichier sur votre classe ViewController et utilisez un point de vente pour référencer la tableView.

 enter image description here

et

 enter image description here

Maintenant, dans votre contrôleur de vue, vous pouvez déléguer la tableView comme vous le feriez normalement.

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    ...

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // Table view delegate
        self.tableView.delegate = self
        self.tableView.dataSource = self

        ...

Pour créer votre cellule personnalisée, déposez à nouveau un objet Cellule de la vue Tableau dans un fichier TableCellNib .xib vide. Cette fois, dans le fichier .xib de la cellule, vous ne devez pas spécifier de "propriétaire", mais vous devez également spécifier une Custom Class et un identifier comme "TableCellId".

 enter image description here  enter image description here

Créez votre sous-classe avec tous les points de vente dont vous avez besoin

class TableCell: UITableViewCell {

    @IBOutlet weak var nameLabel: UILabel!

}

Enfin ... de retour dans votre View Controller, vous pouvez charger et afficher le tout comme si

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    // First load table nib
    let bundle = NSBundle(forClass: self.dynamicType)
    let tableNib = UINib(nibName: "TableNib", bundle: bundle)
    let tableNibView = tableNib.instantiateWithOwner(self, options: nil)[0] as! UIView

    // Then delegate the TableView
    self.tableView.delegate = self
    self.tableView.dataSource = self

    // Set resizable table bounds
    self.tableView.frame = self.view.bounds
    self.tableView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

    // Register table cell class from nib
    let cellNib = UINib(nibName: "TableCellNib", bundle: bundle)
    self.tableView.registerNib(cellNib, forCellReuseIdentifier: self.tableCellId)

    // Display table with custom cells
    self.view.addSubview(tableNibView)

}

Le code montre comment charger et afficher un fichier nib (le tableau) et comment enregistrer un nib pour une utilisation cellulaire. 

J'espère que cela t'aides!!!

26
internet-nico

Swift 4

Enregistrer Nib

tblMissions.register(UINib(nibName: "MissionCell", bundle: nil), forCellReuseIdentifier: "MissionCell")

Dans TableView DataSource 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          guard let cell = tableView.dequeueReusableCell(withIdentifier: "MissionCell", for: indexPath) as? MissionCell else { return UITableViewCell() }
          return cell
    }
11
GSK

Une autre méthode qui peut fonctionner pour vous (c’est comme ça que je le fais) est d’inscrire une classe.

Supposons que vous créez un tableau personnalisé comme suit:

class UICustomTableViewCell: UITableViewCell {...}

Vous pouvez ensuite enregistrer cette cellule dans n'importe quel UITableViewController que vous allez afficher avec "registerClass":

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.registerClass(UICustomTableViewCell.self, forCellReuseIdentifier: "UICustomTableViewCellIdentifier")
}

Et vous pouvez l'appeler comme vous le souhaitez dans la méthode cellule pour ligne:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("UICustomTableViewCellIdentifier", forIndexPath: indexPath) as! UICustomTableViewCell
    return cell
}
3
Ethan Kay

Pour résoudre le "La méthode de substitution ... a un type incompatible ..." error J'ai changé la déclaration de fonction en

override func tableView(tableView: (UITableView!), 
                        cellForRowAtIndexPath indexPath: (NSIndexPath!)) 
    -> UITableViewCell {...}

(était -> UITableViewCell! - avec un point d'exclamation à la fin)

2
tse

Vous n'avez pas enregistré votre plume comme ci-dessous:

tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
2
vsujan

Swift 4.1.2

xib. 

Créer une imageCell2.Swift

Étape 1

import UIKit

class ImageCell2: UITableViewCell {

    @IBOutlet weak var imgBookLogo: UIImageView!
    @IBOutlet weak var lblTitle: UILabel!
    @IBOutlet weak var lblPublisher: UILabel!
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

}

étape 2 . Selon la classe Viewcontroller

  import UIKit

    class ImageListVC: UIViewController,UITableViewDataSource,UITableViewDelegate {
    @IBOutlet weak var tblMainVC: UITableView!

    var arrBook : [BookItem] = [BookItem]()

    override func viewDidLoad() {
        super.viewDidLoad()
         //Regester Cell
        self.tblMainVC.register(UINib.init(nibName: "ImageCell2", bundle: nil), forCellReuseIdentifier: "ImageCell2")
        // Response Call adn Disply Record
        APIManagerData._APIManagerInstance.getAPIBook { (itemInstance) in
            self.arrBook = itemInstance.arrItem!
            self.tblMainVC.reloadData()
        }
    }
    //MARK: DataSource & delegate
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.arrBook.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//    [enter image description here][2]
        let cell  = tableView.dequeueReusableCell(withIdentifier: "ImageCell2") as! ImageCell2
        cell.lblTitle.text = self.arrBook[indexPath.row].title
        cell.lblPublisher.text = self.arrBook[indexPath.row].publisher
        if let authors = self.arrBook[indexPath.row].author {
            for item in authors{
                print(" item \(item)")
            }
        }
        let  url  = self.arrBook[indexPath.row].imageURL
        if url == nil {
            cell.imgBookLogo.kf.setImage(with: URL.init(string: ""), placeholder: UIImage.init(named: "download.jpeg"))
        }
        else{
            cell.imgBookLogo.kf.setImage(with: URL(string: url!)!, placeholder: UIImage.init(named: "download.jpeg"))
        }
        return cell
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 90
    } 

}
1
user3263340

Prenez simplement un xib avec la classe UITableViewCell. Définissez l'interface utilisateur selon vos besoins et affectez IBOutlet. Utilisez-le dans cellForRowAt () de la vue tableau comme ceci:

//MARK: - table method

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.arrayFruit.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell:simpleTableViewCell? = tableView.dequeueReusableCell(withIdentifier:"simpleTableViewCell") as? simpleTableViewCell
    if cell == nil{
        tableView.register(UINib.init(nibName: "simpleTableViewCell", bundle: nil), forCellReuseIdentifier: "simpleTableViewCell")
        let arrNib:Array = Bundle.main.loadNibNamed("simpleTableViewCell",owner: self, options: nil)!
        cell = arrNib.first as? simpleTableViewCell
    }

    cell?.labelName.text = self.arrayFruit[indexPath.row]
    cell?.imageViewFruit.image = UIImage (named: "fruit_img")

    return cell!

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

 enter image description here

100% travaille sans problème (testé)

0
Mr.Javed Multani