Can't add textLabel to a UICollectionViewCell? - ios

I have a class file that is a subclass of the UICollectionViewController class. In my cellForItemAtIndexPath method, I am trying to set the textLabel of the cells. However, there is no textLabel option in the completions. This is the method so far:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as UICollectionViewCell
// Configure the cell
cell.backgroundColor = cellColor ? UIColor.blueColor() : UIColor.orangeColor()
//cell.textLabel.text = "Text"???
switch indexPath.item {
case 0...5:
cellColor = true
case 6...13:
cellColor = false
default:
cellColor = true
}
}
What can I do to add the textLabel to the cells?

Unlike tableViewCell ,UICollectionViewCell doesn't have textLabel. You need to add the UILabel to cell's content view
example:
var title = UILabel(frame: CGRectMake(0, 0, cell.bounds.size.width, 40))
cell.contentView.addSubview(title)

Use the documentation, Luke. It's under Xcode's "Help" menu.
UICollectionViews don't have textLabels - that's why you don't get a completion.
They have contentViews. You can put text in the content view though. Any UIView subclass will do. If all you want is text (no graphics), then you could use a UITextView for your content view, then assign to its "text" property:
cell.contentView.text = "Text"
However, you will want a subclass of UICollectionView that already provides the UITextViews for the contentViews.

Swift 4
Here is the Swift 4 way to add text to a collection view cell:
let title = UILabel(frame: CGRect(x: 0, y: 0, width: cell.bounds.size.width, height: 40))
title.textColor = UIColor.black
title.text = "T"
title.textAlignment = .center
cell.contentView.addSubview(title)

Related

UITableView - adjustsFontSizeToFitWidth in sectionHeader

I've created a custom sectionHeader for my UITableview.
Sometimes I have to fill it with large text, so I added adjustsFontSizeToFitWidth = true which normally works.
In this case the font is not resized when it is to large. Does anyone have an idea what I'm doing wrong?
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.lightGray
let headerLabel = UILabel(frame: CGRect(x: 30, y: 0, width:
tableView.bounds.size.width, height: tableView.bounds.size.height))
headerLabel.textColor = UIColor.white
headerLabel.text = self.tableView(self.tableView, titleForHeaderInSection: section)
headerLabel.sizeToFit()
headerLabel.adjustsFontSizeToFitWidth = true
headerLabel.clipsToBounds=true
headerLabel.numberOfLines=0
headerLabel.lineBreakMode = NSLineBreakMode.byTruncatingTail
headerLabel.minimumScaleFactor = 0.4
headerView.addSubview(headerLabel)
return headerView
}
You need to remove
headerLabel.sizeToFit() to make adjustsFontSizeToFitWidth property working.
The solution was to delete this line:
headerLabel.sizeToFit()

How to add UIImage and UILabel if UITableView has no data

I've looked into many answers but either it's only UILabel or UIImage not both. So after trying to implement it I finally found that we cannot do two tableView.backgroundView. Here is what I've done so far:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let noDataLabel: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: tableView.bounds.size.height))
let image = UIImage(named: "noData")
let noDataImage = UIImageView(image: image)
noDataImage.frame = CGRect(x: 0, y: 10, width: 20, height: 20)
if allData.count == 0 {
noDataLabel.isHidden = false
noDataImage.isHidden = false
noDataLabel.text = "No data added. Add new entry \nby pressing the add icon on top right."
noDataLabel.textColor = UIColor.black
noDataLabel.numberOfLines = 3
noDataLabel.backgroundColor = UIColor.white
noDataLabel.textAlignment = .center
//what to do from here
tableView.backgroundView = noDataImage
tableView.backgroundView = noDataLabel
//end
tableView.separatorStyle = .none
return 0;
}
else {
noDataLabel.backgroundColor = UIColor.clear
noDataLabel.isHidden = true
noDataImage.isHidden = true
tableView.backgroundView = nil
return allData.count
}
I want to show an image and below that image I want to show a UILabel. How can I achieve this?
You need to create a view with subviews your image and label
var backgroundView =UIView(frame: CGRectMake(0, 0, your_width, your_height))
backgroundView.addSubview(noDataImage)
backgroundView.addSubview(noDataLabel)
tableView.backgroundView=backgroundView;
Note: Adjust the frame of noDataImage and noDataLabel as per your use.
backgroundView Property
The background view of the table view.
Declaration
Swift
var backgroundView: UIView?
Objective-C
#property(nonatomic, readwrite, retain) UIView *backgroundView
Discussion
A table view’s background view is automatically resized to match the size of the table view. This view is placed as a subview of the table view behind all cells, header views, and footer views.
You must set this property to nil to set the background color of the table view.

Swift 3 UITableView cell seperator disappears when i remove cell subviews

I have an array type of string arrays and I print it to tableView within for loop.I know its a bad practice loop inside cellForRowAt indexPath: function but I don't have any solution.My Problem is every time I move my tableview on simulator,i insert more subviews on existing ones.it overwrites older ones and to prevent i use
for view in cell.subviews {
view.removeFromSuperview()
}
but it deletes my cell seperators with my older cell labels.How can i remove only cell data not my seperator.
func tableView(_ tableView: UITableView, cellForRowAt indexPath:IndexPath) -> UITableViewCell {
var cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell
//print(cell.subviews)
for view in cell.subviews {
view.removeFromSuperview()
}
for i in 0..<globalHeaderStructArray.count{
var newLabel = UILabel(frame: CGRect(x:xCoordination, y:10, width:Double(globalHeaderStructArray[i].width)!, height:30.0))
newLabel.font = UIFont(name: "Avenir", size: 17.0)
newLabel.textColor = UIColor.darkGray
newLabel.text = "\(globalDataArray[indexPath.row][i])"
var scrollview = UIScrollView(frame: cell.bounds)
scrollview.contentSize = CGSize(width:cell.bounds.width * 5, height:cell.bounds.height) // will be 5 times as wide as the cell
scrollview.isPagingEnabled = true
cell.contentView.addSubview(scrollview)
cell.addSubview(newLabel)
xCoordination += Double(globalHeaderStructArray[i].width)!
}
xCoordination = 0.0
return cell
}
You can set tag to your label and scrollView object and check that inside loop like this.
for view in cell.subviews {
if view.tag == 101 || view tag == 102 {
view.removeFromSuperview()
}
}
for i in 0..<globalHeaderStructArray.count{
var newLabel = UILabel(frame: CGRect(x:xCoordination, y:10, width:Double(globalHeaderStructArray[i].width)!, height:30.0))
newLabel.font = UIFont(name: "Avenir", size: 17.0)
newLabel.textColor = UIColor.darkGray
newLabel.text = "\(globalDataArray[indexPath.row][i])"
newLabel.tag = 101
var scrollview = UIScrollView(frame: cell.bounds)
scrollview.contentSize = CGSize(width:cell.bounds.width * 5, height:cell.bounds.height) // will be 5 times as wide as the cell
scrollview.isPagingEnabled = true
scrollview.tag = 102
cell.contentView.addSubview(scrollview)
cell.addSubview(newLabel)
xCoordination += Double(globalHeaderStructArray[i].width)!
}
Tips: It is batter if you use interface builder to design your cell instead of adding UI element at run time.

Add subview on tableView cells causes a sad patchwork

I want to give a chat aspect to a table view of messages in my iPhone app.
In order to perform a quality render I add two subviews: the text and the "container" which is just a view with background color.
Even if it works the first time, when I scroll, it becomes really messy because it keeps adding lots of subviews.
Here you can see it when clean
And then when it has become messy
Here is the function to handle the transform, it's called when scrolling.
func configChatCell(cell: UITableViewCell, text: String, color:UIColor)
{
cell.textLabel?.numberOfLines = 0
cell.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
cell.textLabel?.textColor = UIColor.whiteColor()
let fixedWidth = cell.bounds.width - 150
let textView: UITextView = UITextView(frame: CGRect(x: 0, y: 0, width: 10, height: CGFloat.max))
textView.text = text
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
var newFrame = textView.frame
newFrame.size = CGSize(width: min(newSize.width, fixedWidth), height: newSize.height)
textView.sizeThatFits(newFrame.size)
textView.frame = newFrame
textView.backgroundColor = UIColor.clearColor()
self.rowHeight = textView.frame.height+20
let view = UIView()
view.backgroundColor = color
print(textView.frame.height+10)
view.frame = CGRect(x: 0, y: 5, width: textView.frame.width+50, height: textView.frame.height+10)
view.layer.cornerRadius = 5
cell.backgroundColor = UIColor.clearColor()
cell.contentView.addSubview(view)
cell.contentView.addSubview(textView)
cell.contentView.sendSubviewToBack(view)
}
If I remove the subviews each time I scroll, nothing appears on screen.
Can somebody help me to find a solution? Or is there any other way to do this?
Thanks in advance!
I quickly wrote up something for this.
It starts with the ChatCell
class ChatCell: UITableViewCell {
var messageLabel: UILabel? {
didSet {
messageLabel?.text = message
}
}
var message: String? {
didSet {
messageLabel?.text = message
}
}
class func messageCell(withText text: String, leading: Bool = true) -> ChatCell {
let cell = ChatCell()
cell.message = text
// Make the container
let container = UIView()
container.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(container)
container.topAnchor.constraintEqualToAnchor(cell.contentView.topAnchor, constant: 8).active = true
container.bottomAnchor.constraintEqualToAnchor(cell.contentView.bottomAnchor, constant: -8).active = true
if leading {
container.leadingAnchor.constraintEqualToAnchor(cell.contentView.leadingAnchor, constant: leading ? 8 : 8*8).active = true
container.trailingAnchor.constraintLessThanOrEqualToAnchor(cell.contentView.trailingAnchor, constant: leading ? -8*8 : -8).active = true
} else {
container.leadingAnchor.constraintGreaterThanOrEqualToAnchor(cell.contentView.leadingAnchor, constant: leading ? 8 : 8*8).active = true
container.trailingAnchor.constraintEqualToAnchor(cell.contentView.trailingAnchor, constant: leading ? -8*8 : -8).active = true
}
// Make the messageLabel.
let messageLabel = UILabel()
messageLabel.numberOfLines = 0
messageLabel.textColor = UIColor.whiteColor()
messageLabel.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(messageLabel)
// Add constraints.
messageLabel.topAnchor.constraintEqualToAnchor(container.topAnchor, constant: 8).active = true
messageLabel.bottomAnchor.constraintEqualToAnchor(container.bottomAnchor, constant: -8).active = true
messageLabel.leadingAnchor.constraintEqualToAnchor(container.leadingAnchor, constant: 8).active = true
messageLabel.trailingAnchor.constraintEqualToAnchor(container.trailingAnchor, constant: -8).active = true
cell.messageLabel = messageLabel
container.backgroundColor = UIColor(red:0.19, green:0.70, blue:1.00, alpha:1.00)
container.layer.cornerRadius = 12.0
return cell
}
}
The cell also includes support for leading and trailing messages, for back and forth conversation. Perhaps make an array of tuples like this:
let messages: [(message: String, leading: Bool)] = [("Hello", true), ("My name is John Doe and this works quite well", false), ("I would agree", true)]
Then in your tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell you could do this:
let cell = ChatCell.messageCell(withText: messages[indexPath.row].message, leading: messages[indexPath.row].leading)
return cell
Let me know if this works for you. I tested it in a Playground and it works as expected
Assuming that your configureChatCell is called from tableView:cellForRowAtIndexPath:, then #Paulw11 is right; cells are reused, so you should only make changes that are unique to that row in the table. In your example, the only calls that you should be making in your method are textView.text = text and the ones to resize the textView to fit. Everything else should go in a dynamic cell prototype in the storyboard or, if you want to do everything in code (which I have a bad feeling you do), then put the rest of the configuration in a UITableViewCell subclass, then register that subclass with your table view.
I write something like this. It's simple but can elucidate solution
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseid", forIndexPath: indexPath)
// Configure the cell...
let contentView = cell.contentView
let subviews = contentView.subviews
for view in subviews {
if 100 == view.tag {
let label = view as! UILabel
label.text = self.datas[indexPath.row]
} else if 200 == view.tag {
view.layer.cornerRadius = 10.0
}
}
return cell
}
the key point is config every thing in tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
the view in code with tag 200 is a background view has same frame with label, I use layout constraint in storyboard to make sure its size and position.

Custom UIImageView added to UItableview cell doesnot shift on on x-axis?

I am trying to give some margin on x-axis for a imageView that is set inside a tableView cell. But the imageView does not move. And I also tried same for a label. It does shift to the value I gave.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
// cell.textLabel?.font = UIFont(name: label.font.fontName, size: 22)
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("myCell") as UITableViewCell
// cell.imageView?.image = UIImage(named: self.cellImgs[indexPath.row])
cell.textLabel?.text = self.cellTxtArrs[indexPath.row]
cell.textLabel?.textAlignment = NSTextAlignment.Right
cell.textLabel?.textColor = UIColor.whiteColor()
cell.backgroundColor = UIColor(red: 0.000, green: 0.400, blue: 0.404, alpha: 1.00)
cell.selectionStyle = UITableViewCellSelectionStyle.None
// var videoImgView:UIImageView = UIImageView(frame: CGRectMake(50, 10, 20, 30.0))
// let videoImage = UIImage(named: "accounts")
// videoImgView = UIImageView(image: videoImage)
// cell.contentView.addSubview(videoImgView)
var newLabel = UILabel(frame: CGRectMake(80, 0, 80, 30.0))
newLabel.text = "hello all"
newLabel.textColor = UIColor.redColor()
cell.contentView.addSubview(newLabel)
return cell
}
I have created a table view as
var tblView : UITableView = UITableView()
tblView.frame = CGRectMake(0, 168, 320-50 , 448)
tblView.separatorColor = UIColor.clearColor()
tblView.scrollEnabled = false
tblView.rowHeight = 39
self.addSubview(tblView)
tblView.delegate = self
tblView.dataSource = self
tblView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "myCell")
1) your code will cell.contentView.addSubview everytime that cellForRowAtIndexPath is called. You are not reusing cell properly .
2) Subclass UITableViewCell and add your "logic View code" inside there (right place to do it)
3) look at this: http://www.objc.io/issue-1/lighter-view-controllers.html
Please try to use this one i hope it helps you.
videoImgView = UIImageView(image: videoImage)
videoImgView.frame = CGRectMake(100, 10, 20, 30.0)
cell.contentView.addSubview(videoImgView)

Resources