I've been scouring the web trying to figure this out but can't find a clear answer. Here's what's going on:
I've created a UITableViewController called MainTableViewController and I have two custom cells that live in that: "FirstCell" and "SecondCell". They both use that naming convention as their reuse identifiers. I've also created cell class files for each: "FirstTableViewCell" and "SecondTableViewCell" that I've assigned each cell accordingly. I've also created IBOutlets for all the objects in the cells within each UITableViewCell class file.
So in MainTableViewController I have no problem getting "FirstCell" loaded. I'm doing that like so:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FirstCell") as! FirstTableViewCell
cell.friendfirstnameLabel.text = "Michael"
cell.friendImageView.image = UIImage(named: "mikepic")
return cell
}
How do I now call "SecondCell"? I know I will need to change my return to 2. But then how do I change the dequeueReusableCellWithIdentifier and cellForRowAtIndexPath code to make both my cells work? "Second Cell" has a radically different layout with different objects defined.
try this
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return yourArrayCount
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row % 2 == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("FirstCell") as! FirstTableViewCell
cell.friendfirstnameLabel.text = "Michael"
cell.friendImageView.image = UIImage(named: "mikepic")
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("SecondCell") as! SecondTableViewCell
cell.friendfirstnameLabel.text = "Michael"
cell.friendImageView.image = UIImage(named: "mikepic")
return cell
}
}
You just need to deque your second cell with the reuse identifier assigned. This is completely on your requirements when you want to use first and when second.
You should simply change the parameter value you send to dequeueReusableCellWithIdentifier based on [indexPath row]. If it's 0, use "firstCell" and if it's 1, use "secondCell" and create a cell for the matching object type.
here i see you have static text to show in the cell view. Usually we have NSArray of data to populate the data in tableview and we define the count in umberOfRowsInSection method
so it will be very easy if you know what data you want to display in which cell like that you can easily use If statement for selecting your desire table cellview
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayCount
}
after checking count you can do this by if statement
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
NSUInteger row = [indexPath row];
if [yourArray objectAtIndex:row] =="Michael" {
let cell = tableView.dequeueReusableCellWithIdentifier("FirstCell") as! FirstTableViewCell
cell.friendfirstnameLabel.text = "Michael"
cell.friendImageView.image = UIImage(named: "mikepic")
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("SecondCell") as! SecondTableViewCell
cell.friendfirstnameLabel.text = “Unknown"
cell.friendImageView.image = UIImage(named: "mikepic")
return cell
}
}
Related
How to implement two xib cells and only one array, if array count is nil show empty xib cell and if array count is not nil show xib cell with data swift. Please solve the problem i have searched lot of no answer is related to me.
This example assumes your data array is named myData:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return either 1, or the count of your data, whichever is greater
return max(1, myData.count)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// if it's the first row, and your data is empty
if indexPath.row == 0 && myData.count == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "emptyCell", for: indexPath) as! EmptyCell
return cell;
}
let cell = tableView.dequeueReusableCell(withIdentifier: "dataCell", for: indexPath) as! DataCell
// populate the cell
return cell
}
My Situation: I want to save Data from an Array at Index X in an Row on Index X in Section 1.
My code is:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return setObjectToPass.count
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section \(section)"
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cellEmpty = tableView.dequeueReusableCellWithIdentifier("LabelCell")
var countCell = 0
while countCell < setObjectToPass.count {
let indexPaths = NSIndexPath(forRow: countCell, inSection: 0)
let cell = tableView.dequeueReusableCellWithIdentifier( "LabelCell", forIndexPath: indexPaths)
cell.textLabel!.text = String(setObjectToPass[countCell])
print(cell)
countCell+=1
return cell
}
My Problem is that only the first index of the Array SetObjectToPass is passed and set into the Cell.text
while counter < fetchResult?.count {
let set = fetchResult![counter]
counter+=1;
setObject.append((set.reps?.integerValue)!)
}
You are implementing the tableView(_:cellForRowAtIndexPath:indexPath:) method wrongly.
Remember, every delegate method in UITableViewDelegate is like asking you a question. For example, numberOfSectionsInTableView(_:) is like asking you "How many sections do you want in your table view?". You answer the question by returning a value.
tableView(_:cellForRowAtIndexPath:indexPath:) is similar. It asks a question as well. It asks "What should I display in the table row at this index path?"
In your code, it seems like you want to give multiple answers - looping through the array and attempting to return multiple times. But it doesn't work that way, you can only give one answer.
In the first iteration of the while loop, the execution hits return and stopped. That's why you only see the first table cell.
Thus, you should change your code so that it only gives one answer to the question:
let cell = tableView.dequeueReusableCellWithIdentifier("LabalCell")
cell.textLabel?.text = String(setObjectsToPass[indexPath.row])
return cell
Don't use the loop in cellForRowAtIndexPath delegate method. cellForRowAtIndexPath method call each row based upon numberOfRowsInSection count rows, simply use indexpath.row, Use this code,
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cellEmpty = tableView.dequeueReusableCellWithIdentifier("LabelCell")
let cell = tableView.dequeueReusableCellWithIdentifier( "LabelCell", forIndexPath: indexPaths)
cell.textLabel!.text = setObjectToPass[indexPath.row] as? String
return cell
}
hope its helpful
My table view has some elements sorted by some types: TypeA, TypeB and TypeC.
I want that when I click on a cell with TypeA to change the selection color to Red, when I type on TypeB to change color to Blue and when pressing on TypeC to change color to Yellow.
Right now I came up with this code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
guard let mode = dataSource.selectedObject else {
fatalError("willDisplayCell, but no selected row?")
}
let type = ModeType(rawValue: mode.type)!
let selectionColor = UIView() as UIView
selectionColor.backgroundColor = type.color()
cell.selectedBackgroundView = selectionColor
}
My issue with this is that willDisplayCell is called when I start my app and my data source is empty so I get a fatal error.
How can I overcome this ? Maybe using a flag to do this only when didSelectRowAtIndexPath was called.
Or is there another way to achieve what I am after ?
I assume you have created custom UITableviewCell. Create a cell type enum.
enum CellType {
case RedCell
case Yellowcell
case OrangeCell
}
//Create enum property
class CustomCell : UITableViewCell {
var cellType:CellType = CellType.RedCell //Default is RedCell
}
Now you have to assign the cell type in your ViewController tableview datasource.
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! CustomCell
cell.cellType = .RedCell //your choice
return cell
}
override func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, didHighlightRowAtIndexPath indexPath: NSIndexPath) {
var cell = tableView.cellForRowAtIndexPath(indexPath)
switch(cell.cellType) {
//Handle Switch case
case .RedCell:
cell?.contentView.backgroundColor = UIColor.redColor()
cell?.backgroundColor = UIColor.redColor()
}
}
override func tableView(tableView: UITableView, didUnhighlightRowAtIndexPath indexPath: NSIndexPath) {
var cell = tableView.cellForRowAtIndexPath(indexPath)
// Set unhighlighted color
cell?.contentView.backgroundColor = UIColor.blackColor()
cell?.backgroundColor = UIColor.blackColor()
}
EDIT:
If you have created 3 different types of cell class check tableview cell class type and change the color in didHighlightRowAtIndexPath method.
My issue with this is that willDisplayCell is called when I start my
app and my data source is empty so I get a fatal error.
tableView(_:willDisplayCell:forRowAtIndexPath:) will only be called if your data source tells the table view that there are rows to display. So the problem more likely is that your tableView(_:numberOfRowsInSection:) method is returning a number larger than zero when your data source is empty.
Also, your code looks like it expects tableView(_:willDisplayCell:forRowAtIndexPath:) to get called only for selected rows. It gets called for all displayed rows. But this method isn't necessary to affect the background color. In fact, it's rarely used in most apps. There are only a few edge cases where you need to mess with the cell just before it's displayed.
The proper way to set the selection background color is to create and assign a UIView to the cell's selectedBackgroundView property. You can do that either from the cell's subclass (preferred for complex cells) or from the tableView:cellForRowAtIndexPath: data source method:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell")
cell!.textLabel?.text = "Kilroy was here."
cell!.selectedBackgroundView = UIView(frame: cell!.bounds)
cell!.selectedBackgroundView!.backgroundColor = .greenColor()
return cell!
}
I would like to use a UITableView to have 2 static cells on top of a list of dynamic cells. As far as I understand, I have to use a dynamic prototype tableView. But I don't understand how to add 2 static cells and design them, eg. adding a textfield to the first and a label to the second.
What do I have to do in my storyboard? And what do I have to do inside the Controller? How can I differentiate the static from the dynamic cells?
EDIT:
I tried this for testing:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cardCell", forIndexPath: indexPath) as CardTableViewCell
//static cell
if (indexPath.row < 2) {
cell.dyn.text = "static \(indexPath.row)"
return cell;
}
// Configure the cell...
cell.dyn.text = "buh"
return cell
}
this results in this:
Later when I use real data I will miss the first 2 data rows...
Can I somehow "reset" the row counter after I created my static cells?
And how can I modify the 2 static cells? For adding a textfield and labels? Or do I have to do this programmatically?
I found help here: Mixing static and dynamic sections in a grouped table view
And my solution looks like this:
1.
Add and layout the static cells:
Give each cell a unique name and add them as outlet to the TableViewCell class
Adjust the code:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (section == 2){ // my dynamic cell is index 2
return 5 // just for testing, add here yourrealdata.count
}
return 1 // for static content return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: CardTableViewCell!
if (indexPath.section == 0) {
cell = tableView.dequeueReusableCellWithIdentifier("static1", forIndexPath: indexPath) as CardTableViewCell
cell.cardSetName?.text = self.cardSetObject["name"] as String
}else if (indexPath.section == 1) {
cell = tableView.dequeueReusableCellWithIdentifier("static2", forIndexPath: indexPath) as CardTableViewCell // just return the cell without any changes to show whats designed in storyboard
}else if (indexPath.section == 2) {
cell = tableView.dequeueReusableCellWithIdentifier("cardCell", forIndexPath: indexPath) as CardTableViewCell
cell.dyn.text = "row \(indexPath.row)" // return test rows as set in numberOfRowsInSection
}
return cell;
}
End results will look like this:
I hope I can help someone with the same question :)
you could use something like this to use or display your static cell
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return numberOfDynamicCells + 1;
}
and in you cellForRowAtIndexPath datasource you may use something like this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 0){
// go ahead to display your static Cell
}
else{
//go ahead to display your dynamic cells.
}
return yourCell;
}
here is code for swift.
func numberOfRowsInSection(_ section: Int) -> Int{
return numberOfDynamicCells + 1
}
and in you cellForRowAtIndexPath datasource you may use something like this.
func cellForRowAtIndexPath(_ indexPath: NSIndexPath) -> UITableViewCell?{
if indexPath.row = 0{
// go ahead to display your static Cell
}
else{
//go ahead to display your dynamic cells.
}
return yourCell;
}
Good Luck...
Yes you can by having static cells be IBOutlet properties and in the tableView(_:cellForRowAt:) you can return those properties for any index paths you want
Here's an example:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
return firstStaticCell
case 1:
return secondStaticCell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "DynamicCell", for: indexPath)
cell.textLabel?.text = "Dynamic \(indexPath.row + 1)"
return cell
}
}
I just made a UITableView in swift with expandable cells when clicking them. Upon being expanded, the cells show a UIDatePicker.
The expanding itself works fine, but the cell-content that should only visible when the cell is expanded kind of shines through the cells. Here is a screenshot of what I am talking about:
Cell 1 is expanded and the other cells are not. As you can see, their expandable content is visible while it actually shouldn't be.
Here is the code I use:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cellIdentifier = "Cell";
var cell: NewExpenseTableCell;
var array: NSArray = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil);
cell = array.objectAtIndex(0) as NewExpenseTableCell;
cell.backgroundColor = UIColor.whiteColor();
cell.descriptionLabel?.text = descriptionLabels[indexPath.item];
return cell;
}
var selectedRowIndex = -1;
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if selectedRowIndex == indexPath.row {
selectedRowIndex = -1;
} else {
self.selectedRowIndex = indexPath.row;
}
newExpenseTable.beginUpdates();
newExpenseTable.endUpdates();
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == selectedRowIndex {
return 206;
}
return 55;
}
Could anyone tell me how I can make sure the UIDatePicker is only visible when the cell is expanded?
Here's what I would recommend to get the cell reuse working correctly.
Open the .xib file for your NewExpenseTableCell. Go to Attributes Inspector, enter "NewExpenseTableCell" as the Identifier.
In the viewDidLoad method of your view controller, register the nib like so:
self.tableView.registerNib(UINib(nibName: "NewExpenseTableCell", bundle: nil), forCellReuseIdentifier: "NewExpenseTableCell")
In the cellForRowAtIndexPath method, replace the first four lines you have with this:
var cell = tableView.dequeueReusableCellWithIdentifier("NewExpenseTableCell") as NewExpenseTableCell