In one of my methods I want to iterate between the cells I have and perform changes on them, something like:
for (UITableViewCell *cell in ___________) {
cell.accessoryType = accessoryType = UITableViewCellAccessoryCheckmark;
}
so is there a property that will complete the ____________ ?
tnx!
There are only visible cells array self.tableView.visibleCells
for (UITableViewCell *cell in self.tableView.visibleCells) {
cell.accessoryType = accessoryType = UITableViewCellAccessoryCheckmark;
}
The UITableView itself doesn't know much about its content. That's the job of it's dataSource delegate. See documentation for UITableViewDataSource
Rather than thinking of the problem in a linear fashion. Think of the problem as event driven. If you want to modify the cell before it is displayed, you can check out tableView:willDisplayCell:forRowAtIndexPath: on the UITableViewDelegate
edit: given that you are looking to set the accesoryType you should probably try using tableView:cellForRowAtIndexPath:. Since that's where you're either dequeueing a reusable cell or manually alloc] init]'ing one .
Have you tried: yourTableView.visibleCells
Chikabuz is right.
BUT you should avoid making changes to the cells like this. Instead you should tell the tableView that your cells are updated and provide the changes in - [id<UITableViewDataSource> tableView:cellForRowAtIndexPath:] like so:
- (IBAction)toggleSelecting:(id)sender {
[[self tableView] setEditing:![[self tableView] isEditing] animated:YES];
// or with custom use with own BOOL property:
// [self setEditing:![self editing]];
[[self tableView] reloadRowsAtIndexPaths:[[self tableView] indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationFade];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// cell setup here...
// or with custom use with own BOOL property:
// if ([self editing]) {
if ([[tableView] isEditing]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
return cell;
}
Probably you can't get all cells in one array. But you can try to use the following:
let cellsArray: []
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Your data source methods
let cell = ......
....
cellsArray.append(cell)
}
This way you can get array of cells after view loads. I think there is no any other way to do that.
Related
I have a setting screen that is a UITableView with rows of settings. When user open that screen I load stored settings and filled to UITextField etc... Everything was fine.
But there are some of the checkmark settings, I've been trying to check this in programmatically way but is not work, here is my code:
-(void)viewDidAppear:(BOOL)animated{
[self LoadCurrentRecord];
if(_previousValid)
{
NSIndexPath *regionFromData = [NSIndexPath indexPathForRow:_regionAutoCheck inSection:3];
[self.tableView cellForRowAtIndexPath:regionFromData].accessoryType = UITableViewCellAccessoryCheckmark;
}
[self.tableView reloadData];
}
In fact, I can see data can load by check to this category but I didn't see checkmark icon.
Any idea?
You must need to set it in this method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell; // Create Cell
if(_previousValid && indexPath.row == _regionAutoCheck && indexPath.section == 3 )
{
// SET CHECKMARK
} else {
// SET NONE
}
}
Here is how you should work with table- and collectionViews:
Have a collection of dedicated data-elements for each of which a cell will be used to display its data. In your case this would be some kind of Region object.
Implement the table/collectionview datasource methods that return number of cells in section and number of sections based on that collection.
Make sure you configure each cell ONLY in -tableView:cellForRowAtIndexPath: / -collectionView:cellForItemAtIndexPath:, just like PKT's answer. This cell might be reused, so assume any changes you made to this type of cell you need to update here.
When data changes, create an indexPath for the object that changes based on its position in the collection from 1. Then call '-reloadRowAtIndexPath:'/ -reloadItemAtIndexPath for that object. This will cause the tableView/collectionView to call -tableViewcellForRowAtIndexPath:/-`collectionView:cellForItemAtIndexPath:' again. As this method now contains the logic for configuring the cell based on your data-object, everything is in sync.
I can't stress enough how important 1. is. Simplest example is: each section is an array of data objects. If you have multiple sections, you can add each array to another array:
// one section:
NSArray *myData =
#[
#[dataItem1, dataItem2, dataItem3]
#[dataItem4, dataItem5, dataItem6]
];
- (NSUInteger) numberOfSectionsInTableView: (UITableView *) tableView
{
return myData.count;
}
- (NSUInteger) tableView: (UITableView *) tableView numnberOfRowsInSection: (NSUInteger) section
{
NSArray *dataForSection = myData[section];
return dataForSection.count;
}
- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath:
{
NSArray *dataForSection = myData[indexPath.section];
MyObject *dataObject = dataForSection[indexPath.row];
NSString * cellID = #"myCellID";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: cellID];
if (nil == cell)
{
// create a cell
// ...
}
// configure the cell based on the data object
if (dataObject.isBlue)
{
cell.contentView.backgroundColor = [UIColor blueColor];
}
else
{
// N.B.! don't forget the else clause, as cells are reused, so this
// cell might be recycled from a cell that was used to display
// the data of a blue data object before.
cell.contentView.backgroundColor = [UIColor blueColor];
}
return cell;
}
Finally, I've found a really simple solution for this case.
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == _regionAutoCheck && indexPath.section == 3)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone; // for other cases remove it
}
}
UPDATE
After that, add [self.tableView reloadData]; into -(void)viewDidAppear:(BOOL)animated and you will see it works.
That's all.
Thanks all for help
I am using a custom cell class in a tableview controller.
When I include a statement in the tableviewcontroller in cellForRowAtIndexPath NSLog(#"method called"): it does not seem to get called.
Is it possible that this method is not called when you have a custom cell?
Edit:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"cell for row at index path called");
NSDictionary *item= [self.getItems objectAtIndex:indexPath.row];
//This sets place in storyboard VC
IDTVCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.item = item;
if (cell == nil) {
cell = [[IDTVCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"Cell"];
}
return cell;
}
cellForRowAtIndexPath is not called if no rows are returned.
-tableView:cellForRowAtIndexPath: is not getting called
That is what happened in my case.
It can also not get returned if you reload table on wrong thread and in certain other scenarios.
cellForRowAtIndexPath: not called
However, a custom cell per se does not cause this..
To answer your question - Yes, it is.
There could be n-number of reasons why cellForRowAtIndexPath: is not getting called. This may be because delegate / dataSource is not set or UITableView frame is not set... etc. etc.
You should easily find a solution with more online research and closure look at your code.
I want a tableview inside another tableviewCell like the following image.It shows one complete cell with a few details and a tableview. How can i do this?I was following this link Link.This is an old code .It is using xibs.I dont have any idea where to set the delegate for the inner tableview.Please help.Any suggestion will be realy helpfull.
My first idea would be:
Subclass UITableViewCell ("MainTableViewCell") and extend it with UITableViewDelegate and UITableViewDatasource.
Next to all the properties you need in "MainTableViewCell" add a TableView "tableViewFilms" and an array "films" for the Films. Also don't forget to add the datasource methods for a tableview to the implementation file.
To easily setup a cell I add a setup-method to the header-file. Which can be called once the cell is instantiated. You can modify it as you want, give it as many parameters as you want and in the implementation (see step 4) set datasource and delegate of your inner tableview.
- (void)setupCellWithDictionary:(NSDictionary *)dict AndArray:(NSArray *)filmsForInnerTable;
You can call this method in your datasource method, once a cell is instantiated:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MainTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainTableViewCell" forIndexPath:indexPath];
NSDictionary *dict = (NSDictionary *) allDataDictionaries[indexPath.row];
[cell setupCellWithDictionary:dict AndArray:filmsForInnerTable];
return cell;
}
Subclass UITableViewCell another time: "FilmTableViewCell"
When setting up the a Cell of "MainTableViewCell", set the delegate and the datasource of "tableViewFilms" to self (object of "MainTableViewCell").
- (void)setupCellWithDictionary:(NSDictionary *)dict AndArray:(NSArray *)filmsForInnerTable{
self.films = filmsForInnerTable;
self.tableViewFilms.dataSource = self;
self.tableViewFilms.delegate = self;
[self.tableView reload];
//more instructions
}
Populate the tableview with the data from the array "films" using "FilmTableViewCells".
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FilmTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"FilmTableViewCell" forIndexPath:indexPath];
Film *film = (Film*)films[indexPath.row];
[cell setupCellWithFilm:film];
return cell;
}
Hope this helps.
Don't forget to use Outlets, the method definitions and to set the reuse-identifiers for the cells!
Check my answer in this ios 8 Swift - TableView with embedded CollectionView. You have replace that UICollectionView with UITableView.
Everything else is pretty much the same. Its just a head start with UITableView and UICollectionView created programmatically.
I can change it accordingly if you don't understand.
I have a UITableView with a cell that has two labels in it. The table view is linked to the dataSource and delegate, the labels in the cell are linked to an IBOutlet, what not. It looks to me like this should work, but this code below is not running so the Cell or labels are not populated with text. Any ideas? Or anything I'm missing?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"theLabelCell";
CustomClassCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
CustomClassText *customText = _arrayThatHasText[indexPath.row];
if (![self isSelectionMode]) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.TitleLabel.text = customText.firstLabel;
cell.TextLabel.text = customText.secondLabel;
return cell;
}
Did you remember to also register the cell identifier for reuse?
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"CustomClassCell" bundle:nil] forCellReuseIdentifier:#"theLabelCell"];
}
If you are not seeing any cells, then check whether numberofSections and numberOfRowsInSection delegate methods are not returning 0
When does your _arrayThatHasText get populated? The issue might very well be that the data source (_arrayThatHasText) is getting instantiated before the numberofSections and numberOfRowsInSection delegate methods are being called and then after these methods are called the data source is being populated with actual data -> which would result in the 0 values in the delegate methods as you are experiencing.
You might want to try putting a [self.tableView reloadData] call at the end of ViewWillAppear or in ViewDidAppear method and see if that helps.
Say I have a table with 10 static cells in it, is there a way to select a certain cell programmatically?
I've tried this
UITableViewCell *cell = [self.tableView.subviews objectAtIndex:indexPath.row];
but that does not actually return a table cell it seems.
this seems to crash my code
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
Im trying to set the individual heights for the static cells in code. An option would be to make outlets for each individual static cell, but that seems silly.
To access statically created cells, try this:
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
This works for static cells. So, if you're in the...
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
return cell;
}
... delegate, you can access all statically configured cells using the above declaration. From there, you can do what ever you want with "cell".
I had a ViewController that had two UITableViews on it. One of them had cells defined statically, with a Storyboard, and the other had cells defined dynamically using code. Given I was using the same ViewController as delegate for both tables, I needed to prevent new cells from being created where cellForRowAtIndexPath was being called where cells had already been created.
In your case, you need to gain programmatic access to your cells.
Have fun.
Create an #IBOutlet.
This will work even if you re-arrange your static cells programmatically.
You can try this...
UITableViewCell *cell = (UITableViewCell*)[yourTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:rowvalue inSection:0]];
If you need accessing the cell object, then using UITableViewCell method cellForRowAtIndexPath is quite appropriate.
That may either just pass the cell, if it is visible, or call the delegate method cellForRowAtIndexPath (do not mix them up) which you should provide. If that one crashes then dig deeper and investigate the root cause of the crash.
Use table view delegate method
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger height;
if(0 == indexPath.row)
{
height = 44;
}
else
{
height = 50;
}
return height;
}
This is a Swift 2.3. Solution.
The UITableViewController is created in IB.
/*
NOTE
The custom static cells must be
In the IB tableview if one is being used
They also must be updated to be MYCustomTableViewCell
instead of UITableViewCell
*/
import UIKit
class MYCustomTableVC: UITableViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
// NO Nib registration is needed
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath) as! MYCustomTableViewCell
// MYCustomTableViewCell can be created programmatically
// without a Xib file
return cell
}
}