We have a Masterview where project data are shown. Each row is build from a Custom UITableViewCell with a XIB file. There is a button on each Cell.
We use the Button to explode cq. implode the project list (based on a hierarchy).
When doing so the image on the button needs to be changed.
This works fine when a button is clicked (a variable:show for all the projects is turned on/off depending on the collapse cq. explode situation, only projects are fetched where show = true) and the correct image is shown in every row.
Problem: but when one row is tapped or let's say: selected, then the image from the XIB file is reloaded.
In RootViewController:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Deselect the currently selected row according to the HIG
[tableView deselectRowAtIndexPath:indexPath animated:NO];
// Set the detail item in the detail view controller.
ProjEntity *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
[self selectProjEntity:selectedObject];
ProjectTableViewCell *selectedCell = (ProjectTableViewCell *)[[self tableView] cellForRowAtIndexPath:indexPath];
[selectedCell setCollapseImage:selectedObject];
[tableView reloadData];
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
In Cell: ProjectTableViewCell:
- (void) setCollapseImage:(ProjEntity *) projRow
{
UIImage* btImage;
if ([projRow.explode intValue] == 0)
{
if ([projRow.projLevel intValue] == 1)
{
btImage = [UIImage imageNamed:#"add-big.png"];
}
else
{
btImage = [UIImage imageNamed:#"plus.gif"];
}
}
else
{
if ([projRow.projLevel intValue] == 1)
{
btImage = [UIImage imageNamed:#"Minus_groenGroot.png"];
}
else
{
btImage = [UIImage imageNamed:#"min.gif"];
}
}
self.collapseButton.imageView.image = btImage;
}
So only when a row is selected the button's image does not update.
Related
EDIT: I should specify that this only happens when I attempt to use the UICollectionViewFlowLayout, not when I try to use a custom view. But either way nothing ever shows up on the CollectionView though it was working just fine before I converted from a TableView.)
So I've been trying to convert a UITableView that I had into a UICollectionView. So far so good. But when I try to run the app it gives me the error:
'the collection view's data source did not return a valid cell from -collectionView:cellForItemAtIndexPath: for index path {length = 2, path = 0 - 0}'
I checked all the similar questions and answers here... so in my viewDidLoad I have (tableView is actually a UICollectionView):
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
[self.tableView registerNib:placeCell
forCellWithReuseIdentifier:CellIdentifier];
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UICollectionView *)tableView numberOfItemsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [_entries count];
//return 5;
}
- (void)tableView:(UICollectionView *)tableView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.item == [_entries count]-1 && page > 1) {
NSLog(#"load more");
//add footer view loading
if (c_page == page) {
// _tableView.tableFooterView = nil;
}
else
{
c_page++;
[self loadPlace:c_page];
}
}
}
- (UICollectionViewCell *)tableView:(UICollectionView *)tableView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
PlaceCell *cell = (PlaceCell *)[tableView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
//cell = [cellLoader instantiateWithOwner:self options:nil];
NSArray *topLevelItems = [placeCell instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
Place *p = [_entries objectAtIndex:indexPath.row];
cell.placeName.text = p.PName;
NSLog (#"p:%#", p.PName")
cell.placeImg.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:p.PImage]]];
return cell;
}
I went into the xib of the UICollectionViewCell (PlaceCell) and made sure that "Cell" was the reuseidentifier. And I made sure that the datasource and delegate were connected to file's owner in the collectionView.
I also noticed that when I use a custom layout instead of the flow layout (like this one: https://github.com/ShadoFlameX/PhotoCollectionView/blob/master/CollectionViewTutorial/BHPhotoAlbumLayout.m ) it doesn't give me that error... but my collectionview still isn't populated.
So I'm wondering if there's some sort of log I can run or something I can do to figure out what's going wrong. Because I've tried all the solutions I've seen and it hasn't gotten me anywhere.
When you make a cell in a xib file you should register the xib, not the class. Also, when you register either the class or xib (or make the cell in the storyboard), you don't need an if (cell==nil) clause because your cell will never be nil when you dequeue it with dequeueReusableCellWithReuseIdentifier:forIndexPath:. You should delete that clause.
So the problem is: "Switched from UITableView to UICollectionView and no valid cell is being returned." It is really a two part answer. The crux of which is every instance of UITableView...
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, self.view.bounds.size.height-50)];
...you want to turn into "CollectionView"
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, self.view.bounds.size.height-50)];
Everything that's a "row":
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
...you'll want to turn into an "item."
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
Ultimately I had to delete the following section entirely:
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
//cell = [cellLoader instantiateWithOwner:self options:nil];
NSArray *topLevelItems = [placeCell instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
My best guess is that the Nib was being loaded twice and that Xcode was complaining that the data wasn't being loaded by the original. So getting rid of that second entry got my cells loaded and populated with data. Hope this helps someone.
I've spent some time writing an xcode application today. I'm using a UITableView with a seperate xib for the table view cell. All is working well besides one quirky thing. In my code I set my image on the table cell xib from an array. When i run the app I've found out that the image does not appear on the table cell until I click on the table cell. And when I click on a different cell, the image on my previously selected cell disappears.
Funny thing is that I set my label on the table cell xib exactly the same way however I don't get the issue with the label.
Here is my code. I would greatly appreciate some help.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = nil;
cell = [tbHealthCheck dequeueReusableCellWithIdentifier:#"CONTENT"]; //all the cells in this table are named content (identifier for all cells in table)
if (cell == nil){
[[NSBundle mainBundle] loadNibNamed:#"FirstViewTableCell" owner:self options:nil];
cell = tcHealthCheck;
tcHealthCheck = nil;
}
UILabel *l1 = (UILabel *) [cell viewWithTag:0];
[l1 setText:[healthCheckCategory objectAtIndex:indexPath.row]];
l1.font = [UIFont fontWithName:#"arial" size:14];
[l1 setTextColor:[UIColor blackColor]];
UIImageView *img1 = (UIImageView *) [cell viewWithTag:1];
NSString *status = [healthCheckStatus objectAtIndex:indexPath.row];
if ([status isEqualToString:#"RED"])
{
img1.image = [UIImage imageNamed:#"red-light-badge.png"];
}
else if ([status isEqualToString:#"YELLOW"])
{
img1.image = [UIImage imageNamed:#"yellow-light-badge.png"];
}
else if ([status isEqualToString:#"GREEN"])
{
img1.image = [UIImage imageNamed:#"green-light-badge.png"];
}
return cell;
}
Here is the problem: I have a table view, custom cells, and detail view. I have 10 rows in my table and when the user selects one of the rows, the detail view opens. How to set the detail view nav bar's title from the selected row of my table view? I have three classes - televisionList (my tableview), televisionCell (my cells in the table view) and televisionDetail (my detail view which opens when a row is selected). In my televisionCell I have declared the following label:
#property (weak, nonatomic) IBOutlet UILabel *tvLabel;
In my televisionList (the tableview) I have this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
televisionCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:#"televisionCell" owner:self options:nil];
for (id currentObject in objects)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (televisionCell *)currentObject;
break;
}
}
}
switch (indexPath.row)
{
case 0:
{
cell.imageView.image = bnt;
cell.tvLabel.text = #"БНТ 1";
cell.backgroundView.image = [UIImage imageNamed:#"lightbackgr.png"];
break;
}
case 1:
{
cell.imageView.image = btv;
cell.tvLabel.text = #"bTV";
cell.backgroundView.image = [UIImage imageNamed:#"background-cell.png"];
break;
}
case 2:
{
cell.imageView.image = novatv;
cell.tvLabel.text = #"Нова TV";
cell.backgroundView.image = [UIImage imageNamed:#"lightbackgr.png"];
break;
}
}
Now, I want to change my detail view title to be equal to cell.tvLabel.text when a row is selected. Where and how to do that? Thanks in advance!
As you wrote, you want to set the title, when the cell is selected, so the best way will be to use:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
televisionCell *cell=[tableView cellForRowAtIndexPath:indexPath];
details.title=cell.tvLabel.text;
}
However, you may consider introducing the model object to your app and keep them in some array(objects in the example below`. So the method would look like:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
YourObject* obj=[self.objects objectAtIndex:indexPath.row];
details.title=obj.stationName;
}
I am trying to connect a UITableViewController to a UIView using storyboards. I have a TabBarController that connects to a Navigation Controller that displays a UITableViewController, displaying a small array. I want to click on a row and that trigger a simple UIView with a label, still displayed in the UINavigationController so I can navigate back to the UITableViewController
I can get the UITableViewController to display OK, with the array, but I can't get the row to trigger when I select it.
This is my UITableViewController (AtoZController.m) file:
#import "AtoZController.h"
#import "StoreDetailsView.h"
#interface AtoZController ()
#end
#implementation AtoZController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = NSLocalizedString(#"A to Z", #"An A to Z List of Stores");
AtoZArray = [[NSMutableArray alloc] init];
[AtoZArray addObject:#"Apple"];
[AtoZArray addObject:#"Boots"];
[AtoZArray addObject:#"Topman"];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [AtoZArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSInteger row = [indexPath row];
cell.textLabel.text = [AtoZArray objectAtIndex:row];
return cell;
}
I have a segue connected, named storeDetailsSegue, from the UITableViewController to a UIView. I am attempting to use the prepareForSeque method to trigger the next view but have had no luck with the following code.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
StoreDetailsView *detail = [self detailForIndexPath:path];
[segue.destinationViewController setDetail:detail];
}
As it keeps saying there is an error as there is 'No visible #interface for "AtoZController declares the selector 'detailForIndexPath'". I may be doing something completely wrong as I have never used storyboards before. What I want is for a simple UIView to display a label that dynamically changes to display the row number that has been selected.
I don't know if the UITableViewController should infact be a UITableView but as I have never used segues or storyboards I have no idea what could be causing the problem.
Any advice at all would be greatly appreciated.
UPDATE:
So I managed to get the UIViewController to display but still can't get the label to update before I display the view.
I have a table view with 3 items, one of which I have behind a button. When the button is selected, I want to hide that button, revealing the item behind it. I am displaying the table row using a table view cell. When I select the one button to hide, scrolling through the table hides more buttons. The hiding of the button seems to hide a button based on some location within the viewable rows of the current view. I'm trying to hide the button on a specific row.
I can write to the NSLog whenever I hit the code to hide a button and I will only get there once, but as I scroll through the table, the hidden attribute for the button applies to other rows that come into view. If I select the button on row 53 I want only the button in row 53 hidden, not buttons on other rows in the 120 row table.
Has anyone ever done what I am trying to do? Any help I can get to figure out what is happening would be appreciated. Thanks.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ElementCellIdentifier = #"ElementCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ElementCellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ElementRowCell"
owner:self options:nil];
if ([nib count] > 0) {
cell = self.tvCell;
} else {
NSLog(#"failed to load ElementRowCell nib file!");
}
}
NSUInteger row = [indexPath row];
UILabel *atomic_number = (UILabel *)[cell.contentView viewWithTag:1];
atomic_number.text = [NSString stringWithFormat:#"%d",elements_table[row].atomic_number];
UILabel *element_name = (UILabel *)[cell.contentView viewWithTag:2];
element_name.text = [NSString stringWithCString:elements_table[row].element_name];
UILabel *element_symbol = (UILabel *)[cell.contentView viewWithTag:3];
element_symbol.text = [NSString stringWithCString:elements_table[row].element_symbol];
return cell;
}
- (IBAction)buttonPressed:(id)sender {
NSLog(#"Getting to buttonPressed from row button");
UIButton *pressedButton = (UIButton *)sender;
NSIndexPath *indexPath = [self.mainTableView indexPathForCell: (UITableViewCell *)[sender superview]];
pressedButton.hidden = TRUE;
}
Sorry.
Basically what's happening is you are hiding the instance of the button in that specific table view cell. The problem is when it gets dequeue'd for another row nothing is restoring it's state. And if you were to just restore it's state to visible then the rows you clicked would be forgotten. You will need to save the rows that have been clicked already to be able to properly restore state in tableView:cellForRowAtIndexPath:.
How I would handle this is declare an NSMutableSet *selectedIndexPaths;. And use this to store the rows I have selected. Then when the button is clicked add that indexPath to the set like so.
- (IBAction)buttonPressed:(UIButton *)button{
if (![button isKindOfClass:[UIButton class]]) return;
UIView *finder = button.superview;
while ((![finder isKindOfClass:[UITableViewCell class]]) && finder != nil) {
finder = finder.superview;
}
if (finder == nil) return;
UITableViewCell *myCell = (UITableViewCell *)finder;
NSIndexPath *indexPath = [self.mainTableView indexPathForCell:myCell];
[selectedIndexPaths addObject:indexPath];
button.hidden = TRUE;
NSLog(#"IndexPathRow %d",indexPath.row);
}
Now to properly restore state when scrolling in tableView:cellForRowAtIndexPath: use an if statement to set the button's hidden property, like so:
buttonPropertyName.hidden = ([selectedIndexPaths containsObject:indexPath]);