Swift: UIView appear in UITableView cell - ios

Im having an issue putting a UIView that I created in a specific UITableView cell. Here is my code:
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
//MARK : Properties
var tableView = UITableView()
var items: [String] = ["Age", "Gender", "Smoking Hx", "Occup. -Ag", "Family Hx", "Chronic Lung Disease Radiology", "Chronic Lung Disease Hx", "Nodule Border", "Nodule Location", "Satellite Lesions", "Nodule Pattern Cavity", "Nodule Size"]
var navigationBar = NavigationBar()
var gender = GenderView()
var maleIcon = MaleIconView()
override func viewDidLoad() {
super.viewDidLoad()
//Create TableView
tableView.frame = CGRectMake(0, self.view.bounds.height * 0.097, self.view.bounds.width,
self.view.bounds.height - self.view.bounds.height * 0.097);
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
//Create Navigation Bar with custom class
self.navigationBar = NavigationBar(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height * 0.097))
self.view.addSubview(navigationBar)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
cell.textLabel?.text = self.items[indexPath.row]
//Cell wont turn grey when selected
cell.selectionStyle = UITableViewCellSelectionStyle.None
//Want to add UIView male Icon in first row
if(indexPath.row == 0){
maleIcon = MaleIconView(frame: CGRect(x: 0, y: 0, width: 55, height: 55))
maleIcon.center.x = cell.center.x + cell.center.x * 0.5
maleIcon.center.y = cell.contentView.center.y
maleIcon.layer.cornerRadius = 0.5 * maleIcon.bounds.size.width
//maleIcon.layer.borderWidth = 3.0
cell.addSubview(maleIcon)
}
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return self.view.bounds.height * 0.15
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
}
Maybe the issue exists within the MaleIconView()? Here is the code to that:
class MaleIconView: UIView {
var maleView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
self.frame = frame
setUpView()
}
func setUpView(){
maleView.frame = CGRectMake(0, 0, self.bounds.width, self.bounds.height)
maleView.alpha = 1
maleView.backgroundColor = UIColor.blackColor()
maleView.layer.cornerRadius = 0.5 * maleView.bounds.size.width
self.addSubview(maleView)
}
func hide(){
self.removeFromSuperview()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Im trying to get the UIView to appear on the right side of the cell 0. There is also this issue where the indexPath's are all off, i think this could be of some issue to why the UIView appears in multiple cells. Thank you in advance!

Here is the code for what should help you with your issues. I made a few assumptions about how you may be trying to implement. But this should be a great start for you.
https://www.dropbox.com/sh/2ilyfnc1pqurjfd/AAC2rU-zlvUtjdKYV33JrQJQa?dl=0
I also highly recommend that you use auto layout for your various view dimensions rather than hard coding weird offsets. It may be difficult to start with. But it definitely pays off in the long run!

It's kinda strange that maleIcon is UIViewController property in your code.
Did you try to put in cellForRowAtIndexPath?
like that:
//Want to add UIView male Icon in first row
if(indexPath.row == 0){
let maleIcon = MaleIconView(frame: CGRect(x: 0, y: 0, width: 55, height: 55))
I'm not sure it will help with reusable cells though. What will help (but there is slightly more work) is to create your own cell class, add maleIcon as property, register this class with your table and put this in your cellForRowAtIndexPath like that:
if (indexPath.row == 0) {
cell.maleIcon.hidden = false}
else {
cell.maleIcon.hidden = true}

Related

How to fix dynamic height for individual cells as UIautodimensions is not working

I am creating a wall page like twitter or Facebook in which user can post on the wall it can include image and just text. So based on the content the cell's heights must change, if the post is of one line the row height must be appropriate.
I tried using UITableViewAutomaticDimensions, but its not working with my code please do help me.
import UIKit
class wallPageViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var tableOfApps : UITableView?
var appNames: [String]? = []
var apps: [wallPageModel]?
var dynamic_height : CGFloat = 150.0
var addPost : UITextField?
var readMore : UITextView?
func loadTableOfApps(){
//appNames = ["jkbajdba", "abfajfb", "akjbfkjag", "ahbfkajf" ]
let provider = wallPageProvider()
apps = provider.getApps()
let tableHeight = view.frame.size.height
tableOfApps = UITableView(frame: CGRect(x: 10, y: 60, width: 300, height: tableHeight))
tableOfApps!.delegate = self
tableOfApps!.dataSource = self
tableOfApps?.separatorStyle = UITableViewCellSeparatorStyle.none
//self.tableOfApps?.rowHeight = UITableViewAutomaticDimension
//self.tableOfApps?.estimatedRowHeight = UITableViewAutomaticDimension
print("load table of apps")
view.addSubview(tableOfApps!)
}
override func viewDidLoad() {
super.viewDidLoad()
loadTableOfApps()
loadAddPost()
tableOfApps?.estimatedRowHeight = 150.0
tableOfApps?.rowHeight = UITableViewAutomaticDimension
view.backgroundColor = UIColor(red: 232/255, green: 234/255, blue: 246/255, alpha: 1.0)
// Do any additional setup after loading the view.
}
func loadAddPost(){
addPost = UITextField(frame: CGRect(x: 10, y: 20, width: 300, height: 30))
addPost?.placeholder = "Stay safe, post a tip!"
addPost?.isUserInteractionEnabled = true
addPost?.borderStyle = UITextBorderStyle.roundedRect
addPost?.autocapitalizationType = .none
view.addSubview(addPost!)
addPost?.addTarget(self, action: #selector(writeComment), for: UIControlEvents.touchDown)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("app coun\(apps!.count)")
return apps!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell : wallModelTableViewCell?
cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? wallModelTableViewCell
if cell == nil {
cell = wallModelTableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
}
let app = apps![indexPath.row]//reading the array of data hence provider
//association of provider and view
//this is the processs from where view can read the data from provide
cell!.iconImageLabel!.image = app.icon
cell!.titleLabel!.text = app.title
cell?.backgroundColor = UIColor.white
cell!.commentsLabel?.image = app.comments_Label
cell?.commentsLabel?.center = CGPoint(x: tableView.frame.size.width/2, y: dynamic_height-20)
cell?.likeButtonLabel?.image = app.likeButton
cell?.likeButtonLabel?.center = CGPoint(x: (tableView.frame.size.width/2)-130, y: dynamic_height-20)
/*cell?.likeButtonLabel?.leftAnchor.constraint(equalTo: tableView.leftAnchor, constant: 50)*/
cell!.feedTextLabel!.text = app.feedText
cell?.feedTextLabel?.sizeToFit()//so that it can expand the data more than two lines
cell?.feedTextLabel?.backgroundColor = UIColor.clear
//Limiting UIlabel to 125 characters
if (cell?.feedTextLabel?.text.count)! > 125{
/*
let index = cell?.feedTextLabel?.text.index((cell?.feedTextLabel?.text.startIndex)!, offsetBy: 125)
cell?.feedTextLabel?.text = cell?.feedTextLabel?.text.substring(to: index!)
cell?.feedTextLabel?.text = cell?.feedTextLabel?.text.appending("...")*/
//cell?.feedTextLabel?.attributedText = NSAttributedString(string: "...readmore")
}
cell?.layer.cornerRadius = 6.0
cell?.isUserInteractionEnabled = false
cell?.titleLabel?.isUserInteractionEnabled = true
tableOfApps?.backgroundColor = UIColor.clear
tableOfApps?.backgroundView?.isOpaque = false
tableOfApps!.estimatedRowHeight = 150.0
tableOfApps!.rowHeight = UITableViewAutomaticDimension
print("table view cell for row")
/*let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector( self.labelAction(gesture:)))
cell?.feedTextLabel?.addGestureRecognizer(tap)
cell?.feedTextLabel?.isUserInteractionEnabled = true
tap.delegate = self as! UIGestureRecognizerDelegate*/
return cell!
}
/*#objc func labelAction(gesture: UITapGestureRecognizer){
}*/
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
print("height for row")
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 150.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
#objc func writeComment(){
let addComment = addCommentViewController()
navigationController?.pushViewController(addComment, animated: true)
}
/*
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
I want each row must have dynamic height as the content is provided by the user if the content contains 150 characters the height of the cell must be 200+ if content contains less than 125 characters the height must be as adequate to read.

UITableview scrolling is not responding properly?

booktable.frame = CGRect(x: 0, y: booktopview.bounds.height, width: screenWidth, height: screenHeight-booktopview.bounds.height-tabbarView.bounds.height)
booktable.register(UITableViewCell.self, forCellReuseIdentifier: "mycell")
booktable.dataSource = self
booktable.delegate = self
booktable.separatorColor = UIColor.lightGray
booktable.backgroundColor = UIColor.clear
booktable.separatorStyle = .singleLine
bookview.addSubview(booktable)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(tableView == booktable)
{
let cell1 = booktable.dequeueReusableCell(withIdentifier: "mycell")
for object in (cell1?.contentView.subviews)!
{
object.removeFromSuperview();
}
let img :UIImageView = UIImageView()
let lbl : UILabel = UILabel()
img.frame = CGRect(x: 15, y: 15, width: 80, height: 130)
img.image = imgarray[indexPath.row]
img.layer.borderWidth = 1.0
img.layer.borderColor = UIColor.lightGray.cgColor
cell1?.contentView.addSubview(img)
imgheight = img.bounds.height
lbl.frame = CGRect(x: img.bounds.width + 40, y: (imgheight+40-80)/2, width: booktable.bounds.width-img.bounds.width + 40 - 100, height: 80)
lbl.text = imgname[indexPath.row]
lbl.numberOfLines = 0
lbl.textAlignment = .left
lbl.font = UIFont(name: "Arial", size: 23)
lbl.textColor = UIColor.black
cell1?.selectionStyle = .none
cell1?.contentView.addSubview(lbl)
return cell1!
}
The code shown above is for book table, which sometimes scrolls like normal and sometimes not scrolling at all. I am doing all the code programatically. I have tested this on both simulators and devices but still the problem exists. Any help is appreciated...
Create Custom UITableViewCell, let's say it is ListTableCell
class ListTableCell: UITableViewCell {
#IBOutlet weak var lblTemp: UILabel!
#IBOutlet weak var imgTemp: UIImage!
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
}
}
I've created UITableViewCell with xib like this and bind IBOutlets
Let's say we have struct Model and array like this
struct Model {
let image : UIImage
let name: String
}
for i in 0...10 {
let model = Model(image: #imageLiteral(resourceName: "Cat03"), name: "Temp \(i)")
array.append(model)
}
Now on ViewController viewDidLoad() method,
tableView.register(UINib(nibName: "ListTableCell", bundle: nil), forCellReuseIdentifier: "ListTableCell")
Implement UITableViewDataSource methods like this,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ListTableCell") as! ListTableCell
let model = array[indexPath.row]
cell.lblTemp.text = model.name
cell.imgTemp.image = model.image
return cell
}
FYI
For different tableviews, you can create different custom cell the same way and cellForRowAt indexPath and numberOfRowsInSection method will change appropriately.
Let me know in case of any queries.
UPDATE
Follow this and this to create CustomTableCell programmatically

How To Share Same UIView Between Multiple UITableView Cells

Objective
When the user clicks on any of the 3 blue buttons, all buttons change to the same color.
Note: this is an abstraction of a shared progress view problem, it's therefore important that only one UIView is shared (or mimicked) across my three rows
Here is a compilable Swift project:
import UIKit
class ToggleButton: UIButton {
var connectedView: UIView?
func onPress() {
self.isHidden = true
self.connectedView?.isHidden = false
}
}
class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView = UITableView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
var myView: UIView? = nil
var toggleBtn: ToggleButton? = nil
override func viewDidLoad() {
self.setupTableView()
}
fileprivate func setupTableView() {
self.tableView.dataSource = self
self.tableView.delegate = self
self.tableView.backgroundColor = UIColor.white
self.tableView.isOpaque = true
self.view.addSubview(self.tableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "CellIdentifier")
let frame = CGRect(x: 10, y: 10, width: 30, height: 30)
if let view = self.myView, let btn = self.toggleBtn {
cell.addSubview(view)
cell.addSubview(btn)
} else {
let myView = UIView(frame: frame)
myView.backgroundColor = UIColor.green
myView.isHidden = true
cell.addSubview(myView)
let toggleBtn = ToggleButton(frame: frame)
toggleBtn.backgroundColor = UIColor.blue
toggleBtn.addTarget(self, action: #selector(onPress), for: .touchUpInside)
toggleBtn.connectedView = myView
cell.addSubview(toggleBtn)
}
return cell
}
#objc func onPress(_ sender: Any) {
if let button = sender as? ToggleButton {
button.onPress()
}
}
}
Any help appreciated.
The concept of UITableViewCell is made to be very independent each other.
So the only thing you can do it having a bool flag in your ViewController, then you init your 3 cells with this flags.
And finally each time the button is pressed you toggle the flag en reload your tableView.

Cell width too big for tableview width

I have a programmatic tableview nested in a caraousel, but when it displays, the programmatic cell is always set wider than the tableview its in. If I print the carousel item width, tableview width and cell width I get: 281, 281, 320(iphone5 screen width). I tried adding constraints to the cell but keep getting nil errors, I believe because the cell hasn't been made yet. So I'm not sure where to put the constraints so that I stop getting these errors, I only need the cell content view width to match the tableview width, but how do I get the tableview width in my custom cell which has been made programmatically? Heres my current code without any constraints:
TableView:
import UIKit
class SplitterCarouselItemTableView: UITableView {
var splitter: BillSplitter?
required init(frame: CGRect, style: UITableViewStyle, splitter: BillSplitter) {
super.init(frame: frame, style: style)
self.splitter = splitter
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupView() {
if Platform.isPhone {
let tableViewBackground = UIImageView(image: UIImage(data: splitter?.image as! Data, scale:1.0))
self.backgroundView = tableViewBackground
tableViewBackground.contentMode = .scaleAspectFit
tableViewBackground.frame = self.frame
}
self.backgroundColor = .clear
self.separatorStyle = .none
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.register(SplitterCarouselItemTableViewCell.classForCoder(), forCellReuseIdentifier: "splitterCarouselItemTableViewCell")
let cell: SplitterCarouselItemTableViewCell = tableView.dequeueReusableCell(withIdentifier: "splitterCarouselItemTableViewCell") as! SplitterCarouselItemTableViewCell
var item = ((allBillSplitters[tableView.tag].items)?.allObjects as! [Item])[indexPath.row]
if allBillSplitters[tableView.tag].isMainBillSplitter {
getMainBillSplitterItems(splitter: allBillSplitters[tableView.tag])
item = mainBillSplitterItems[indexPath.row]
}
let count = item.billSplitters?.count
if count! > 1 {
cell.name!.text = "\(item.name!)\nsplit \(count!) ways"
cell.price!.text = "£\(Double(item.price)/Double(count!))"
} else {
cell.name!.text = item.name!
cell.price!.text = "£\(item.price)"
}
return cell
}
Cell:
import UIKit
class SplitterCarouselItemTableViewCell: UITableViewCell {
var name: UILabel!
var price: UILabel!
var view: UIView!
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:)")
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: "splitterCarouselItemTableViewCell")
self.backgroundColor = .clear
let width = Int(contentView.bounds.width)
let height = Int(contentView.bounds.height)
view = UIView(frame: CGRect(x: 0, y: 2, width: width, height: height - 4 ))
view.backgroundColor = UIColor.white.withAlphaComponent(0.5)
let viewHeight = Int(view.bounds.height)
let viewWidth = Int(view.bounds.width)
price = UILabel(frame: CGRect(x: viewWidth - 80, y: 0, width: 75, height: viewHeight))
price.font = UIFont.systemFont(ofSize: 15.0)
price.textAlignment = .right
name = UILabel(frame: CGRect(x: 5, y: 0, width: width, height: viewHeight))
name.font = UIFont.systemFont(ofSize: 15.0)
name.numberOfLines = 0
view.addSubview(name)
view.addSubview(price)
contentView.addSubview(view)
}
}
I understand the init shouldn't be filled with all that code and will be extracted later. Its just there until i resolve the width issue.
Thanks for any help.
The challenge is that the tableView.dequeueReusableCell(withIdentifier:) method indirectly calls init(frame:) on your UITableViewCell class. There are a couple of ways to solve this:
Override init(frame:) in SplitterCarouselItemTableViewCell and set your width there when you call super.init(frame:)
Modify your cell.frame in your func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) method
Using Autolayout is problematic with UITableView cells. You don't want to go messing with all the subviews there.
Try adding this
cell.frame = CGRect(x: CGFloat(Int(cell.frame.minX)),
y: CGFloat(Int(cell.frame.minY)),
width: tableView.frame.width,
height: cell.frame.height)
to your
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
This fixed the problem for me.
My UITableViewController and UITableViewCell were done programmatically
in viewDidLoad Grab your tableView Outlet or your tableView Instance if you made it programmatically, then access to rowHeight and give an Value to it : Like This code Below:
enter code here
private let MenuTableView:UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.register(FoodTableViewCell.self, forCellReuseIdentifier: FoodTableViewCell.identifier)
tableView.showsVerticalScrollIndicator = false
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(MenuTableView)
MenuTableView.rowHeight = 50
}

UICollectionViewCell only shown when debug step by step

I can't get my custom UICollectionViewCell to be shown when run without put a breakpoint in func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell and debug step by step through it. After that my custom cells will be shown fine. Something wrong from xcode builder or my code?
p/s: I register my custom UICollectionViewCell by className like this: clvDishes.registerClass(PosItemsCollectionViewCell.classForCoder(), forCellWithReuseIdentifier: "DishesCollectionViewCell") and create cell's layout all in code(not using xib file)
Here is my code
class PosCollectionViewSource<T>: NSObject, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var items:[T] = []
var identifier:String!
override init() {
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(identifier + "CollectionViewCell", forIndexPath: indexPath)
switch(String(T)){
case "PosItemsInfo":
let itemsCell = cell as! PosItemsCollectionViewCell
let posItems = items as Any as! [PosItemsInfo]
itemsCell.updateCell(posItems[indexPath.item])
return itemsCell
default : break
}
return cell
}
}
class PosItemsCollectionViewCell: UICollectionViewCell{
private var _lblItemName:UILabel!
private var _lblItemPrice:UILabel!
private var _vOverlayInfo:UIView!
private var _imvPictureContainer:UIImageView!
private var _vSeparate:UIView!
private var _imvWarning:UIImageView!
private var _imvSeason:UIImageView!
private var _lblRemaining:UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
let uiFont = UIFont(name: "HelveticaNeue-Thin", size: 17) as UIFont?
_lblItemName = UILabel()
_lblItemName.textColor = UIColor.whiteColor()
_lblItemName.font = uiFont
_lblItemPrice = UILabel()
_lblItemPrice.textColor = UIColor.whiteColor()
_lblItemPrice.font = uiFont
_vSeparate = UIView()
_vSeparate.backgroundColor = UIColor(hexString: "FFFFFF", a: 0.5)
_vOverlayInfo = UIView()
_vOverlayInfo.backgroundColor = UIColor(hexString: "#000000", a:0.21)
_imvPictureContainer = UIImageView()
_imvPictureContainer.image = UIImage(named: "pos_DefaultDishIcon")
_vOverlayInfo.addSubview(_lblItemName)
_vOverlayInfo.addSubview(_lblItemPrice)
_vOverlayInfo.addSubview(_vSeparate)
_lblRemaining = UILabel()
_lblRemaining.textColor = UIColor(hexString: "E86E2B")
_lblRemaining.SetBorder("E86E2B", radius: 0)
_lblRemaining.backgroundColor = UIColor.whiteColor()
_lblRemaining.font = UIFont(name: "HelveticaNeue-Medium", size: 20)
_lblRemaining.textAlignment = NSTextAlignment.Center
_imvSeason = UIImageView()
_imvSeason.image = UIImage(named: "pos_SeasonIcon")
_imvWarning = UIImageView()
contentView.addSubview(_imvPictureContainer)
contentView.addSubview(_vOverlayInfo)
contentView.backgroundColor = UIColor.whiteColor()
}
func updateCell(item:PosItemsInfo){
_lblItemName.text = item.itemName
_lblItemPrice.text = item.itemPrice?.toString("%.2f")
_lblRemaining.text = item.itemQtyRemaining?.toString()
if item.itemQtyStatus == PosItemQtyStatus.SoldOut{
contentView.addSubview(_imvWarning)
_imvWarning.image = UIImage(named: "pos_SoldOut")
}
else if item.itemQtyStatus == PosItemQtyStatus.LowInStock{
contentView.addSubview(_imvWarning)
contentView.addSubview(_lblRemaining)
_imvWarning.image = UIImage(named: "pos_LowStock")
_lblRemaining.text = item.itemQtyRemaining?.toString()
}
if item.itemIsSeason == true {
contentView.addSubview(_imvSeason)
}
}
override func layoutSubviews() {
_vOverlayInfo.frame = CGRect(x: 0, y: contentView.frame.height - 60, width: 205, height: 60)
_imvPictureContainer.frame = CGRect(x: 0, y: 0, width: 205, height: 160)
_lblItemName.frame = CGRect(x: 10, y: 0, width: contentView.frame.width - 20, height: _vOverlayInfo.frame.height/2 )
_lblItemPrice.frame = CGRect(x: 10, y: _lblItemName.frame.height, width: contentView.frame.width - 20, height: _vOverlayInfo.frame.height/2 )
_vSeparate.frame = CGRect(x: 8, y: _lblItemName.frame.height, width: contentView.frame.width - 16, height: 1 )
_lblRemaining.frame = CGRect(x: (contentView.frame.width - 50)/2, y: 40, width: 50, height: 50)
_imvWarning.frame = CGRect(x: 125, y: 0, width: 81, height: 74)
}
override func didMoveToSuperview() {
self.setNeedsLayout()
self.layoutIfNeeded()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
}
class PosDishesVCtrl: PosBaseController {
#IBOutlet weak var clvDishes: UICollectionView!
private var _clvDataSource:PosCollectionViewSource<PosItemsInfo>!
private var _items:[PosItemsInfo]!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: String(self.dynamicType), bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
modifiedOrUpdateUI()
renderDishes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func modifiedOrUpdateUI(){
clvDishes.setCollectionViewLayout(LayoutGridType, animated: false)
clvDishes.registerClass(PosItemsCollectionViewCell.classForCoder(), forCellWithReuseIdentifier: "DishesCollectionViewCell")
clvDishes.backgroundColor = UIColor(hexString: "979797", a: 1)
clvDishes.showsHorizontalScrollIndicator = false
clvDishes.showsVerticalScrollIndicator = false
clvDishes.pagingEnabled = false
clvDishes.autoresizingMask = UIViewAutoresizing.FlexibleWidth
clvDishes.contentSize = CGSize(width: clvDishes.frame.width, height: clvDishes.frame.height)
clvDishes.scrollsToTop = false
}
func renderDishes(){
if(_clvDataSource == nil){
_clvDataSource = PosCollectionViewSource<PosItemsInfo>()
_clvDataSource.identifier = "Dishes"
_items = [PosItemsInfo]()
}
for var i = 0; i < 12; i++ {
let item = PosItemsInfo()
item.itemName = "Dish " + String(i)
item.itemPrice = Double(i)
item.itemQtyRemaining = 4
if(i%2 == 0){
item.itemIsSeason = true
item.itemQtyStatus = PosItemQtyStatus.LowInStock
}
else {
item.itemQtyStatus = PosItemQtyStatus.SoldOut
}
_items.append(item)
}
clvDishes.setCollectionViewLayout(LayoutGridType, animated: false)
_clvDataSource.items = _items
clvDishes.dataSource = _clvDataSource
clvDishes.delegate = PosCollectionViewDelegate(ctr: self)
clvDishes.reloadData()
clvDishes.collectionViewLayout.invalidateLayout()
}
}
Any idea would be appreciate!
It looks like your DataSource method:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int)
-> Int
{
return items.count
}
is always returning zero. Your row indices correspond to the number of items (cells) you'll return here.
EDIT:
Looking at the code you've provided, it isn't apparent that you ever add any items to the PosCollectionViewSource.items array, so I expect items.count to return zero. If it does not, then you must be adding items to the array somewhere else (in source code you haven't posted).
Looking at your code, I notice that the way you're setting up your custom cell class and using it is a bit complicated (possibly wrong) and could be better.
Assuming that you are adding elements to the items array somewhere, let's try a different approach:
Here's a pattern I use for cell types with reuseIdentifiers (UITableViewCell, UICollectionViewCell, etc.):
class CustomCell: UICollectionViewCell {
// This will do the right thing for CustomCell and its subclasses
class var reuseIdentifier: String { return "\(self)" }
}
Now, when you register the custom class, do it like this:
collectionView.registerClass(CustomCell.self, CustomCell.reuseIdentifier)
and fetch one like this:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(CustomCell.reuseIdentifier, forIndexPath: indexPath)
as! CustomCell
// setup the cell as necessary:
cell.contentView.backgroundColor = UIColor.yellowColor()
return cell
}
I had a very similar problem on iOS 14 (simulator & actual devices). Cells would only be displayed if I stopped running the app with a debug breakpoint before returning each cell.
A solution that worked for me was to call cell.setNeedsLayout() before returning the cells:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueCellOfType(MyCell.self, for: indexPath)
// Make the call below:
cell.setNeedsLayout()
return cell
}

Resources