I have a collection view which looks like
1st cell will hold some text , and from 2nd cell onwards data is populated from a data manager
To handle this i have code something like this
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if(indexPath.row==0){
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(customCellNibName, forIndexPath: indexPath)
let offer: TGOfferDataSource? = dataSource?.dataforIndexPath(indexPath) as? TGOfferDataSource
cell.setOfferData(offer!)
return cell
}
else if(indexPath.row != 0)
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellNibName, forIndexPath: indexPath)
let product: TGProductDataSource? = dataSource?.dataforIndexPath(indexPath) as? TGProductDataSource
cell.setProductData(product!)
return cell
}
}
The issue is 1st product from data manager is hidden behind this grey cell.
So i figure i will have to increment index path in elseif part. Something like indexPath in elseif part should also starts from 0.
(Swift and cells are xib)
Any idea how to do it ?
Thanks
Had a look at this but how to do this in swift
EDIT
If I remove if part , it looks like
You can create new NSIndexPath in swift using following
let path = NSIndexPath(forRow: indexPath.row - 1, inSection: indexPath.section)
And you can pass above path to your dataforIndexPath in the else part. Hope that helps!
Related
I have a TableView that is embedded into a CollectionView, and I am trying to show relevant data in the TableView that corresponds to the correct CollectionViewCell or IndexPath Item. I tried assigning tag as such: cell.tableView.tag = indexPath.item but it seems to be problematic.
I tried print(tableView.tag) in my collectionViewCell and it printed
2 1 0 3 4 5
but I have 7 collectionViewCells in total so the last tag isn't printing for some reason.
My collectionView is embedded in another TableView already, below is the code in the MasterTableViewCell.swift:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if diningIndexPath.section == 0 {
let cell: FoodCourtCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "foodCourtCell", for: indexPath) as! FoodCourtCollectionViewCell
cell.tableView?.register(UINib(nibName: "RestaurantTableViewCell", bundle: nil), forCellReuseIdentifier: "restaurantCell")
cell.tableView.tag = indexPath.item
//...
return cell
}
}
In the customCollectionViewCell.swift, I have this code for my tableView:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: RestaurantTableViewCell = tableView.dequeueReusableCell(withIdentifier: "restaurantCell", for: indexPath) as! RestaurantTableViewCell
print(tableView.tag)
let currentRestaurant = foodCourts[tableView.tag].childLocations[indexPath.row]
cell.textLabel.text = currentRestaurant.name
//...
return cell
}
Is there any way to fix this, or are there other ways to achieve what I want to do? Any help is appreciated, thanks!
Nesting these entities is always a pain especially when you need to access indexPaths of items later. If if get your problem correctly. One of the solutions I suggest is to store a map (dictionary) of your paths. For a fast access to them. Here's an example of how I managed this in a similar situation:
typealias CollectionIndexPath = IndexPath
typealias TableIndexPath = IndexPath
var indexMap: [CollectionIndexPath: TableIndexPath] = [:]
Now when you need to access some of the items or configure it.
func cellForItemAtIndexPath { ... } {
let cell = { ... }
let cellPath = indexPath
let tablePath = indexMap[cellPath]
let foodCourtForCell = foodCourts[cellPath.item]
let childLocationsForTableView = foodCourtForCell.childLocations
cell.configureWith(court: foodCourtForCell, locations: childLocations)
Now you can manage all the data related to this nested monster from the outside.
In my Swift project I have a table controller view with a table view inside. The table view is divided into 4 section and every section has 4 rows. Currently, each row is formed by a label beside a text field.
My purpose is that only rows in the first section has label beside text field. On the contrary, I want the last 3 sections have only labels in their rows (and NOT text fields).
Please, help me.
That's the code I wrote to manage with this problem but it's not working:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("index ", indexPath.section);
let cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath)
cell.textLabel?.text = self.items[indexPath.section][indexPath.row];
if(indexPath.section == 0){
let cell = tableView.dequeueReusableCellWithIdentifier("tableCell") as! TextInputTableViewCell
cell.configure("", placeholder: "name")
}
return cell
}
It's not working because you are using the same cell for all the rows. You need to define two different rows. You can do this by setting prototype cells to more than one row (two in your case).
Each cell must have its own reuse identifier and it must be unique within that table view.
Then in your tableView(cellForRowAtIndexPath:) you can ask:
if indexPath.section == 0 {
cell = tableView.dequeueReusableCellWithIdentifier("firstSectionCell", forIndexPath: indexPath)
//
} else {
cell = tableView.dequeueReusableCellWithIdentifier("otherSectionCell", forIndexPath: indexPath)
//
}
Also note that in Swift you do not need to use parenthesis in if-statement (nor for, while, etc). So I suggest you remove them as they are pointless.
It looks like your cell in if(indexPath.section == 0) block doesn't actually have scope outside that block so any properties set there won't get returned there. If you just want to remove the textField, but keep the label, You can just set the textField.hidden = true. Here is how I would go about it.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath) as! TextInputTableViewCell
cell.textLabel?.text = self.items[indexPath.section][indexPath.row];
if(indexPath.section == 0){
cell.textField.hidden = false //Assumes TextInputTableViewCell's textField property is called "textField"
cell.configure("", placeholder: "name")
} else {
cell.textField.hidden = true //Not in first section we will hide textField
}
return cell
}
Doing it this way you can use the same cell class for every cell in your tableView, but just hide what you want based on its section.
Previously, I was populating my TableView by using this code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath:
indexPath) as CustomTableViewCell
let entry = entries[indexPath.row]
cell.entryLabel!.text = entry.labelOne
cell.entryDayLabel!.text = entry.day
cell.entryDateLabel!.text = entry.date
return cell
}
I've since added sections to my Table, and I'm having trouble figuring out how to specify both the section and the row in this call to my array.
I've tried
let entry = entries[indexPath.section]
and I've tried
let entry = entries[indexPath.row + indexPath.section]
But neither work correctly.
Is there a proper way to do this that I'm missing? Any help is greatly appreciated. Thanks!
indexPath.section
will return the current section.
What you usually want to do then, is add some conditional logic like:
if(indexPath.section == 0)
{
entry = entries[indexPath.row]
}
else if(indexPath.section == 1)
{
entry = whateverDataSource[indexPath.row]
}
Are you using two different tables and/or cell types for your sections?
In my storyboard I have 4 different prototype cells, each pertaining to a different "card" on a timeline view controller as demonstrated in the image below:
Appropriate constraints have been set, however when the timeline is loaded on the device the "cards" stack over each other as demonstrated in the image below:
I have been trying to get to the root of this problem for some time, but I really don't understand what is causing the layout to be so badly invalidated.
For reference, I am loading my cards in using the code below (I have stripped out un-necessary code which sets values of Outlets)
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var count = posts.count
var cell: UITableViewCell!
// Get the post we are currently on
let p = posts[indexPath.row] as Post
// Build the overview cell
if indexPath.row == 0 {
let userCell = tableView.dequeueReusableCellWithIdentifier("UserCardCell", forIndexPath: indexPath) as UserCardCell
// outlet setting code here
cell = userCell
}
// Handle other cell types
else
{
if posts[indexPath.row].getType() == PostType.MEDIA
{
let mediaCell = tableView.dequeueReusableCellWithIdentifier("MediaCardCell", forIndexPath: indexPath) as MediaCardCell
// outlet setting code here
cell = mediaCell
}
if posts[indexPath.row].getType() == PostType.TEXT
{
let textCell = tableView.dequeueReusableCellWithIdentifier("TextCardCell", forIndexPath: indexPath) as TextCardCell
// outlet setting code here
cell = textCell
}
if posts[indexPath.row].getType() == PostType.VERSUS
{
let versusCell = tableView.dequeueReusableCellWithIdentifier("VersusCardCell", forIndexPath: indexPath) as VersusCardCell
// outlet setting code here
cell = versusCell
}
}
return cell
}
Any suggestions on what I may be doing wrong would be greatly appreciated.
I'd like to find out the last UITableViewCell in the last position of my UITableView and change the detailTextLabel of this cell into "Last added". Does someone knows how to do this in Swift?
tableView gives you all you need to create last rows's indexPath and get it's cell.
let lastSectionIndex = tableView.numberOfSections()-1
let lastSectionLastRow = tableView.numberOfRowsInSection(lastSectionIndex) - 1
let indexPath = NSIndexPath(forRow:lastSectionLastRow, inSection: lastSectionIndex)
let cell = tableView.cellForRowAtIndexPath(indexPath)
but depending on your needs you might be better accessing the cell in tableView's delegate
func tableView(_ tableView: UITableView,
willDisplayCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath)
Something like
let lastSectionIndex = tableView.numberOfSections()-1
let lastSectionLastRow = tableView.numberOfRowsInSection(lastSectionIndex) - 1
let lastIndexPath = NSIndexPath(forRow:lastSectionLastRow, inSection: lastSectionIndex)
let cellIndexPath = tableView.indexPathForCell(cell)
if cellIndexPath == lastIndexPath {
// the last cell is about to be displayed. change get here.
}
Since table views always require a datasource, you should look there instead of the table view.
NSIndexPath *lastCellIDP = [NSIndexPath indexPathForRow:self.dataSource.lastObject inSection:0];
UITableViewCell *lastCell = [self.tableView cellForRowAtIndexPath:lastCellIDP];
lastCell.detailTextLabel.text = #"U NEED 2 ChAnGE!";
That code assumes your datasource is of type NSArray.
That said, I would put this logic inside a UITableViewCell subclass when you bind the data, or possibly the property on your model of your datasource if it's the last item.