Adding label programmatically in UITableViewCell? - ios

I'm having a problem adding an extra label on some of my cells in the tableview. At the moment I determine the rowheight as follows:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let numberOfBusses = nearbyStops[indexPath.section].getDepartures()[indexPath.row]!.count
if (numberOfBusses > 2) {
return CGFloat((75/2) * numberOfBusses)
} else {
return 75
}
}
I try to do this to add the missing label, but nothing happens:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! BusDepartureTableViewCell
let numberOfBusses = nearbyStops[indexPath.section].getDepartures()[indexPath.row]!.count
if (numberOfBusses > 2) {
var label = UILabel(frame: CGRectMake(0, 0, 200, 21))
label.center = CGPointMake(160, 284)
label.textAlignment = NSTextAlignment.Center
label.text = "I'am a test label"
label.textColor = UIColor.redColor()
cell.foregroundView.addSubview(label)
}
.........
What am I doing wrong?
UPDATE:
I've taken a picture of my current achievements and I've gotten the cell to expand, however, as you can see, there's now room for two other labels, but how do I add them?

Cells get re"used" - that means to save memory iOS uses your UI-Elements only as an placeholder, and sets your values in
cellForRowAtIndexPath
In that case, its much more memory efficient to create 2 (or more) different cell Layouts in Storyboard, and give every cell an different identifier.
For example:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let item = yourPopulatingArray[indexPath.row] as Item
var cellIdentifier = "cellLayout1"
if item.anyPropertyToCheckforLayout {
cellIdentifier = "cellLayout2"
}
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! BusDepartureTableViewCell

Related

Trouble making more than one or two cells into UITableView with different sizes Swift

I'm trying to build two (or more) custom cells into table View and without custom classes for each one, I'm using storyboard to cell prototyping and tableView.dequeueReusableCell(withIdentifier: "customCellName", for: indexPath) to create different cell from cellForRowAt method.
I need cell type 1 with different height than cell type 2 but if a try to use func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat the cell type 2 is not displayed correctly.
I try to build a "dummy project" to understand the right way, here my code:
var cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let value = dataArray[indexPath.row]
if (value == "second") || (value == "Hawaii") {
cell = self.tableView.dequeueReusableCell(withIdentifier: "cellTwo", for: indexPath)
}
let lbl = cell.viewWithTag(100) as! UILabel
lbl.text = dataArray[indexPath.row]
return cell
In ViewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = self
self.tableView.delegate = self
self.tableView.estimatedRowHeight = 200
}
This is the result:
Every cell with the same size, is not working for me.
If you want to create a custom cell appearance, you will have to create a subclass of UITableViewCell - there are some great tutorials on how to do that.
You then have to register your custom cell, so that your UITableView knows about it. See register(_:​for​Cell​Reuse​Identifier:​) method.
In your table​View(_:​height​For​Row​At:​) you can do write the following code in order to figure out the height of particular cell:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
let value = dataArray[indexPath.row]
if (value == "second") || (value == "Hawaii") {
return 180.0
} else {
return 40.0
}
}

How to know which IndexPath.row is clicked on IBAction, and how to exclude a specific button from it being triggered

I have a UITableViewController. It has one prototype cell, and spawns anywhere from 0 to 100 cells based on a user query. Once they load, I want an IBAction to trigger if a user taps anywhere within the cell EXCEPT for a specific button. I have multiple labels, and I still want the IBAction to be triggered if user taps on them. How do I accomplish this?
Here's my code for loading the tables:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TypeOfActivityTableViewCell
cell.activityLabel?.text = activityNames[indexPath.row]
cell.bgImage?.image = UIImage(named: activityPic[indexPath.row])
cell.sloganLabel?.text = slogan[indexPath.row]
return cell
}
I do not want to code all this within tableView for MVC principles.
For tapping anywhere in the cell you need not configure an IBAction. Just use the default UITableViewDelegate i.e:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let geoSearchWord = "geoSearchWord" + searchQuery[indexPath.row]
let geoSearchLat = "&geoSearchWordLat=" + (lat == "" ? "33.9700" : lat)
let geoSearchLon = "&geoSearchWordLon=" + (lat == "" ? "-118.4180" : lon)
let geoSearchRadius = "&geoSearchWordRad=5mi"
let twitterURLRequest: String = "https://quiet-cove-5048.herokuapp.com/tw?\(geoSearchWord)\(geoSearchLat)\ (geoSearchLon)\(geoSearchRadius)"
alamoRequest(twitterURLRequest)
}
Else if you have Buttons inside your cell for specific actions. You will have to add action to that button and assign a tag for identification(which button is tapped).
You can add action in cellForRowAtIndexPath
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TypeOfActivityTableViewCell
cell.activityLabel?.text = activityNames[indexPath.row]
cell.bgImage?.image = UIImage(named: activityPic[indexPath.row])
cell.sloganLabel?.text = slogan[indexPath.row]
cell.myButton.addTarget(self, action: "myAction:", forControlEvents: .TouchUpInside)
cell.myButton.tag = indexPath.row
return cell
}
Tapping on a button inside the cell will execute the below function:
func myAction(sender:UIButton){
let selectedActivityName = activityNames[sender.tag]
}
Here is one crafty solution.You can add an UIControl(e.g. UIButton) to receive touch in that special area.And then receive events in UITableViewDelegate: tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
If you want click any where in cell then you can use its delegate methods
i.e
tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
And if you want to add UIControl and on touch event of that control you need to do as follows:
First You need to add target for your control in your cellForRowAtIndexPath as below.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TypeOfActivityTableViewCell
cell.activityLabel?.text = activityNames[indexPath.row]
cell.bgImage?.image = UIImage(named: activityPic[indexPath.row])
cell.sloganLabel?.text = slogan[indexPath.row]
cell.btn.addTarget(self, action: "btnClickAction", forControlEvents: UIControlEvents.TouchDragInside)
return cell
}
Button Click fucntion:
func btnClickAction(sender: UIButton)
{
var superView = sender.superview
while superView?.isKindOfClass(UITableViewCell) == false
{
superView = superView?.superview
}
var cell = superView as! UITableViewCell
var indexPath = self.tableView.indexPathForCell(cell)! as NSIndexPath
}
In above code you will find indexPath.

Custom expanding UITableViewCell has a glitch?

Here's the glitch. As you can see when I push the custom UITableViewCell SummaryCell out of the view of the app the cell glitches and doesn't put the UILabels dayOfTheWeek and totalAmountSpent in their proper places. But if you click on the glitchy cell, it returns to normal.
Here are some of the methods of theUITableViewController SummaryTableViewController that I used to create the custom cell summaryCell :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Create day of week cell
let cell = tableView.dequeueReusableCellWithIdentifier("summaryCell", forIndexPath: indexPath) as! SummaryCell
let day = dayOfWeek[indexPath.row]
let height = CGFloat(55)
let dayOfWeekWidth = CGFloat(80)
cell.dayOfWeek.text = day.rawValue.uppercaseString
cell.dayOfWeek.frame = CGRectMake(0, 0, dayOfWeekWidth, height)
cell.dayOfWeek.backgroundColor = colorOfDay[day]
cell.totalAmountSpent.text = "$\(totalSpentPerDay[indexPath.row])"
cell.totalAmountSpent.frame = CGRectMake(cell.dayOfWeek.frame.maxX + 1, 0, view.bounds.width - dayOfWeekWidth, height)
cell.totalAmountSpent.backgroundColor = colorOfDay[day]
cell.totalAmountSpentView.backgroundColor = colorOfDay[day]
cell.heightOfMainView.constant = normalCellHeight
//^I have this to make sure the height of the cell is the same as
//the height of the mainView in the nib file `summaryCell` so that
//when the table loads intially, only the mainView of the `summaryCell` shows up.
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if expandedCellPaths.contains(indexPath){
let index = expandedCellPaths.indexOf(indexPath)
expandedCellPaths.removeAtIndex(index!)
}else{
expandedCellPaths.append(indexPath)
}
//old trick to animate cell expand/collapse
tableView.beginUpdates()
tableView.endUpdates()
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let expandedCellHeight = normalCellHeight*2
if expandedCellPaths.contains(indexPath){
return expandedCellHeight
}else{
return normalCellHeight
}
}
This is the nib file & its constraints corresponding to my custom UITableViewCell SummaryCell
My 2 best guess as to why this is happening are (1) the constraints in my nib file summaryCell or (2) the lines in my UITableViewConroller SummaryTableViewController:
If anyone could tell me how I can fix this glitch it would be greatly appreciated!
tableView.beginUpdates()
tableView.endUpdates()
Actually never mind! I realized my error! I just needed to delete these lines in tableView(:cellForRowAtIndexPath:):
let height = CGFloat(55)
let dayOfWeekWidth = CGFloat(80)
cell.dayOfWeek.frame = CGRectMake(0, 0, dayOfWeekWidth, height)
cell.totalAmountSpent.frame = CGRectMake(cell.dayOfWeek.frame.maxX + 1, 0, view.bounds.width - dayOfWeekWidth, height)

When select cell, UITableView changing appearance when scroll?

I have the strangest glitch after I select a UITableView cell and scroll away(You can see it here):
When I select a cell, it's programmed to change its text and change the font color from brown to red. However, when I scroll, other cells that I have not selected change their font color to red. And when I scroll back to the selected cell it reverts to its original text and sometimes, its font color too (from red to brown).
I've used this post in attempt to fix it. But still the glitch remains.
I am completely baffled as to why this is happening and would love love love if anyone could tell me why.
In my code I made my ViewController CategoryViewController the UITableView's Datasource & Delegate instead of a UITableViewController b/c I have other views in my CategoryViewController, not just a UITableView
class CategoryViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private let themeColors = ThemeColors()
private let expensesOrganizer = ExpensesOrganizer()
override func viewDidLoad() {
super.viewDidLoad()
//Set up subCategory table view
subCategoryTableView.dataSource = self
subCategoryTableView.delegate = self
}
// MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return expensesOrganizer.getNumOfSubcategoriesFor(category!)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let subcategoryCell = tableView.dequeueReusableCellWithIdentifier("subCategoryCell", forIndexPath: indexPath) as! SubcategoryTableViewCell
let subcategory = expensesOrganizer.getSubcategoryFor(category!, index: indexPath.row)
subcategoryCell.subCategoryLabel.text = "\(indexPath.row) \(expensesOrganizer.getText(subcategory.rawValue))"
subcategoryCell.selectedBackgroundView = UIView(frame: CGRect.zero)
subcategoryCell.selectedBackgroundView?.backgroundColor = themeColors.getColorOfCategory(category!)
return subcategoryCell
}
// MARK: UITableViewDelegate
var indexPathSelectedCell: NSIndexPath?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let subcategoryCell = tableView.cellForRowAtIndexPath(indexPath) as! SubcategoryTableViewCell
subcategoryCell.subCategoryLabel.textColor = UIColor.redColor()
subcategoryCell.subCategoryLabel.text = "\(indexPath.row) didSELECTRowAtIndexPath called"
indexPathSelectedCell = indexPath
//What the post said to add:
let selectedRows = subCategoryTableView.indexPathsForSelectedRows
for i in selectedRows! {
if !i.isEqual(indexPath){
subCategoryTableView.deselectRowAtIndexPath(i, animated: false)
}
}
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let subcategoryCell = tableView.cellForRowAtIndexPath(indexPath) as! SubcategoryTableViewCell
subcategoryCell.subCategoryLabel.textColor = themeColors.getFontColor(Shade.Light)
subcategoryCell.subCategoryLabel.text = "\(indexPath.row) didDESELECTRowAtIndexPath called"
}
The approach that you take is incorrect, because you are not setting the color when you reuse a cell. Your cellForRowAtIndexPath needs to set color back to brown if the cell is not selected. It should be set to red if the cell is selected:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let subcategoryCell = tableView.dequeueReusableCellWithIdentifier("subCategoryCell", forIndexPath: indexPath) as! SubcategoryTableViewCell
let subcategory = expensesOrganizer.getSubcategoryFor(category!, index: indexPath.row)
subcategoryCell.subCategoryLabel.text = "\(indexPath.row) \(expensesOrganizer.getText(subcategory.rawValue))"
subcategoryCell.selectedBackgroundView = UIView(frame: CGRect.zero)
subcategoryCell.selectedBackgroundView?.backgroundColor = themeColors.getColorOfCategory(category!)
if let selected = tableView.indexPathsForSelectedRows() as? [NSIndexPath] && selected! == indexPath {
subcategoryCell.subCategoryLabel.textColor = UIColor.brownColor()
} else {
subcategoryCell.subCategoryLabel.textColor = UIColor.redColor()
}
return subcategoryCell
}
This has to do with cell reuse.
When you change the color of the label in didSelectRowAtIndexPath, then scroll that cell off-screen, it gets reused for a different cell that will appear on-screen.
However, since you don't prepare the cell for reuse, it is still using the selected font color for your label.
Assigning the label's default text color in prepareForReuse or cellForRowAtIndexPath will fix this issue.

How to get a appropriate height for a reused cell according to the Label in that cell?

This is my layout.The Label's top to the ContentView's top is 58pt.The numberOfLine of the Label is 0.So it can Enter automatically.
And I want the Height of every cell is 58.0+10.0+the height of label.
I have tried this code.
TV.estimatedRowHeight = 68
TV.rowHeight = UITableViewAutomaticDimension
But didn't work.
And then tried this code.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CommentDetailCell
return 68.0 + cell.Comment.frame.size.height
}
Didn't work again.
And then try this!To create a array to store the height of every cell's labelHeight.
var CommentHeightA:[CGFloat] = [60.0,60.0,60.0,60.0]
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell:CommentDetailCell = tableView.dequeueReusableCellWithIdentifier("cell") as! CommentDetailCell
cell.UserImg.image = UIImage(named: UserImgA[indexPath.row])
cell.AtNum.text = AtNumA[indexPath.row]
cell.LikeNum.text = LikeNumA[indexPath.row]
cell.isLike.image = UIImage(named: isLikeA[indexPath.row])
cell.Comment.text = CommentA[indexPath.row]
CommentHeightA[indexPath.row] = cell.Comment.frame.size.height
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 68.0 + CommentHeightA[indexPath.row]
}
And :( all the ways above is failed.
So how can I get what I want?
Update:
I have added the bottom constraint and used the 1st way.
This is the result.Only the 1st row has a appropriate height.
You need to add a bottom constraint from the comment label to the content view. Then add the following code:
TV.estimatedRowHeight = 68
TV.rowHeight = UITableViewAutomaticDimension
It will work,

Resources