【问题标题】:UICollectionView cells with Images inside UITableView prototypeUICollectionView 单元格与 UITableView 原型内的图像
【发布时间】:2018-02-18 03:48:19
【问题描述】:

更新:我解决了在 collectionView 上滚动之前无法加载正确图像的主要问题。我向 tableView:cellForRowAtIndexPath 添加了一个 collectionView.reloadData()。我还对预加载序列数组进行了一些更改,而不是在滚动表格时构建它(tableView:cellForRowAtIndexPath)。

如果您有兴趣,请将更新添加到 GitHub。
https://github.com/Druiced/OpenDeck

一旦我弄清楚如何防止应用程序在返回时放入动态值时崩溃(如果我将其设置为 15,应用程序将不会崩溃):

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return count(Array(sequenceArray[collectionView.tag])) / 2
}

原帖: 请求一些指导。

本教程帮助我意识到这必须与我的 DataSource/Delegate 有关。作者使用 addSubview 构建单元,而不是利用 Xcode 原型单元,这似乎是一件很酷的事情,所以我正在尝试这样做。 http://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell

欢迎对我的方法或未能遵循最佳实践提出任何批评。

表格中的每个单元格都有一个 UICollectionView。集合视图中的每个单元格按照保存的“序列”字符串的顺序显示一个图像。示例:“ADKDQDJDTD”链接到 AD.png KD.png QD.png JD.png TD.png

我有两个问题似乎无法解决。

  • numberOfItemsInSection 会在卡片数量由数组长度驱动时变得古怪(返回 handArray.count / 2)。如果我输入一个固定的号码,该应用程序可以运行,但不是很流畅。
  • 当表第一次出现时,直到我上下滚动表时才会显示正确的牌。每个 CollectionView 的数据似乎也在交叉路径,因为在快速上下滚动时会显示错误的卡片。

我几乎可以肯定这与我的数据源的设置方式有关。

DeckTableViewController.swift

import UIKit
import Parse

var deviceID: String?
var noRefresh: Bool?
var sequenceArray: Array<Character>?

class DeckTableViewController: UITableViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var handArray: Array<Character>!
var timeLineData:NSMutableArray = NSMutableArray()

override func viewDidLoad() {
    super.viewDidLoad()
    noRefresh = false
    deviceId = UIDevice.currentDevice().identifierForVendor.UUIDString
}

override func viewDidAppear(animated: Bool) {
    if noRefresh == false {
        loadData()
        noRefresh = true
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

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

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

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

    let cell:DeckTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DeckTableViewCell
    
    let deck:PFObject = timeLineData.objectAtIndex(indexPath.row) as! PFObject

    cell.collectionView.dataSource = self
    cell.collectionView.delegate = self
    
    let sequenceTemp = deck.objectForKey("Sequence") as! String
    handArray = Array(sequenceTemp)
    cell.sequenceId.setTitle(deck.objectId, forState: UIControlState.Normal)
    cell.cardCountLabel.text = "\((count(sequenceTemp)/2))"
    
    // Date to String Stuff
    var dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "(MM-dd) hh:mm:ss"
    cell.timeLabel.text = dateFormatter.stringFromDate(deck.updatedAt!)
    
    let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.itemSize = CGSizeMake(99, 140)
    layout.scrollDirection = UICollectionViewScrollDirection.Horizontal
    
    cell.collectionView.collectionViewLayout = layout

    return cell
}


func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return handArray.count / 2
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    
    let cell:TableCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! TableCollectionViewCell
    var bcolor : UIColor = UIColor.orangeColor()
    cell.layer.borderColor = bcolor.CGColor
    cell.layer.borderWidth = 2
    cell.layer.cornerRadius = 3
    
    var firstLetter: Character!
    var secondLetter: Character!

    //Building card file names from Sequence data
    if (indexPath.row * 2) + 1 <= handArray.count {

        firstLetter = handArray[indexPath.row * 2]
        secondLetter = handArray[indexPath.row * 2 + 1]
        let imageNameString = "\(firstLetter)\(secondLetter).png"
        let front = UIImage(named: imageNameString)
        cell.ImageView.backgroundColor = UIColor.orangeColor()
        cell.ImageView.image = front

    }

    return cell
}

DeckTableViewCell.swift

import UIKit

class DeckTableViewCell: UITableViewCell, UITextViewDelegate {

    @IBOutlet var collectionView: UICollectionView!
    @IBOutlet var sequenceId: UIButton!
    @IBOutlet var timeLabel: UILabel!
    @IBOutlet var cardCountLabel: UILabel!

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

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

    }
}

TableCollectionViewCell.swift

导入 UIKit

class TableCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet var ImageView: UIImageView!
    
}

对于这个示例,我将 (return handArray.count / 2) 设置为 10 并加载了 3 个序列。 顶部中心的数字代表每行卡片的数量。 请注意,CollectionView 没有使用正确的卡片进行更新,它正在从其他 CollectionViews 中获取数据。如果我在此组合中添加更多序列,则在上下滚动时,有时会填充正确的卡片,但不可预测。

感谢您的任何建议,我很高兴回到绘图板上。干杯

【问题讨论】:

    标签: ios iphone uitableview swift uicollectionview


    【解决方案1】:

    好吧,让我们这样想,您的 DeckTableViewController 充当 tableview 的数据源,DeckTableViewCell 充当集合视图的数据源。

    考虑到上述内容,我们创建了一个示例项目 我不会深入,我会在你浏览时给出像教程这样的例子

    让我们在ViewController 中创建一个带有单视图应用程序的示例项目 通过下面的代码,我采用了一个整数数组,其中包含一些值作为要出现在集合视图中的单元格数量。不要忘记添加 tableview 并设置它的数据源和委托。

    在我们编写控制器类之前,我们需要一些类,例如自定义 tableview cell 和自定义 collection view cell,我们首先创建它们

    创建一个新文件,它是UICollectionViewCell 的子类,并将其命名为CustomCollectionViewCellxib 文件。

    class CustomCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak var aLabel: UILabel!  //to show the card number
    @IBOutlet weak var imageView: UIImageView! //imageview i am setting it's background color
    override init(frame: CGRect) {
        super.init(frame: frame)
    
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
    
        }
    }
    

    并像上面的代码一样为标签和图像视图创建一个出口。

    接下来,创建UITableViewCell 的新文件子类并将其命名为CustomTableViewCellxib file。打开CustomTableViewCell.xib 文件并拖放collection view 并将它的datasourcedelegate 设置为cell 而不是控制器。

    并为集合视图创建一个出口并将其命名为foldersCollectionView。 通过下面的代码

    import UIKit
    
    class CustomTableViewCell: UITableViewCell,UICollectionViewDataSource,UICollectionViewDelegate {
    
    @IBOutlet weak var foldersCollectionView: UICollectionView!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init(coder aDecoder: NSCoder) {
       // fatalError("init(coder:) has not been implemented")
        super.init(coder: aDecoder)
    }
    
    var folderCount:Int?
    {
        didSet(value)
        {
    
        }
    }
    
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        //configure our collectionview
        var aFlowLayout : UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        aFlowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
        aFlowLayout.itemSize = CGSizeMake(60.0, 90.0)
        aFlowLayout.minimumLineSpacing = 10.0
        aFlowLayout.minimumInteritemSpacing = 0.0
        aFlowLayout.sectionInset = UIEdgeInsetsMake(2, 9, 0, 10)
        foldersCollectionView.collectionViewLayout = aFlowLayout
        foldersCollectionView.registerClass(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "FOLDER_CELL")
        var cNib:UINib? = UINib(nibName: "CustomCollectionViewCell", bundle: nil)
        foldersCollectionView.registerNib(cNib, forCellWithReuseIdentifier: "FOLDER_CELL")
        foldersCollectionView.frame = self.bounds
    }
    
    
    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    
        // Configure the view for the selected state
    }
    
    class func CreateCustomCell() -> CustomTableViewCell
    {
        var nibElements: Array = NSBundle.mainBundle().loadNibNamed("CustomTableViewCell", owner: self, options: nil)
        var item: AnyObject?
        for item in nibElements
        {
            if item is UITableViewCell
            {
                return item as CustomTableViewCell
            }
        }
        return item as CustomTableViewCell
    }
    
    
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        var cell :CustomCollectionViewCell? = collectionView.dequeueReusableCellWithReuseIdentifier("FOLDER_CELL", forIndexPath: indexPath) as? CustomCollectionViewCell
        //hear u can modify which image to be displayed in the collection view cell
    
        cell?.aLabel.text = "Card:\(indexPath.row)"
        return cell!
    }
    
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
       return folderCount!
    }
    
    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
       return 1
       }
    }
    

    现在我们将代码 ViewController 类 现在刚刚过去的代码

    class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
    var cardCountArray:[Int] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        cardCountArray = [5,15,6,12,7,10]
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func numberOfSectionsInTableView(tableView: UITableView) -> Int
    {
        return cardCountArray.count
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
       return  1
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        var cell:CustomTableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? CustomTableViewCell;
        if(cell == nil)
        {
            cell = CustomTableViewCell.CreateCustomCell()
        }
        cell?.folderCount = cardCountArray[indexPath.section]
        cell?.foldersCollectionView.reloadData()
        cell?.clipsToBounds = true
        return cell!;
    }
    
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
    {
        return 100.0
    }
    
    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    
        var headerView:UIView = UIView(frame: CGRectMake(0, 0, tableView.bounds.size.width, 70.0))
        var labelTitle:UILabel = UILabel(frame: CGRectMake(0, 0, tableView.bounds.size.width, 35))
        var descriptionTitle:UILabel = UILabel(frame: CGRectMake(0, 20,tableView.bounds.size.width , 30))
        headerView.addSubview(labelTitle)
        headerView.addSubview(descriptionTitle)
        labelTitle.text = "TOTAL_CARDS in section:\(section)"
        descriptionTitle.text = "This CARD_SECTION contains \(cardCountArray[section]) CARDS"
        return headerView
    }
    
     func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 50.0
      }
     }
    

    结果如下所示

    如果有任何遗漏请告诉我

    对于您的评论我有一个数组,例如 ["2C3C4C5C6C7C", "AD2D3D4D5D", "9H8H7H"]

    为此,您需要进行以下修改

    //for first row u get like this
    //the string for the row is 2C3C4C5C6C7C
    //stringForCell = "2C3C4C5C6C7C"
    //2C
    //3C
    //4C
    //5C
    //6C
    //7C
    //for other cells u can get like below
    //the string for the row is AD2D3D4D5D
    //stringForCell = "AD2D3D4D5D"
    //AD
    //2D
    //3D
    //4D
    //5D
    //the string for the row is 9H8H7H
    //stringForCell = "9H8H7H"
    //9H
    //8H
    //7H
    
    //in controller controller class define array of string
    class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
    var cardCountArray:[Int] = []
    var stringArray : [String] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        stringArray = ["2C3C4C5C6C7C", "AD2D3D4D5D", "9H8H7H"] 
    }
    
    func numberOfSectionsInTableView(tableView: UITableView) -> Int
    {
       // return cardCountArray.count
        return stringArray.count
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        var cell:CustomTableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? CustomTableViewCell;
        if(cell == nil)
        {
            cell = CustomTableViewCell.CreateCustomCell()
        }
        //cell?.folderCount = cardCountArray[indexPath.section]
        cell?.stringForCell = stringArray[indexPath.section];
        cell?.foldersCollectionView.reloadData()
        cell?.clipsToBounds = true
        return cell!;
    }
    
    
    //in custom tableview cell add a string variable
    class CustomTableViewCell: UITableViewCell,UICollectionViewDataSource,UICollectionViewDelegate {
    
    @IBOutlet weak var foldersCollectionView: UICollectionView!
    var stringForCell:String = "" //add the string to hold the string
    
    //rest of the code
    
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        var cell :CustomCollectionViewCell? = collectionView.dequeueReusableCellWithReuseIdentifier("FOLDER_CELL", forIndexPath: indexPath) as? CustomCollectionViewCell
        var str:NSString = stringForCell
        var length = str.length
        var totalLlength:Int =  length/2
        var indexStart   = indexPath.row * (2);
        var aRange = NSMakeRange(indexStart, 2)
        var cardString:NSString = str.substringWithRange(aRange)
        println(cardString)
        cell?.aLabel.text   = "Card: \(cardString)"
        return cell!
    }
    
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    
       println("the string for the row is \(stringForCell)")
        var str:NSString = stringForCell
        var length:Int = str.length
        return length / 2
       //return folderCount!
    }
    
    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
     return 1
    }
    

    我写了一篇关于how to add collection view inside custom table view cell 的详细帖子,希望这比这篇帖子给出更详细的解释。

    【讨论】:

    • 感谢您抽出时间回复。我仍在考虑按照您使用 addSubView 处理它的方式重新编码这个应用程序(我试图避免)。我发现添加一个 collectionView.reloadData() 并用序列预加载一个数组解决了我的大部分问题。现在我唯一的问题是 collectionView numberOfItemsInSection return count(Array(sequenceArray[collectionView.tag])) / 2 如果不是 FIXED 值(例如 15),它会在向下滚动表格时崩溃。如果你添加了项目到 github '很好奇github.com/Druiced/OpenDeck
    • 嗨@Shan,我创建了一个新项目并准确复制了所有内容。看来我必须将新的类文件命名为 .swift 而不是 .xib。请问2个问题。 1)当你说创建插座时,你的意思是,我需要构建一个故事板来补充你的代码并控制将每个组件拖到代码中的 IBOutlets 中?这就是我通常创建网点的方式,但是您的示例似乎仅使用代码就可以完成? 2)在CustomTableViewCell类的顶部,init(frame:CGRect){super.init(frame:frame)}错误:“必须调用超类'UITableViewCell'的指定初始化程序谢谢
    • @AndrewDouwesew 您的主要项目将是情节提要项目,对于第一个问题:是的,您需要使用 .xib 文件创建一个新的子类 tableview 单元格,并在该拖放视图组件和板条箱出口对于视图组件,在我的示例中,我没有使用 xib 文件的代码。对于问题 2。我没有收到任何这样的错误.. 它对我来说工作正常..
    • 你太棒了。我只需要注释掉我之前提到的覆盖初始化函数,它就可以工作了!我以前从未在我的项目中使用过 xib 文件,这给我带来了一些困惑。谢谢先生。
    • 嗨@Shan,现在我已经使用.xib 文件重建了整个项目,我学到了很多东西!我遇到了和以前一样的数据问题。我有一个数组,例如 ["2C3C4C5C6C7C", "AD2D3D4D5D", "9H8H7H"]。使用您的代码,如何让 tableView(row 0) 仅显示 6 张卡片。然后有collectionCell0 = 2C,collectionCell1 = 3C等标签。我得到'Array Index Out Of Range',因为'return folderCount'部分中的numberOfItems与该数组中字符串的长度不匹配。如果您能抽出时间,我将不胜感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    • 2023-03-18
    相关资源
    最近更新 更多