web-dev-qa-db-fra.com

créer des cellules personnalisées dans la table dans swift

J'ai une classe de cellules personnalisée avec quelques IBOutlets. J'ai ajouté la classe au storyboard. J'ai connecté tous mes points de vente. ma fonction cellForRowAtIndexPath ressemble à ceci:

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

        cell.mainTextLabel.text = self.venueService.mainCategoriesArray()[indexPath.row]

        return cell
    }

Voici ma classe de cellule personnalisée:

class SwipeableCell: UITableViewCell {
    @IBOutlet var option1: UIButton
    @IBOutlet var option2: UIButton
    @IBOutlet var topLayerView : UIView
    @IBOutlet var mainTextLabel : UILabel
    @IBOutlet var categoryIcon : UIImageView

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


    }
}

Lorsque je lance l'application, toutes mes cellules sont vides. Je me suis déconnecté self.venueService.mainCategoriesArray() et il contient toutes les chaînes correctes. J'ai également essayé de mettre une chaîne réelle égale à l'étiquette, et cela produit le même résultat.

Qu'est-ce que je rate? Toute aide est appréciée.

40
Nilzone-

Merci pour toutes les suggestions différentes, mais j'ai finalement compris. La classe personnalisée a été configurée correctement. Tout ce que je devais faire, c’était dans le storyboard où je choisissais la classe personnalisée: supprimez-la et sélectionnez-la à nouveau. Cela n'a pas beaucoup de sens, mais cela a fini par fonctionner pour moi.

11
Nilzone-

Exemple de cellule d'affichage de tableau personnalisé

Testé avec Xcode 9 et Swift 4

Le demandeur de la question initiale a résolu son problème. J'ajoute cette réponse en tant que mini-projet d'exemple autonome pour ceux qui essaient de faire la même chose.

Le projet fini devrait ressembler à ceci:

enter image description here

Créer un nouveau projet

Il peut s'agir simplement d'une application à vue unique.

Ajouter le code

Ajoutez un nouveau fichier Swift à votre projet. Nommez-le MyCustomCell.Swift. Cette classe contient les points de vente des vues que vous ajoutez à votre cellule dans le storyboard.

import UIKit
class MyCustomCell: UITableViewCell {
    @IBOutlet weak var myView: UIView!
    @IBOutlet weak var myCellLabel: UILabel!
}

Nous connecterons ces prises plus tard.

Ouvrez ViewController.Swift et assurez-vous que vous avez le contenu suivant:

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    // These strings will be the data for the table view cells
    let animals: [String] = ["Horse", "Cow", "Camel", "Sheep", "Goat"]

    // These are the colors of the square views in our table view cells.
    // In a real project you might use UIImages.
    let colors = [UIColor.blue, UIColor.yellow, UIColor.Magenta, UIColor.red, UIColor.brown]

    // Don't forget to enter this in IB also
    let cellReuseIdentifier = "cell"

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self
    }

    // number of rows in table view
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.animals.count
    }

    // create a cell for each table view row
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell:MyCustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MyCustomCell

        cell.myView.backgroundColor = self.colors[indexPath.row]
        cell.myCellLabel.text = self.animals[indexPath.row]

        return cell
    }

    // method to run when table view cell is tapped
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("You tapped cell number \(indexPath.row).")
    }
}

Installer le storyboard

Ajoutez une vue Table à votre contrôleur de vue et utilisez la présentation automatique pour l'épingler aux quatre côtés du contrôleur de vue. Faites ensuite glisser une cellule de la vue tableau dans la vue tableau. Ensuite, faites glisser une vue et une étiquette sur la cellule Prototype. (Vous devrez peut-être sélectionner la cellule d'affichage du tableau et définissez manuellement la hauteur de ligne pour qu'elle soit plus haute dans l'inspecteur de taille afin de disposer de davantage d'espace pour travailler.) Utilisez la disposition automatique pour corriger l'affichage et le Indiquez comment vous souhaitez les organiser dans la vue Contenu de la cellule Table View. Par exemple, j'ai créé une vue 100x100.

enter image description here

Autres paramètres IB

Nom de classe et identifiant personnalisés

Sélectionnez la cellule de la vue tableau et définissez la classe personnalisée sur MyCustomCell (le nom de la classe dans le fichier Swift que nous avons ajouté). Définissez également l'identificateur sur cell (la même chaîne que celle utilisée pour cellReuseIdentifier dans le code ci-dessus.

enter image description here

Raccordez les prises

  • Faites glisser le contrôle de la vue Table du storyboard vers la variable tableView du code ViewController.
  • Faites de même pour la vue et le libellé de votre cellule Prototype avec les variables myView et myCellLabel de la classe MyCustomCell.

Fini

C'est ça. Vous devriez pouvoir exécuter votre projet maintenant.

Remarques

  • Les vues colorées que j'ai utilisées ici pourraient être remplacées par n'importe quoi. Un exemple évident serait un UIImageView.
  • Si vous essayez simplement de faire fonctionner une TableView, voir cet exemple encore plus fondamental .
  • Si vous avez besoin d’une vue tableau avec des hauteurs de cellules variables, voir cet exemple .
98
Suragch

Ceci est pour qui travaille cellule personnalisée avec .xib

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{

    let identifier = "Custom"

    var cell: CustomCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomCel  

      if cell == nil {
            tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: identifier)
           cell =tableView.dequeueReusableCellWithIdentifier(identifier) as? CustomCell
        }return cell}
18
ShigaSuresh

J'ai le même problème.

Généralement ce que j'ai fait est le même que toi.

class dynamicCell: UITableViewCell {

    @IBOutlet var testLabel : UILabel

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

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

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

et dans la méthode uitableviewcell:

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
    var cell :dynamicCell = tableView.dequeueReusableCellWithIdentifier("cell") as dynamicCell

    cell.testLabel.text = "so sad"

    println(cell.testLabel)

    return cell;
}

et oui la table ne montre rien! Mais devinez quoi, cela montre en réalité quelque chose ... parce que le journal que je tire de println (cell.testLabel) montre que toutes les étiquettes sont réellement affichées.

MAIS! leurs cadres est étrange, qui ont quelque chose comme ça:

cadre = (0 à 21; 42 à 21);

il a donc un (0, -21) comme (x, y), ce qui signifie que l'étiquette apparaît juste à quelque part en dehors de la limite de la cellule.

donc j'essaye d'ajouter ajuster le cadre manuellement comme ceci:

cell.testLabel.frame = CGRectMake (10, 10, 42, 21)

et malheureusement, ça ne marche pas.

--------------- mise à jour après 10 min -----------------

I DID IT. Il semble donc que le problème vienne des classes de taille.

Cliquez sur votre fichier .storyboard et accédez à l'onglet Inspecteur de fichier.

Décochez la case de la classe de taille

et finalement, mon label "tellement triste" sort!

14
The Little DD

La dernière version mise à jour est avec xCode 6.1

class StampInfoTableViewCell: UITableViewCell{


@IBOutlet weak var stampDate: UILabel!
@IBOutlet weak var numberText: UILabel!


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

required init(coder aDecoder: NSCoder) {
    //fatalError("init(coder:) has not been implemented")
    super.init(coder: aDecoder)
}

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

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

[1] D'abord, concevez votre cellule tableview dans StoryBoard.

[2] Mettez en dessous de la méthode déléguée de la vue tablea

// MARK: - Méthodes de délégué Tableview

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

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{

    return <“Your Array”>
}


func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{

    var totalHeight : CGFloat = <cell name>.<label name>.frame.Origin.y    

    totalHeight +=   UpdateRowHeight(<cell name>.<label name>, textToAdd: <your array>[indexPath.row])    

    return totalHeight
}


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{


    var cell : <cell name>! = tableView.dequeueReusableCellWithIdentifier(“<cell identifire>”, forIndexPath: indexPath) as! CCell_VideoCall

    if(cell == nil)
    {
        cell = NSBundle.mainBundle().loadNibNamed("<cell identifire>", owner: self, options: nil)[0] as! <cell name>;
    }


    <cell name>.<label name>.text = <your array>[indexPath.row] as? String



    return cell as <cell name>
}

// MARK: - Méthodes personnalisées

func UpdateRowHeight ( ViewToAdd : UILabel , textToAdd : AnyObject  ) -> CGFloat{


    var actualHeight : CGFloat = ViewToAdd.frame.size.height

    if let strName : String? = (textToAdd as? String)
        where !strName!.isEmpty
    {

        actualHeight = heightForView1(strName!, font: ViewToAdd.font, width: ViewToAdd.frame.size.width, DesignTimeHeight: actualHeight )

    }
    return actualHeight
}
1
PSS

Détails

  • Xcode version 10.2.1 (10E1001), Swift 5

Solution

import UIKit

// MARK: - IdentifiableCell protocol will generate cell identifire based on the class name

protocol Identifiable: class {}
extension Identifiable { static var identifier: String { return "\(self)"} }

// MARK: - Functions which will use a cell class (conforming Identifiable protocol) to `dequeueReusableCell`

extension UITableView {
    typealias IdentifiableCell = UITableViewCell & Identifiable
    func register<T: IdentifiableCell>(class: T.Type) { register(T.self, forCellReuseIdentifier: T.identifier) }
    func register(classes: [Identifiable.Type]) { classes.forEach { register($0.self, forCellReuseIdentifier: $0.identifier) } }
    func dequeueReusableCell<T: IdentifiableCell>(aClass: T.Type, initital closure: ((T) -> Void)?) -> UITableViewCell {
        guard let cell = dequeueReusableCell(withIdentifier: T.identifier) as? T else { return UITableViewCell() }
        closure?(cell)
        return cell
    }
    func dequeueReusableCell<T: IdentifiableCell>(aClass: T.Type, for indexPath: IndexPath, initital closure: ((T) -> Void)?) -> UITableViewCell {
        guard let cell = dequeueReusableCell(withIdentifier: T.identifier, for: indexPath) as? T else { return UITableViewCell() }
        closure?(cell)
        return cell
    }
}

extension Array where Element == UITableViewCell.Type  {
    var onlyIdentifiables: [Identifiable.Type] { return compactMap { $0 as? Identifiable.Type } }
}

Usage

// Define cells classes
class TableViewCell1: UITableViewCell, Identifiable { /*....*/ }
class TableViewCell2: TableViewCell1 { /*....*/ }

// .....

// Register cells
tableView.register(classes: [TableViewCell1.self, TableViewCell2.self]. onlyIdentifiables)

// Create/Reuse cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if (indexPath.row % 2) == 0 {
        return tableView.dequeueReusableCell(aClass: TableViewCell1.self, for: indexPath) { cell in
            // ....
        }
    } else {
        return tableView.dequeueReusableCell(aClass: TableViewCell2.self, for: indexPath) { cell in
            // ...
        }
    }
}

Échantillon complet

N'oubliez pas d'ajouter le code de la solution ici

import UIKit

class ViewController: UIViewController {
    private weak var tableView: UITableView?
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTableView()
    }
}

// MARK: - Setup(init) subviews

extension ViewController {
    private func setupTableView() {
        let tableView = UITableView()
        view.addSubview(tableView)
        self.tableView = tableView
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        tableView.register(classes: [TableViewCell1.self, TableViewCell2.self, TableViewCell3.self].onlyIdentifiables)
        tableView.dataSource = self
    }
}

// MARK: - UITableViewDataSource

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int { return 1 }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 20 }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch (indexPath.row % 3) {
        case 0:
            return tableView.dequeueReusableCell(aClass: TableViewCell1.self, for: indexPath) { cell in
                cell.textLabel?.text = "\(cell.classForCoder)"
            }
        case 1:
            return tableView.dequeueReusableCell(aClass: TableViewCell2.self, for: indexPath) { cell in
                cell.textLabel?.text = "\(cell.classForCoder)"
            }
        default:
            return tableView.dequeueReusableCell(aClass: TableViewCell3.self, for: indexPath) { cell in
                cell.textLabel?.text = "\(cell.classForCoder)"
            }
        }
    }
}

Résultats

enter image description here

1
Vasily Bodnarchuk

C’est purement Swift fonctionne pour moi)

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        var cellIdentifier:String = "CustomFields"
        var cell:CustomCell? = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? CustomCell
        if (cell == nil)
        {
            var nib:Array = NSBundle.mainBundle().loadNibNamed("CustomCell", owner: self, options: nil)
            cell = nib[0] as? CustomCell
        }
        return cell!
    }
1
Gaurav

Décochez la case "Classes de taille" pour moi aussi, mais vous pouvez également ajouter les contraintes manquantes dans le générateur d'interface. Utilisez simplement la fonction intégrée si vous ne voulez pas ajouter les contraintes vous-même. À mon avis, le meilleur moyen consiste à utiliser des contraintes, car la mise en page est indépendante de l'appareil (iPhone ou iPad).

1
empty2308

La documentation de référence Apple est assez complète

https://developer.Apple.com/library/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson7.html

Faites défiler jusqu'à ce que vous voyez cette partie

enter image description here

0
Ives.me

Définir une balise pour imageview et une étiquette dans la cellule

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

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{

    let cell = tableView.dequeueReusableCellWithIdentifier("imagedataCell", forIndexPath: indexPath) as! UITableViewCell

    let rowData = self.tableData[indexPath.row] as! NSDictionary

    let urlString = rowData["artworkUrl60"] as? String
    // Create an NSURL instance from the String URL we get from the API
    let imgURL = NSURL(string: urlString!)
    // Get the formatted price string for display in the subtitle
    let formattedPrice = rowData["formattedPrice"] as? String
    // Download an NSData representation of the image at the URL
    let imgData = NSData(contentsOfURL: imgURL!)


    (cell.contentView.viewWithTag(1) as! UIImageView).image = UIImage(data: imgData!)

    (cell.contentView.viewWithTag(2) as! UILabel).text = rowData["trackName"] as? String

    return cell
}

[~ # ~] ou [~ # ~]

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "imagedataCell")

    if let rowData: NSDictionary = self.tableData[indexPath.row] as? NSDictionary,
        urlString = rowData["artworkUrl60"] as? String,
        imgURL = NSURL(string: urlString),
        formattedPrice = rowData["formattedPrice"] as? String,
        imgData = NSData(contentsOfURL: imgURL),
        trackName = rowData["trackName"] as? String {
            cell.detailTextLabel?.text = formattedPrice
            cell.imageView?.image = UIImage(data: imgData)
            cell.textLabel?.text = trackName
    }

    return cell
}

voir aussi le chargeur de tableImage de github

0
Jaleel Nazir