UITableViewCell textLabel changing position on selection - ios

I have created a UITableView and a subclass of UITableViewCell using code and it displays perfectly fine untill I select the cell.
The textLabel of the cell would shift rightwards or not shift sometimes
Image Representation of the problem before selection
Image representation of the problem after selection
Relevant Code
class MyCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
// here I fixed the image at a specific point
self.imageView?.bounds = CGRectMake(0, 0, 100, 125)
self.imageView!.frame = CGRectMake(0, 0, 100, 125)
self.imageView?.contentMode = .ScaleAspectFill
} }
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = MyCell(style: UITableViewCellStyle.Default, reuseIdentifier: "FeedCell")
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
func configureCell(cell: MyCell, atIndexPath indexPath: NSIndexPath) {
let item = self.items[indexPath.row] as MWFeedItem
cell.textLabel?.text = item.title
cell.textLabel?.font = UIFont.systemFontOfSize(12.0)
cell.textLabel?.numberOfLines = 0
}

You should really define your own image view and text label (with different names) in your subclass and apply constraints to lay them out in relation to the size of the cell, then set the row height in the controller so that things are displayed appropriately.
Even in your first image the size of images is incorrect so you have a mismatch configuration between the cell and the controller. And the properties you're currently using should be considered private private in terms of their size and position because you don't own the implementation which sets those features of the views.

Related

UITableViewCell only displays accessory after scrolling

So I have a TableView with custom cells that I make from fetching data from a server. I have a variable 'selectedIndex' which I use to keep track and add a checkmark accessory to my cell. Weirdly, it only works after I scroll the selected cell (cell with indexPath.row is equal to off the screen and back. Here is the code in my willDisplayCell method:
if selectedIndex == indexPath.row {
if let accessory = cell.viewWithTag(528) as? UITableViewCell {
accessory.frame = (cell.checkmarkView.bounds.offsetBy(dx: 0, dy: 7))
accessory.accessoryType = .checkmark
accessory.isUserInteractionEnabled = false
accessory.backgroundColor = UIColor.clear
accessory.tag = 528
accessory.isHidden = false
print("accessory not nil")
} else {
let accessory = UITableViewCell()
accessory.frame = (cell.checkmarkView.bounds.offsetBy(dx: 0, dy: 7))
accessory.accessoryType = .checkmark
accessory.isUserInteractionEnabled = false
accessory.backgroundColor = UIColor.clear
accessory.tag = 528
accessory.isHidden = false
cell.addSubview(accessory)
print("accessory nil")
}
} else {
let accessory = cell.viewWithTag(528)
accessory?.isHidden = true
}
For example, when the selected index is 0, the checkmark is not displayed at first view, and the logs print ("accessory nil"). When I scroll the cell at index 0 off-screen, and scroll to it again, the checkmark is now displayed and the logs print ("accessory not nil"). For more information, tapping on a cell works just as expected.
Edit:
I know I'm adding another TableViewCell to my cell! I'm only doing that because I need my checkmark accessory to be in a different position (left-aligned, top-aligned) than the default one (right-aligned, vertically centered). So what I did was add a view in my XIB that is in the desired position (right-aligned, top-aligned) and and aligned my programatically-made cell to it. If you could show me another approach it would be appreciated.
Removed cell.addSubview from the first if. Still behaves the same.
Thanks!
You are adding UITableViewCell into your dequeued original cell, this is unnecessary, you need implement this logic in your cellForRowAt datasource method,
updated
If you need a custom position for your accessory view use cell.layoutMargins check my updated code
try this instead
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) as! YourCellClass
cell.accessoryType = .none
if selectedIndex == indexPath.row {
cell.accessoryType = .checkmark
}
//if you need a custom position for your accessory view
cell.layoutMargins = UIEdgeInsetsMake(0, 0, 0, 100)
}
UITableView will optimize your cells by reusing them. So in your case it seems better to use tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) instead of calling the Cell's constructor yourself or find the cell back by looking for it's tag.
Besides that the part which determines the state of the cell should be in the UITableView's tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell function instead of the willDisplayCell. This might solve your problem and prevents issues with reusing cells.

Space between cells in UITableView

I have UIViewController with UITableView.
In the table I have two different cells and use UITableViewAutomaticDimension.
First and second cell - one style (no space between cells)
Second and third cell - different styles (have some space as in image)
How can I remove this space?
P.S. Xib of cells are good.
You can subclass UITableViewCell and add something like:
// Inside UITableViewCell subclass
override func layoutSubviews() {
super.layoutSubviews()
let frame = contentView.frame
let frameRect = UIEdgeInsetsInsetRect(frame, UIEdgeInsetsMake(5, 5, 5, 5))
contentView.frame = frameRect
}
Then based on the indexPath.row you can chose which tableView cell you want to use, like :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
//First cell
if(indexPath.row == 0) {
// Would need to return appropriate cell here
}
if(indexPath.row == 1) {
// Would need to return appropriate cell here
}
return cell
}
Hope this helps.

Adding label programmatically in UITableViewCell?

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

UITableViewCell ImageView not scaling properly?

I am populating a UITableView with images selected by the user. I'd like to the have thumbnails in the table cells all be the same size without affecting the aspect ratio so as not to stretch/skew the images, which sounds to me like ScaleAspectFill, however none of the UIViewContentMode selections seem to have an effect. There me conflicting methods, notable heightForRowAtIndexPath, but removing this makes my cells too small. The following are my didSelectRowAtIndexPath and heightForRowAtIndexPath methods, along with a screen shot from the simulator of my current code (using simulator stock images). Any help is appreciated.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//sets cell based on meme in array
let cell = tableView.dequeueReusableCellWithIdentifier("memeCell") as! UITableViewCell
let meme = self.memes[indexPath.row]
// Set the name and image
cell.textLabel?.text = meme.topText + " " + meme.bottomText
cell.imageView?.frame = CGRectMake(0, 0, 200, 100)
cell.imageView?.contentMode = UIViewContentMode.ScaleToFill //ScaleAspectFill is best, ScaleToFill used to exagerate that its not working
//cell.imageView?.backgroundColor = UIColor.grayColor() //legacy code, will be removed at commit
cell.imageView?.image = meme.origImage
return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
//cell row won't be large enough unless this method is called
return 75.0
}
You can add a subclass of UITableViewCell, then overrides layoutSubviews method:
override func layoutSubviews() {
super.layoutSubviews()
self.imageView.frame = CGRect(0,0,200,100)
}
Check out https://github.com/mattgemmell/MGImageUtilities
You can use the crop function in UIImage+ProportionalFill, that scales the image proportionally to completely fill the required size, cropping towards its center, to crop all images to the same size before assigning the image.
You can use it like this:
cell.imageView?.image = meme.origImage. imageCroppedToFitSize(CGSize(width: 200, height: 100))

Swift : Single Selection with UITableViews

I have a regular UITableView with single selection enabled. My problem is that if the user selects multiple rows then the original rows remain selected. I also have a problem where the highlight remains gray no matter if I set the cell.selectionStyle = UITableViewCellSelectionStyle.Blue
My view controller is defined in the Storyboard.
Table View
Content: Dynamic Prototypes
Selection: Single Selection
Show Selection on Touch [X]
Background: Black Color
Index Row Limit: 0
Table Cell View
Style: Custom
Selection: Blue
Background: Black Color
Here are some screenshots:
Here is my code:
class AreaViewController: UITableViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
self.tableView.backgroundColor = backgroundColour
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("areacell", forIndexPath: indexPath) as! UITableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.Blue
cell.textLabel?.text = "Cell Contents"
cell.textLabel?.textColor = UIColor.whiteColor()
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let cell = tableView.dequeueReusableCellWithIdentifier("areacell", forIndexPath: indexPath) as! UITableViewCell
}
}
I must be missing something obvious but I've not been able to see anything non standard.
From the UITableViewCell Class Reference
UITableViewCellSelectionStyleBlue The cell has a default background
color when selected.
In iOS 7, the selection color is no longer blue. Use
UITableViewCellSelectionStyleDefault instead.
If you want a special background color for selected cells you have to set the cells' backgroundView:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.redColor()
cell.selectedBackgroundView = backgroundView
return cell
}
Looks like this:
Argh! I found it at last. Seems like I was calling let cell = tableView.dequeueReusableCellWithIdentifier("areacell", forIndexPath: indexPath) as! UITableViewCell in the didSelectRowAtIndexPath method. Removing it caused everything to start working again. Obvious really. Thanks for your help zisoft in putting me on the right road.

Resources