UIScrollView in UITableView content problems - ios

I have a scrollview inside each cell in my tableview, although the pictures embed in my scrollview don't show up until i scroll the tableview up and down...
I have a custom class with a #property for the scrollview and the cell. I have my code for setting the scrollview in the cellForRowAtIndexPath: method. This should be called upon initial creation of the cells as well? Im confused.
How can I get rid of the problem and make the images appear at first when I start the app?
Related code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"CustomID";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
for (int i = 0; i < [imageArray count]; i++) {
CGRect frame;
frame.origin.x = cell.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = cell.scrollView.frame.size;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
[cell.scrollView addSubview:imageView];
}
cell.scrollView.contentSize = CGSizeMake(cell.scrollView.frame.size.width * [imageArray count], cell.scrollView.frame.size.height);
return cell;
}

This is not exactly related to your question but you will run into this issue too:
Don't forget that your cells will be reused. Upon reusage (lets say the user scrolls down, a cell is moved upwards off the screen and the next that appears on the bottom will be physically the instance of CustomCell that just disappeard and was reused.)
Therefore add:
for (UIView *aView in [NSArray arrayWithArray:cell.subviews]) {
[aView removeFromSuperview];
// if you don't arc then release them and take care of their subviews - if any.
}
before adding any new UIImageView.
(I thought there was a method for removing all subviews in one go but did not find it)

Related

Objective C - ImageView (custom checkmark) in UITableViewCell stops toggling after multiple cell selections

I've encountered some very strange behaviour with my tableViewCells in a simple list application (iOS).
This is the basic function of my working app :
TableView with 2 sections. First section (e.g. with 2 cells) is always visible. Second section can be shown/hidden with a custom button in the section header. I've created two classes (i.e. FirstSectionItem and SecondSectionItem) both with a boolean property "completed" and some other properties.
After compilations the app runs as expected. Tapping cells results in showing the checkmarks and tapping them again hides the checkmarks (=custom imageView). However after tapping some different cells (random order) or showing/hiding the second section the checkmark (ImageViews) tend to stay checked no matter how much I tap the cells. After a while every cell is checked and can't be unchecked but the boolean values still keep changing.
Here's part of the code:
#property NSMutableArray *sectionTitleArray;
#property NSMutableDictionary *sectionContentDict;
#property NSMutableArray *firstSectionItems;
#property NSMutableArray *secondSectionItems;
ViewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
if (!self.sectionTitleArray) {
self.sectionTitleArray = [NSMutableArray arrayWithObjects:#"section1", #"section2", nil];
}
self.firstSectionItems = [[NSMutableArray alloc] init];
self.secondSectionItems = [[NSMutableArray alloc] init];
[self loadInitialData];
self.sectionContentDict = [[NSMutableDictionary alloc] init];
self.arraySection1 = [[NSMutableArray alloc] init];
for (int i = 0; i < [self.firstSectionItems count]; i++)
{
FirstSectionItem *firstSectionItem = [self.firstSectionItem objectAtIndex:i];
[self.arraySection1 addObject:firstSectionItem.itemName];
}
self.arraySection2 = [[NSMutableArray alloc] init];
for (int i = 0; i < [self.secondSectionItems count]; i++)
{
SecondSectionItem *secondSectionItem = [self.secondSectionItems objectAtIndex:i];
[self.arrayFuture addObject:secondSectionItem.itemName];
}
[self.sectionContentDict setValue:self.arraySection1 forKey:[self.sectionTitleArray objectAtIndex:0]];
[self.sectionContentDict setValue:self.arraySection2 forKey:[self.sectionTitleArray objectAtIndex:1]];
}
CellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListPrototypeCell" forIndexPath:indexPath];
// ... cell content ...
NSArray *content = [self.sectionContentDict valueForKey:[self.sectionTitleArray objectAtIndex:indexPath.section]];
//... constraints ...
UIImage *checkmark = [UIImage imageNamed:#"checkmark.png"];
UIImage *noCheckmark = [UIImage imageNamed:#"transparent.png"];
UIImageView *imageView = [[UIImageView alloc] init];
if (indexPath.section==0){
FirstSectionItem *firstSectionItem = [self.firstSectionItems objectAtIndex:indexPath.row];
imageView.image = firstSectionItem.completed ? checkmark : noCheckmark;
}
if (indexPath.section==1){
if(self.sec2isTapped == YES){
SecondSectionItem *secondSectionItem = [self.secondSectionItems objectAtIndex:indexPath.row];
imageView.image = secondSectionItem.completed ? checkmark : noCheckmark;
}
}
[cell.contentView addSubview:imageView];
// ... more constraints
return cell;
}
didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
if (indexPath.section ==0){
FirstSectionItem *tappedItem = [self.firstSectionItems objectAtIndex:indexPath.row];
tappedItem.completed = !tappedItem.completed;
}
if (indexPath.section ==1){
SecondSectionItem *tappedItem = [self.secondSectionItems objectAtIndex:indexPath.row];
tappedItem.completed = !tappedItem.completed;
}
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
[tableView endUpdates];
}
I've tried multiple approaches but none of them seem to work. I can't figure out what the problem is.
(I am new to objective C so some parts might seem a bit devious).
Thanks in advance.
The problem is that you are initializing the UIImageView each time cellForRowAtIndexPath is running. But remember that that cells are reused so what you are doing is reusing a cell that has a checkmark and adding a new clear checkmark on top.
What you need to do is either:
Add the imageView in the storyboard, tag it, and user the tag to find it in the code
Subclass UITableViewCell and assign the correct image in there.
There are MANY articles of how to do both online.

Offset appears in image content when scrolling UITableView

I am getting some strange behaviour when scrolling a TableView of custom UITableView cells.
When the app first opens, the content is fine:
But if I scroll my view some offsets appear in the embedded UIImageViews:
I have removed all layout constraints, and the problem still occurs.
I am at loss for reasons why this happens; any help is welcomed!
Here's my cellForRowAtIndexPath code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *StrechCellIdentifier = #"StrechCell";
//Place regular strechable cells.
GFStrechCell *cell = [tableView dequeueReusableCellWithIdentifier:StrechCellIdentifier];
if (cell == nil) {
cell = (GFStrechCell*) [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:StrechCellIdentifier];
}
cell.nameLabel.text = #"Chez Julien";
cell.descriptionLabel.text = #"A yummy place!";
cell.descriptionLabel.hidden = YES;
[cell.restaurantImage setImage:[UIImage imageNamed:[NSString stringWithFormat:#"restaurant%i.png", (indexPath.row%5 + 1)]]];
if(indexPath.row % 2 == 0){
[cell.favoriteButton.imageView setImage:[UIImage imageNamed:#"favoriteButtonPressed.png"]];
} else {
[cell.favoriteButton.imageView setImage:[UIImage imageNamed:#"favoriteButton.png"]];
}
return cell;
}
GFStrechCell is just a simple subclass of call with elements pointing to IBOutlets in storyboard:
That's odd, try this out just to see if it works
Below:
[cell.restaurantImage setImage:[UIImage imageNamed:[NSString stringWithFormat:#"restaurant%i.png", (indexPath.row%5 + 1)]]];
Try adding:
CGRect restaurantImageFrame = cell.restaurantImage.frame;
restaurantImageFrame.origin = CGPointZero; //or whatever it should be
cell.restaurantImage.frame = restaurantImageFrame;
This will set the image's origin to (0,0).
Edit: you could also try adding the following line instead.
[cell.restaurantImage sizeToFit];

Improper functioning tableView data and recharging

-Hi, I have a problem with a tableview reloading data and what I want to do is that you put the selected cell in blue and change an image that is, the problem is that if I make the [self.mytableview reloadData] in the didselectedRow blue background disappears and if I do the image of the cell does not change, I'm a bit lost with this piece of code I give thanks
if (indexPath.row == _selectedRow) {
UIImageView *favView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"favIconSelected.png"]];
CGRect frame = favView.frame;
frame.origin.x = 294;
frame.origin.y = 7;
favView.frame = frame;
[cell.contentView addSubview:favView];
[favView release];
}
cell.selectedBackgroundView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:SELCETED_BGIMGCELL]]autorelease];
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Product *p = [_productList objectAtIndex:indexPath.row];
_selectedRow=indexPath.row;
[_delegate productWasSelected:p];
[self.myTableView reloadData];
}
You don't need to call reloadData at all. All you need to do is to update the cell that was selected.
In the didSelectRowAtIndexPath method you can get the cell directly by calling cellForRowAtIndexPath on the tableView. This will return the actual cell that's on display and you can directly set the image it's displaying.
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.imageView.image = ...;
Alternatively you could control the image display from your cell subclass if you provide it with both the normal and selected images when you configure each instance.

IOS: Custom UITableViewCell - Strange Behaviour after Scrolling

i have a TableView with custom table cells. I add programmatically borders at the bottom of each cell to keep the screendesign layout. Everything is fine, when the App loads the first time. But after scrolling (and scrolling back to the top) multiple border lines are displayed all over the screen.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ static NSString *CellIdentifier = #"CellProgramm";
ProgrammTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
...
if([object.cellMessageArray[1] isEqualToString:#"wrapper"] || [object.cellMessageArray[1] isEqualToString:#"keynote"] || [object.cellMessageArray[1] isEqualToString:#"break"]) {
UIImageView *lineSeparator = [[UIImageView alloc] initWithFrame:CGRectMake(0, cell.bounds.size.height, 1024, 5)];
lineSeparator.image = [UIImage imageNamed:[NSString stringWithFormat:#"blind.png" ]];
lineSeparator.backgroundColor = [UIColor whiteColor];
[cell.contentView addSubview:lineSeparator];
}
else if([object.cellMessageArray[1] isEqualToString:#"standard"]) {
UIImageView *lineSeparator = [[UIImageView alloc] initWithFrame:CGRectMake(60, cell.bounds.size.height+4, 1024, 1)];
lineSeparator.image = [UIImage imageNamed:[NSString stringWithFormat:#"blind.png" ]];
lineSeparator.backgroundColor = [UIColor pxColorWithHexValue:#"eeeeee"];
[cell.contentView addSubview:lineSeparator];
}
}
Has anyone an idea?
When you scroll a tableview, the cells are reused (dequeueReusableCellWithIdentifier) to optimize performance. In the code above, a lineSeparator image view is added to the cell each time the cellForRowAtIndexPath method is invoked. If the cell is used 5 times, it will have 5 image views added.
One way address this is to remove the lineSeparator image view from the cell before it is reused. This is typically done in the cell's prepareForReuse method.
In the cellForRowAtIndexPath, add a tag to the lineSeparator image view (e.g., lineSeparator.tag = 100;
In your cell's class, implement the prepareForReuse method. E.g.:
-(void)prepareForReuse{
UIView *lineSeparatorView = [self.contentView viewWithTag:100];
[lineSeparatorView removeFromSuperview];
}

UISwitch not shown in UITable

I have made a UITable with some data and I had include a UISwitch in, but it not shown in the table when its run.
in .h
#interface CalcViewController : UITableViewController {
IBOutlet UITableView *mainTableView;
NSMutableArray *courseMURArray;
NSMutableArray *switchStates;
}
and in .m
- (void)viewDidLoad
{
[super viewDidLoad];
switchStates = [[NSMutableArray alloc] init ];
int i = 0;
for (i = 0; i < 33; i++) {
[switchStates addObject:#"OFF"];
}
}
and in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
UISwitch *theSwitch = nil;
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
theSwitch = [[UISwitch alloc]initWithFrame:CGRectZero];
theSwitch.tag = 100;
CGRect frame = theSwitch.frame;
frame.origin.x = 230;
frame.origin.y = 8;
theSwitch.frame = frame;
[theSwitch addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:theSwitch];
}else{
theSwitch = [cell.contentView viewWithTag:100];
}
if ([[switchStates objectAtIndex:indexPath.row] isEqualToString:#"ON"]) {
theSwitch.on = YES;
}else{
theSwitch.on = NO;
}
return cell;
}
and this is selector method
-(void) switchChanged: (UISwitch *) sender{
UITableViewCell *theParentCell = [[ sender superview] superview];
NSIndexPath * indexPathOfSwitch = [mainTableView indexPathForCell:theParentCell];
if (sender.on) {
[switchStates replaceObjectAtIndex:indexPathOfSwitch.row withObject:#"ON"];
}else{
[switchStates replaceObjectAtIndex:indexPathOfSwitch.row withObject:#"OFF"];
}
}
every thing is ok with the data but its not with are there any problem?
When you set up the cell in cell for RowAtIndexPath, you're setting the frame to CGRectZero, a rect at position (0,0) with width = height = 0. You then reset the position, but you never reset the the width & height.
After your 2 frame.origin lines add:
frame.size.width = XX;
frame.size.height = YY;
or just use CGRectMake(X, Y, width, height) to make the frame.
In your cellForRowAtIndexPath, if the cell is nil, then you initialise the UISwitch and add it to the cell. What if the cell is not nil initially?
Let's say, UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"] returns a valid cell, then no switch will be created at all.
You may want to verify whether you have specified "Cell" as the identifier for the UITableViewCell in interface builder just in case.
Alternatively, move the code for initialising the UISwitch outside of the "if(cell==nil)". See if this solves your issue. The "if(cell==nil)" block is supposedly for initialising cell if dedequeueReusableCellWithIdentifier: returns nil.
Also, you are using a tag number of 100 for all switches and in the else block, you initialise theSwitch with contentView of tag 100. Which UISwitch should iOS assign to theSwitch if you have more than one switch? You might want to refer to my post on how to set tag numbers correctly.

Resources