I am displaying files in a tableview. In cellForRowAtIndexPath, I want to display only certain types of files.
I am doing something like this:
if (document is folder) {
display folder details;
}
else (document is not folder) {
display empty cell;
}
by doing this i can display empty cells but those are still there(hidden) how to get rid of those rows. see the pic for details.
I think you should rethink the problem, cellForRowAtIndexPath: should never be called for a cell that does not exist. Determine how many folders are available in your data set and return that number in tableView:numberOfRowsInSection:
Then you don't need to worry about hiding it once cellForRowAtIndexPath: is reached because it is a real cell that should be created.
To 'hide' cells you will need to first create an array of only Folders. Your not really going to hide cells, but rather only include the correct objects in your tables datasource array.
In your viewDidLoad, iterate though your entire documents array and add any Folders to a separate folderArray like so:
_folderArray = [NSMutableArray new];
for(Document *doc in documentsArray)
{
if(doc is a folder)
{
[_folderArray addObject:doc];
}
}
Use that folderArray in your all of your tableView delegate & datasource methods instead of the documentsArray.
Related
My cell(UITableViewCell) contains a UITextView, and I have customed UIMenuController(Clipboard). Now I need select two or more cells at the same time, so that I can copy the text of them. What should I do?
Use this line for multiple selection.
self.tableView.allowsMultipleSelection = YES;
Allow multiple selection on your tableview by setting the property
self.tableView.allowsMultipleSelection = YES;
Then, in your didSelectRowAtIndexPath, you could manage a collection of data by storing or removing the UITextView's content based on what is returned by
if (cell.selected) {
// Add to collection
} else {
// Remove from collection
}
In the case that multiple cells are selected when you present your UIMenuController, you could manipulate the menu text to say something like
Copy text from (#) items
and then use your collection to grab the data regardless of which cell they accessed the menu from.
It would be helpful for the user to see some indication of multiple selection. For this you could set the accessoryType on the selected cell to UITableViewCellAccessoryCheckmark.
To deselect the row, set it back to UITableViewCellAccessoryNone.
I'd like to leverage Apple's locking section header control on my tableview (where the section header sticks to the top until pushed upward by the next section header), but I'd like to use my own view, and one that I design by xib.
Elsewhere in my app, I create views in code for the section headers and all is well, but when trying to do the same thing with a xib for a view, it gets problematic.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
ProductSectionHeader* header = self.productHeaderView;
if (!header)
{
[[NSBundle mainBundle] loadNibNamed:#"ProductSectionHeader" owner:self options:nil];
}
header.nameLabel.text = #"Some person";
header.locationLabel.text = #"Some place";
return header;
}
This shows the header view in the first section (each cell has it's own section) but then all headers disappear when the second header is prompted to show. It seems that I'm only allowed one reference to the xib or something.
So how do I reuse a xib to create multiple instances of that view in one controller, and how do I employ that into section headers?
So how do I reuse a xib to create multiple instances of that view in
one controller, and how do I employ that into section headers?
A new copy of the view is created each time you load the .xib. The trick is to save the newly loaded view in a different property or variable and then clear the outlet connected to the view so that you can load another copy. So, something like this, assuming productHeaderView is an outlet connected to the header view:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// load the view from the .xib
[[NSBundle mainBundle] loadNibNamed:#"ProductSectionHeader" owner:self options:nil];
// save it in a different variable
ProductSectionHeader* header = self.productHeaderView;
// clear the outlet for next time
self.productHeaderView = nil;
if (!header)
{
NSLog(#"There was a problem loading the view.")
}
header.nameLabel.text = #"Some person";
header.locationLabel.text = #"Some place";
return header;
}
I should also point out the relatively new UITableView method -registerNib:forHeaderFooterViewReuseIdentifier:, which makes things even easier. You can just register a nib object with the table and let the table worry about loading the view. There's a similar method for table cells.
In the line where you call loadNibNamed:, you're not doing anything with the result of that line. It returns an NSArray containing the views from that xib file, which you're not saving. You never set header to anything in your if statement. Assuming that xib contains only the one UIView that you want, you would want to get the item at index 0 from that array.
Also, the fact that you're seeing a header in the first place implies to me that self.productHeaderView is already set to something somewhere else in your code, so it never goes into your if statement in the first place. So I'm guessing you're seeing the issue you're seeing because it is trying to use the same UIView as the header for every section, and it's causing issues because it's trying to place it in multiple spots.
If you want to fix this, make sure that you're using a unique UIView for each section, so you shouldn't be trying to store and retrieve a single UIView in an instance variable like you are, unless you only had one section. You could maybe replace that with an NSMutableDictionary, so that you create and store a header for each section only once, and subsequent calls to this will just retrieve it from the dictionary.
I am trying to figure out the best way to approach this. I have a UITableView, and within it there could be X number of sections. I also have a button that produces a popover with a custom UIPickerView that displays the titles of each section (I got those values from the array, not the UITableView since I couldn't figure out how).
When they select an option, I am wanting to hide all of the sections in the UITableView expect, obviously, the one section with the title of the selected option.
I was wondering if you could loop through all of the sections, look at its title, and if it didnt match the selection, hide it? It might be worthwhile to note there will never be anymore than 10 sections with a few cells each, so I don't know if [table updateTable] or [table reloadData] is better.
My attempt:
//Filter out the notes that should display
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
//self.notesTable.dataSource = [myArrayOfDictionaries objectAtIndex:row];
//[self.notesTable reloadData]; this did not work
for (int section = 0; section < [notesTable numberOfSections]; section++){
//find sections that don't match pickerview selection
NSLog#("%#",[notesTable headerViewForSection:row);//return null?
}
}
Can you please post code for your UITableView.delegate and UITableView.dataSource methods?
You want to do something like this:
Maintain a #property pointing to allData and maintain another #property pointing to currentData
User picks a section
You grab the sectionData out of allData, set this sectionData as your currentData
Call reloadData on the tableView
Make sure your delegate and dataSource methods reference the currentData #property
It looks like the reason that this did not work for you above is because you are setting the UITableView's dataSource = currentData, which is incorrect. DataSource should always be set to the class that you set as conforming to this protocol (probably your UIViewController).
I have a UITableViewController with prototype cells containing UITextFields. To configure these custome cells, I've created a UITableViewCell subclass. I've conected the textField to the cell subclass via an outlet (nonatomic, weak).
On this subclass I've created a protocol for which the UITableViewController is its delegate so that everytime something changes in these textFields, the TableViewController knows about it. Basically I wanted this to save the values on the NSUserDefaults
Besides, in order to dynamically obtain values from these textFields, I can do something like this:
((TextFieldCell*)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]]).textField.text
It works ok most of the times. However when the textField is outside of the view because it has scrolled, the vaulue I get from textField.text is (null). As soon as it gets in the view again, everything goes back to normal.
I tried to change the outlet from weak to strong but to no avail.
I guess I could define some private NSStrings on the class, and fill them out when the delegate protocol gets called. The thing is that I wanted to get my code as generic as possible, keeping the need for private variables as low as possible, mostly to simplify the cell generation code.
Is there any other way to get the values of the textFields when they are outside of the view?
Thanks in advance!
But you know that UITableView only keeps Cells for the visible rect?
When a cell leaves the screen, and a new cell is needed for another cell moving into the visible area, the old cell is reused for the new content.
So there is not one cell for each row of your table view.
And if your table contains a lot data, there are far more rows than cells.
As Thyraz said, the UITableView only keeps cells for the visible rect -- and a reasonable buffer to allow for scrolling. Thats why 'reuse identifiers' are so very important, they indicate which cells can be used for which tables (critical when you have more than one table to worry about). Unfortunately, that doesn't answer your question by itself.
The responsibility for storing the contents of those textViews isn't on the UITableView's shoulders. It's your job to provide that data through the data source delegate protocols, and therefore you should be querying the data source for that information.
Edit: Which means that yes, you should be storing this data somewhere else, usually in the form of properties on the view controller class that contains the table view. I'd recommend the use of NSArray for the purpose, but you can also do it through dicts or even, at the last resort (and this is more a in theory you can do this, but it's an incredibly bad idea kind of thing), a series of properties. Personally, I almost always use NSArrays because they're structured in a manner appropriate to the problem, but you could theoretically do it other ways. (I've used a dict based structure exactly once, and that was a situation where my data was nested inside itself in a recursive structure)
UITableViewController doesn't keep cells around once off the screen. You can use the following pattern to get a previously used one as a memory management optimization, but you MUST assume that cells need to have the values reset on them every time they come onto the screen (even if dequeued) because there is no guarantee what the values will be.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if( cell == nil ) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier1] autorelease];
cell2.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell2.editingAccessoryType = UITableViewCellAccessoryNone;
}
switch( indexPath.section ) {
case first_Section:
if( row == 0 ) {
cell1.textLabel.text = #"Some Text";
cell1.accessoryView = [self myCustomViewControl];
cell = cell1;
}
... etc
}
}
i want change the content of a UITableView when i change a button, how i can do it?...i retrieve my information from Core Data, and when i press a button i want change the information in the tableview, i know the:
[self.tableview reloadData]
and in this way i give the information to the row:
NSManagedObject *name = [[self sortName] objectAtIndex:indexPath.row];
cell.textLabel.text = [[name valueForKey:#"firstName"] description]];
but my question is how i can give another array to my table view to retrieve information when i tap a button...i every where but i can't find an answer...
The information displayed in your table view cells are determined in the cellForRowAtIndexPath method.
In your code, it looks like this method references your array named sortName.
If you are retrieving your new data set into some other array, then you have to replace the contents of sortName with the contents of the new array.
Replace your sortName array with the new contents after pressing the button. Than call reloadData..!?