willDisplayCell first row does not work in Swift - swift

I wanted to make custom corner rounded background for my custom cells and it worked with code below but the first row is not affected I should scroll it up to make it have a background
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row != 0 {
cell.contentView.backgroundColor = UIColor.clearColor()
var whiteRoundedCornerView: UIView = UIView(frame: CGRectMake(10, 10, 365, 250))
whiteRoundedCornerView.backgroundColor = UIColor.lightGrayColor()
whiteRoundedCornerView.layer.masksToBounds = false
whiteRoundedCornerView.layer.cornerRadius = 20
whiteRoundedCornerView.layer.shadowOffset = CGSizeMake(-0, -1)
whiteRoundedCornerView.layer.shadowOpacity = 0.1
cell.contentView.addSubview(whiteRoundedCornerView)
cell.contentView.sendSubviewToBack(whiteRoundedCornerView)
}
}

The issue in your code is the if statement. When indexPath.row is 0 (which is the first row), your configuration code isn't executed. To solve this, simply remove the if statement from your code. It should look something like this:
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.contentView.backgroundColor = UIColor.clearColor()
var whiteRoundedCornerView: UIView = UIView(frame: CGRectMake(10, 10, 365, 250))
whiteRoundedCornerView.backgroundColor = UIColor.lightGrayColor()
whiteRoundedCornerView.layer.masksToBounds = false
whiteRoundedCornerView.layer.cornerRadius = 20
whiteRoundedCornerView.layer.shadowOffset = CGSizeMake(-0, -1)
whiteRoundedCornerView.layer.shadowOpacity = 0.1
cell.contentView.addSubview(whiteRoundedCornerView)
cell.contentView.sendSubviewToBack(whiteRoundedCornerView)
}

Related

Add view dynamically to cells produce issues in table

I have this function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 400, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
cell.contentView.addSubview(label)
return cell
}
Well, with this function I'm adding a list of rows dynamically.
Why dynamically? Because, the number of columns depends of the data.
Don't take focus on that.
The list has 244 elements.
The result is displayed ok, but once I started scrolling, I get this:
How I can add elements dynamically without get this error?
Cells get reused. You keep adding more and more labels to each cell.
The proper solution is to create a custom cell class that contains the desired label. Then simply set that label's text in cellForRowAt. Don't create and add subviews in cellForRowAt.
But keep in mind that you may just want to use the provided textLabel property of UITableViewCell. No need for a custom cell or your own label.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
cell.textLabel?.text = "\(data[indexPath.row])"
return cell
}
I found a solution, hope this works to you!!!
You have to add to your cellForRowAt this code:
for item in cell.contentView.subviews
{
item.removeFromSuperview()
}
Just after to get the cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
for item in cell.contentView.subviews
{
item.removeFromSuperview()
}
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 300, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
let btn = UIButton(type: UIButtonType.custom) as UIButton
btn.backgroundColor = UIColor.red
btn.setTitle("boton", for: .normal)
btn.frame = CGRect(x:0, y:5, width: 80, height:40)
//btn.addTarget(self, action: "buttonPressed:", for: UIControlEvents.touchUpInside)
btn.tag = indexPath.row
cell.contentView.addSubview(btn)
cell.contentView.addSubview(label)
cell.tag = indexPath.row
return cell
}
UITableview create 10 cell at scroll down recreate cell view
You can using
cell.contentView.removeFromSuperview() before cell.contentView.addSubview(label) or using cell.textLabel?.text
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
cell.contentView.removeFromSuperview()
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 400, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
cell.contentView.addSubview(label)
return cell
}
Note This solution will delete All subview in cell

SWIFT 3: List with Dropdown pictures/clips

I'm trying to develop an app that has a similar look as the pictures that I have attached here, since I really like that Idea.
After selecting an item, it drops down and a clip starts playing
Any idea on how to implement this? I can work with tables and lists, but I have no idea on how to actually implement something like this.
You can achieve this with multiple ways
let indexPath = NSIndexPath(forRow: YourSelectedRow, inSection: 0)
tableView.insertRowsAtIndexPaths(indexPath, withRowAnimation: .none )
insert a different row here which will be tricky to manage.
Create all this headers and and create only one cell under selected section.
var selectedSection = -1
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 50)
let button = UIButton(frame: view.frame)
button.tag = section
button.addTarget(self, action: #selector(selectExercise(_:), forControlEvents: UIControlEvents.TouchUpInside)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 5
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if section == selectedSection
{
return 1
}
else
{
return 0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier(“YourDetailCell”, forIndexPath: indexPath) as! YourDetailCell
return cell
}
fun selectExercise(sender:UIButton)
{
selectedSection = sender.tag
}
Create two cells and change that specific cell with whole cell portion with animation
var selectedRow = -1
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
if selectedRow == -1
{
selectedRow = indexPath.row
tblConfirmedServices.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Bottom)
}
else
{
selectedRow = - 1
tblConfirmedServices.reloadRowsAtIndexPaths([indexPathPre], withRowAnimation: .Top)
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
if selectedRow = indexPath.row
{
let cell = tableView.dequeueReusableCellWithIdentifier(“YourDetailCell”, forIndexPath: indexPath) as! YourDetailCell
return cell
}
else
{
let cell = tableView.dequeueReusableCellWithIdentifier(“YourCell”, forIndexPath: indexPath) as! YourCell
return cell
}
}

Text overlapping itself in table cells SWIFT

I have some text which goes into UIlabels I have created inside a table view cell. When these table view cells become updated the text overlaps itself, almost like the previous text what was there has not been removed, like so:
code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell",forIndexPath: indexPath) as! UITableViewCell
var nameLabel = UILabel(frame: CGRectMake(cell.frame.size.width * 0.040, cell.frame.size.height * 0.22, cell.frame.size.width * 0.735, cell.frame.size.height * 0.312))
var userAtIndexPath = finalMatchesBlurUser[indexPath.row]
nameLabel.text = userAtIndexPath.username.uppercaseString
cell.addSubview(nameLabel)
}
The finalMatchesBlurUser is a PFUser fetched from Parses database that will be changing, when this change is what causes the names to overlap.
Can anyone point out why this is happening?
Everytime you update the tableview, it checks the queue to see if it can reuse a cell instead of initializing a new one. In this case, when it updates, it has cells in the queue so you're adding a new label subview everytime the table updates which is causing this effect. In this case, you should only add the label subview if it doesn't exist already. Otherwise, just update the text of that subview.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell",forIndexPath: indexPath) as! UITableViewCell
if let nameLabel = cell.viewWithTag(100) as? UILabel{
var userAtIndexPath = finalMatchesBlurUser[indexPath.row]
nameLabel.text = userAtIndexPath.username.uppercaseString
}
else{
nameLabel = UILabel(frame: CGRectMake(cell.frame.size.width * 0.040, cell.frame.size.height * 0.22, cell.frame.size.width * 0.735, cell.frame.size.height * 0.312))
nameLabel.tag = 100;
var userAtIndexPath = finalMatchesBlurUser[indexPath.row]
nameLabel.text = userAtIndexPath.username.uppercaseString
cell.addSubview(nameLabel)
}
return cell;
}
the UILabel is created every time even when the cell is reused.
A solution is to create the UILabel in Interface Builder and assign a tag (e.g. 100).
Then use this code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell",forIndexPath: indexPath) as! UITableViewCell
let nameLabel = cell.viewWithTag(100) as! UILabel
let userAtIndexPath = finalMatchesBlurUser[indexPath.row]
nameLabel.text = userAtIndexPath.username.uppercaseString
}

Changing cell background color in UICollectionView in Swift

I am using horizontal collection view to scroll dates. Collection view contain 30 cells. If I select first cell, to indicate the selection, cell background color has been change to brown from default color red. Then, if I select another cell, selected cell color has changed to brown from red. But first cell BGColor remains the same (brown). How can i change to default color by clicking other cell?
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath
indexPath: NSIndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell",
forIndexPath: indexPath) as myViewCell
cell.date_label.text = arr_date[indexPath.item]
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath
indexPath: NSIndexPath) {
var cell = collectionView.cellForItemAtIndexPath(indexPath) as myViewCell
if(cell.selected)
{
cell.backgroundColor = UIColor.brownColor()
}
else
{
cell.backgroundColor = UIColor.redColor()
}
}
You can use the function collectionView with the parameter didSelectItemAtIndexPath
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath
indexPath: NSIndexPath) {
let selectedCell:UICollectionViewCell = myCollectionView.cellForItemAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor(red: 102/256, green: 255/256, blue: 255/256, alpha: 0.66)
}
This creates a constant for the selected UICollectionViewCell, then you just change the background's color
And then for return to the original color when it is deselected, you must use the function collectionView with the parameter didDeselectItemAtIndexPath
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let cellToDeselect:UICollectionViewCell = myCollectionView.cellForItemAtIndexPath(indexPath)!
cellToDeselect.contentView.backgroundColor = UIColor.clearColor()
}
And you change the color to the original one!
For example here is the screenshot from this code in a filterApp
UICollectionView example
var selectedIndex = Int ()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
if selectedIndex == indexPath.row
{
cell.backgroundColor = UIColor.green
}
else
{
cell.backgroundColor = UIColor.red
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
selectedIndex = indexPath.row
self.yourCollctionView.reloadData()
}
May be crazy, But it works fine for me...!
You could maintain a copy of the last selected index path, and then in your didSelectItemAtIndexPath compare the index paths to see if they are different. If different, change the colors of the two cells at those index paths as necessary and then copy the new index path over the old.
Edit
Thinking about this again, this should be done with the backgroundView and selectedBackgroundView properties of the cells. After you dequeue a cell you can do the following to let iOS handle the changing.
cell.backgroundView.backgroundColor = [UIColor redColor];
cell.selectedBackgroundView.backgroundColor = [UIColor brownColor];
Best way to handle background colour on selected cell is observing the property isSelected. This handles both selection and un-selection of a cell otherwise it would be tricky to un-select a selected cell at selection of any other cell.
Here is the demonstration of using isSelected property of UICollectionViewCell:
class CustomCollectionViewCell: UICollectionViewCell {
override var isSelected: Bool {
didSet {
contentView.backgroundColor = isSelected ? .red : .white
}
}
}

Swift tableView cell set accessory type

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet
var tableView: UITableView
var items: String[] = ["We", "Heart", "Swift"]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "myCell")
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return self.items.count;
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("myCell") as UITableViewCell
cell.textLabel.text = self.items[indexPath.row]
cell.accessoryType = UITableViewCellAccessoryType.DetailDisclosureButton
cell.selectionStyle = UITableViewCellSelectionStyle.Blue
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
return cell
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
}
}
My problem is that the accessoryType and the selectionStyle don't get changed.
The tableView.separatorStyle does get changed as well as the cell.textlabel.text.
How can I fix that?
UITableViewCell.SelectionStyle.blue
The cell has a default background color when selected.
In iOS 7, the selection color is no longer blue. Use
UITableViewCell.SelectionStyle.default instead.
As for the accessoryType, it should work fine as long as you don't change it later somewhere else. Make sure that the table width is correct, otherwise accessory views might be offscreen.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet
var tableView: UITableView
var items: String[] = ["We", "Heart", "Swift"]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "myCell")
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return self.items.count;
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("myCell") as UITableViewCell
cell.textLabel.text = self.items[indexPath.row]
cell.selectionStyle = UITableView.CellSelectionStyle.blue
/*
enum UITableViewCellAccessoryType : Int {
case none // don't show any accessory view
case disclosureIndicator // regular chevron. doesn't track
case detailDisclosureButton // info button w/ chevron. tracks
case checkmark // checkmark. doesn't track
case detailButton // info button. tracks
}
*/
// Standard options
cell.accessoryType = UITableViewCell.AccessoryType.none
cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
cell.accessoryType = UITableViewCell.AccessoryType.detailDisclosureButton
cell.accessoryType = UITableViewCell.AccessoryType.checkmark
cell.accessoryType = UITableViewCell.AccessoryType.detailButton
// Custom view options
cell.accessoryType = UITableViewCell.AccessoryType.none
cell.accessoryView = UIView(frame: CGRectMake(0, 0, 20, 20))
cell.accessoryView.backgroundColor = UIColor.blueColor()
return cell
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
}
}
Note that it isn't a good solution to set separatorStyle of the table each time the cell is requested, instead do it once when the tableView is loaded: at viewDidLoad.
I didn't have any luck setting it in the cellForRowAtIndexPath method, moving it to willDisplayCell fixed the issue with it not showing up.
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.accessoryType = .DisclosureIndicator
}
I would like to share my experience about this, I had the same issue, cell.accessoryType = IUTableViewCellAccessoryType.Checkmark
And I noticed my tableview didn't have constraints, so I added missing constraints then it worked for me
Below will set your accessoryView as an icon named "sentIcon". Just in case!!!
let sentImage = UIImage(named: "sentIcon")
let sentImageView = UIImageView(image: sentImage)
sentImageView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
sentImageView.tintColor = .lightGray
cell.accessoryView = sentImageView