web-dev-qa-db-ja.com

swiftにカスタムテーブルビューセルを作成する

IBOutletsがいくつかあるカスタムセルクラスがあります。ストーリーボードにクラスを追加しました。すべてのコンセントを接続しました。 cellForRowAtIndexPath関数は次のようになります。

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
    }

これが私のカスタムセルクラスです。

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)


    }
}

アプリを実行すると、すべてのセルが空になります。 self.venueService.mainCategoriesArray()をログアウトしましたが、すべての正しい文字列が含まれています。また、ラベルに等しい実際の文字列を入れてみましたが、同じ結果が得られました。

私は何が欠けていますか?どんな助けも大歓迎です。

40
Nilzone-

さまざまな提案をありがとうございますが、私は最終的にそれを理解しました。カスタムクラスが正しくセットアップされました。必要なのは、ストーリーボードでカスタムクラスを選択することだけでした。それを削除して、再度選択します。それはあまり意味がありませんが、それは私のために働いてしまいました。

11
Nilzone-

カスタムテーブルビューセルの例

Xcode 9およびSwift 4でテスト済み

元の質問の質問者は問題を解決しました。私はこの答えを、同じことをしようとしている他の人のためのミニ自己完結型のサンプルプロジェクトとして追加しています。

完成したプロジェクトは次のようになります。

enter image description here

新しいプロジェクトを作成する

単一のビューアプリケーションにできます。

コードを追加する

新しいSwiftファイルをプロジェクトに追加します。 MyCustomCell.Swiftという名前を付けます。このクラスは、ストーリーボードのセルに追加するビューのアウトレットを保持します。

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

これらのコンセントは後で接続します。

ViewController.Swiftを開き、次のコンテンツがあることを確認します。

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).")
    }
}

ストーリーボードをセットアップする

View ControllerにTable Viewを追加し、自動レイアウトを使用してView Controllerの4辺にピン留めします。次に、テーブルビューセルをテーブルビューにドラッグします。次に、ビューとラベルをプロトタイプセルにドラッグします。 (テーブルビューセルを選択し、 手動で行の高さを設定 サイズインスペクターでより高い値に設定して、作業の余地を増やす必要があります。)自動レイアウトを使用して、ビューとテーブルビューセルのコンテンツビュー内での配置方法にラベルを付けます。たとえば、ビューを100x100にしました。

enter image description here

その他のIB設定

カスタムクラス名と識別子

テーブルビューセルを選択し、カスタムクラスをMyCustomCell(追加したSwiftファイル内のクラスの名前)に設定します。また、識別子をcell(上記のコードでcellReuseIdentifierに使用したものと同じ文字列)に設定します。

enter image description here

コンセントを接続する

  • ストーリーボードのテーブルビューからtableViewコードのViewController変数へのドラッグを制御します。
  • Prototypeセルのビューとラベルに対して、myViewクラスのmyCellLabelおよびMyCustomCell変数に対して同じことを行います。

完成した

それでおしまい。これでプロジェクトを実行できるはずです。

ノート

  • ここで使用した色付きのビューは、何でも置き換えることができます。明らかな例はUIImageViewです。
  • TableViewを機能させようとしている場合は、 このさらに基本的な例 を参照してください。
  • セルの高さが可変のテーブルビューが必要な場合は、 この例 を参照してください。
98
Suragch

これは、.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

私は同じ問題を抱えています。

一般的に私がしたことはあなたと同じです。

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

および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;
}

ええ、テーブルビューには何も表示されません!しかし、実際には何かを示していると思います... println(cell.testLabel)から取得したログは、すべてのラベルが実際に表示されていることを示しているためです。

しかし!彼らのフレームは奇妙で、このようなものがあります:

フレーム=(0 -21; 42 21);

したがって、(x、y)として(0、-21)があるため、ラベルはセルの境界外のどこかに表示されるだけです。

次のように手動でフレームを追加しようとしています:

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

悲しいことに、それは機能しません。

--------------- 10分後に更新-----------------

I DID IT。そのため、問題はサイズクラスに起因するようです。

.storyboardファイルをクリックして、[ファイルインスペクター]タブに移動します

サイズクラスのチェックボックスをオフにします

そして最後に、私の「とても悲しい」ラベルが出てきました!

14
The Little DD

最終更新バージョンは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]最初にStoryBoardでテーブルビューセルを設計します。

[2]テーブルビューデリゲートメソッドの下に配置

// MARK:-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:-カスタムメソッド

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

詳細

  • Xcodeバージョン10.2.1(10E1001)、Swift 5

解決

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

使用法

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

完全なサンプル

ソリューションコードをここに追加することを忘れないでください

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

結果

enter image description here

1

それは純粋にSwift表記法です

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

[サイズクラス]チェックボックスのチェックを外しても機能しますが、インターフェイスビルダーで不足している制約を追加することもできます。独自に制約を追加したくない場合は、組み込み関数を使用してください。レイアウトはデバイス(iPhoneまたはiPad)から独立しているため、制約の使用は-私の意見では-より良い方法です。

1
empty2308

実際のAppleリファレンスドキュメントは非常に包括的な

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

この部分が表示されるまで下にスクロールします

enter image description here

0
Ives.me

セルにイメージビューとラベルのタグを設定します

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
}

または

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
}

github のTableImageローダーも参照してください。

0
Jaleel Nazir