uitableviewcell disappears after rotating iOS device - ios

I am facing problem for UITableViewCell
What I am doing,
Having three table views on 3 different views of same view controller of iPad.
Among which,
on 1st tableview I have cell with content view button and text.
Text+button is showing well when the app loads first time.
But as soon as I rotate the device the button+text disappears.
What I am doing wrong.
Thanks in advance.
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
if (tableView.tag == 1005)
{
if (indexPath.row == 0)
{
circle = [CAShapeLayer layer];
// Make a circular shape
circularPath=[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 35, 35) cornerRadius:MAX(35, 35)];
circle.path = circularPath.CGPath;
// Configure the apperence of the circle
circle.fillColor = [UIColor blackColor].CGColor;
circle.strokeColor = [UIColor blackColor].CGColor;
circle.lineWidth = 0;
UIButton* cameraBtn = [[UIButton alloc] initWithFrame:CGRectMake(0,0, 35,35)];
cameraBtn.backgroundcolor = [UIColor redColor];
[cell.contentView addSubview: cameraBtn];
cameraBtn.layer.mask=circle;
UILabel *photoLbl = [[UILabel alloc]initWithFrame:CGRectMake(50, 0, 150, 30)];
photoLbl.backgroundColor = [UIColor clearColor];
photoLbl.font = [UIFont fontWithName:#"OpenSans" size:16];
photoLbl.text = #"Take photo";
[cell.contentView addSubview:photoLbl];
[photoLbl release];
[cameraBtn release];
cell.contentView.frame = cell.bounds;
cell.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
return cell;
}
I searched for all links on SO, but didn't get suitable solution.

Try upgrading your simulator , I had the same problem and it worked fine when I tested it in a real device.

Related

UITableViewCell with subviews is not working properly

I have UITableView in my iOS app and I want to add some subviews to cell. I do it by using
[cell.contentView addSubview:someView];
and it works well, but... When I scroll down, subviews are starting to hide from cells that are on top and when I scroll back to top, they wont appear again... What I'm doing wrong? Is there some solution please?
EDIT
Mainly, I'm talking about "detailtext" label, but I have those problems in more cases...
Here is whole code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell;
switch (indexPath.row) {
case 0:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
break;
default:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
break;
}
UIView *separatorLine = [[UIView alloc] init];
separatorLine.frame = CGRectMake(15.0f, 60 - 0.5f, cell.frame.size.width-15.0f, 0.5f);
separatorLine.tag = 4;
separatorLine.backgroundColor = [UIColor lightGrayColor];
cell.layer.masksToBounds = NO;
tableView.backgroundColor = [UIColor colorWithRed:33.0 / 255.0 green:157.0 / 255.0 blue:147.0 / 255.0 alpha:1.0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIView *row2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 200)];
UIView *profileBorder = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-50, 50, 102, 102)];
profileBorder.layer.borderColor = [UIColor whiteColor].CGColor;
profileBorder.layer.borderWidth = 5; //2
profileBorder.layer.cornerRadius = 50;
NZCircularImageView *profileImage = [[NZCircularImageView alloc] initWithFrame:CGRectMake(1,1, 100, 100)];
profileImage.image = profilePhoto;
profileImage.contentMode = UIViewContentModeScaleAspectFill;
UITapGestureRecognizer *showBigProfilePhoto = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showImage:)];
profileImage.userInteractionEnabled = YES;
[profileImage addGestureRecognizer:showBigProfilePhoto];
[profileBorder addSubview:profileImage];
UILabel *numberFeelings = [[UILabel alloc] initWithFrame:CGRectMake(10, 100-25, 100, 50)];
numberFeelings.text = [NSString stringWithFormat:#"%#\nFeelings", feelings];
numberFeelings.font = [UIFont boldSystemFontOfSize:16];
numberFeelings.textAlignment = NSTextAlignmentCenter;
numberFeelings.textColor = [UIColor whiteColor];
numberFeelings.numberOfLines = 0;
UILabel *numberFriends = [[UILabel alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2+60, 100-25, 100, 50)];
numberFriends.text = [NSString stringWithFormat:#"%#\nFollowers", friends];
numberFriends.font = [UIFont boldSystemFontOfSize:16];
numberFriends.textColor = [UIColor whiteColor];
numberFriends.numberOfLines = 0;
numberFriends.textAlignment = NSTextAlignmentCenter;
[row2 addSubview:profileBorder];
[row2 addSubview:numberFriends];
[row2 addSubview:numberFeelings];
int rectButtons = cell.frame.size.width-246;
UIImageView *graph = [[UIImageView alloc] initWithFrame:CGRectMake(rectButtons/2, -20, 82, 82)];
UIImageView *badgets = [[UIImageView alloc] initWithFrame:CGRectMake(rectButtons/2+82, -20, 82, 82)];
UIImageView *photos = [[UIImageView alloc] initWithFrame:CGRectMake(rectButtons/2+164, -20, 82, 82)];
graph.image = [UIImage imageNamed:#"graph.jpg"];
badgets.image = [UIImage imageNamed:#"badgets.jpg"];
photos.image = [UIImage imageNamed:#"photos.jpg"];
graph.userInteractionEnabled = YES;
badgets.userInteractionEnabled = YES;
photos.userInteractionEnabled = YES;
UITapGestureRecognizer *graphTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showGraph:)];
[graph addGestureRecognizer:graphTap];
NSArray *jmenoCasti = [name componentsSeparatedByString:#" "];
krestni = [jmenoCasti objectAtIndex:0];
int indexOfPost = indexPath.row-3;
NSMutableAttributedString *str;
int countFeeling;
int countString;
int countBeforeFeeling;
if (indexPath.row >=3) {
str = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"%# was %#", krestni, [naladyHim objectAtIndex:[[[posts objectAtIndex:indexOfPost] objectForKey:#"_feel"] integerValue]]]];
countFeeling = [[naladyHim objectAtIndex:[[[posts objectAtIndex:indexOfPost] objectForKey:#"_feel"] integerValue]] length];
countString = krestni.length+5+countFeeling;
countBeforeFeeling = countString-countFeeling+1;
int rangeStart = countBeforeFeeling-1;
int rangeStop = str.length-rangeStart;
NSLog(#"%i ... %i", countBeforeFeeling-1, countString-1);
[str addAttribute:NSFontAttributeName value: [UIFont fontWithName:#"Helvetica-Bold" size:16.0f] range:NSMakeRange(rangeStart, rangeStop)];
[str addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:32.0 / 255.0 green:147.0 / 255.0 blue:138.0 / 255.0 alpha:1.0] range:NSMakeRange(rangeStart, rangeStop)];
}
UILabel *mainText = [[UILabel alloc] initWithFrame:CGRectMake(15, 70, cell.frame.size.width-10, 20)];
mainText.attributedText = str;
UILabel *detailText;
if (!detailText) {
detailText = [[UILabel alloc] initWithFrame:CGRectMake(15, 90, cell.frame.size.width-10, 30)];
}
detailText.textColor = [UIColor grayColor];
detailText.font = [UIFont systemFontOfSize:13];
switch (indexPath.row) {
case 0:
cell.textLabel.textAlignment = NSTextAlignmentCenter;
cell.textLabel.text = name;
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.font = [UIFont systemFontOfSize:20];
cell.backgroundColor = [UIColor clearColor];
break;
case 1:
[cell.contentView addSubview:row2];
cell.backgroundColor = [UIColor clearColor];
break;
case 2:
cell.backgroundColor = [UIColor colorWithRed:236.0 / 255.0 green:235.0 / 255.0 blue:210.0 / 255.0 alpha:1.0];
[cell.contentView addSubview:graph];
[cell.contentView addSubview:badgets];
[cell.contentView addSubview:photos];
break;
default:
detailText.text = [[posts objectAtIndex:indexPath.row-3] objectForKey:#"_text"];
[cell.contentView addSubview:detailText];
cell.textLabel.attributedText = str;
cell.backgroundColor = [UIColor colorWithRed:236.0 / 255.0 green:235.0 / 255.0 blue:210.0 / 255.0 alpha:1.0];
break;
}
return cell; }
This is an easy way thats works for me:
for(UIView *subview in cell.contentView.subviews)
{
if([subview isKindOfClass: [UIView class]])
{
[subview removeFromSuperview];
}
}
You can use it at the begin of
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
In your tableView:cellForRowAtIndexPath:, you hide the info when you don't want it to be shown, but you don't explicitly unhide it for cells where it should be shown.
Look at the first two lines in that method: What you are - correctly - doing is reusing your cells, so when cells are scrolled out of view, they are removed from the UITableView and put into the reuse queue. Then, when cells should become visible, the TableView gets cells from that queue - or creates new ones if none are available.
This all goes very well, but after a while, cells with hidden info buttons are put on the queue. And then, some time later, those cells are reused - and sometimes for rows in which there should be info visible.
There are two solutions to this: You could either explicitly unhide the information for those rows where you want it to be shown, or you could use two different kinds of cell, one with hidden info, and one with visible info. You then give each of those cells a different identifier, and based on what row the cells are in, set the identifier before dequeuing/creating cells.
You should create a subclass of UITableViewCell for each different cell and add all your view related code that doesn't change depending on the data into an initialization method. Then create a method in each cell called something like configureWithData and pass in the data relevant to the cell. The creation of your attributed string and modification of label frames can occur in this configuration method.
It will dramatically reduce the clutter in your UITableViewController and is much better design wise. There is no real need for your view controller to know what your table cells look like.
Here is an example of what I am talking about:
-(void)awakeFromNib
{
if( self.accessoryType == UITableViewCellAccessoryDisclosureIndicator )
{
DTCustomColoredAccessory *accessory = [DTCustomColoredAccessory accessoryWithColor:[UIColor whiteColor]];
accessory.highlightedColor = [UIColor blackColor];
self.accessoryView = accessory;
}
}
-(void)configureCellWithObject:(id)inObject
{
TableDataModel *dataObject = (TableDataModel *)inObject;
self.titleLabel.text = dataObject.titleString;
self.subtitleLabel.text = dataObject.subtitleString;
self.accessibilityIdentifier = dataObject.accessIdString;
if( dataObject.imageUrlString != nil )
{
UIImage *iconImage = [UIImage imageNamed:dataObject.imageUrlString];
if( iconImage != nil )
{
NSInteger yOffset = [StaticTools centerYOffset:self.frame.size objectFrameSize:iconImage.size];
self.iconImageView.image = iconImage;
CGRect frame = self.iconImageView.frame;
frame.origin.y = yOffset;
frame.size = iconImage.size;
[self.iconImageView setFrame:frame];
}
else
{
[self.iconImageView loadImageFromUrl:dataObject.imageUrlString];
}
}
}

iOS switching between UIWebViews causing memory warning

Hi i have created a custom tab bar that hides and shows certain web views depending on which tab your on i'm currently loading all three web views on an operation queue then making them visable and invisable depending on the selected tab. problem is its so slow to load and scroll and i'm getting a recieved memory warning
heres what i have done so far
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSArray *subviews = [cell subviews];
for(UIView *subview in subviews) if([subview tag] == 4) [subview removeFromSuperview];
UIView *loadingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 800)];
UIView *sendingMessage = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
UIActivityIndicatorView *sendingSpinner = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(25, 15, 50, 50)];
UILabel *sendingLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 65, 100, 20)];
int sendingViewLeft = (loadingView.frame.size.width/2) - (sendingMessage.frame.size.width/2);
int sendingViewTop = 160 - (sendingMessage.frame.size.height/2);
loadingView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
sendingMessage.frame = CGRectMake(sendingViewLeft, sendingViewTop, sendingMessage.frame.size.width, sendingMessage.frame.size.height);
sendingMessage.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
sendingMessage.layer.cornerRadius = 10;
sendingSpinner.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
sendingLabel.textColor = [UIColor whiteColor];
sendingLabel.backgroundColor = [UIColor clearColor];
sendingLabel.text = #"Loading...";
sendingLabel.textAlignment = UITextAlignmentCenter;
sendingLabel.font = [UIFont boldSystemFontOfSize:12];
sendingLabel.shadowColor = [UIColor blackColor];
sendingLabel.shadowOffset = CGSizeMake(0, -1);
[sendingSpinner startAnimating];
[sendingMessage addSubview:sendingLabel];
[sendingMessage addSubview:sendingSpinner];
[loadingView addSubview:sendingMessage];
[loadingView setTag:4];
cell.textLabel.text = #"";
if([self.webViewStatus isEqualToString:#"FALSE"]){
[cell addSubview:loadingView];
self.tableView.userInteractionEnabled = NO;
} else {
[cell addSubview:self.fixturesWebView];
[cell addSubview:self.resultsWebView];
[cell addSubview:self.tablesWebView];
self.tableView.userInteractionEnabled = YES;
}
if(self.selectedTabNumber == 1){
self.fixturesWebView.alpha = 1;
self.resultsWebView.alpha = 0;
self.tablesWebView.alpha = 0;
}
if(self.selectedTabNumber == 2){
self.fixturesWebView.alpha = 0;
self.resultsWebView.alpha = 1;
self.tablesWebView.alpha = 0;
}
if(self.selectedTabNumber == 3){
self.fixturesWebView.alpha = 0;
self.resultsWebView.alpha = 0;
self.tablesWebView.alpha = 1;
}
return cell;
}
First off, you should consider creating a custom cell rather than creating it at the tableview datasource. Second, when you are getting the webview content, consider using Asynchronous calls to avoid lock ups. This could be done in a block too. If you write delegate methods on the custom cell, you can let the tableview know when things are loaded or not etc.
But it looks like you are making it do too much work when the tableview needs to draw a cell.

iOS how to add UIView to tableview cell effectively

I have a table going where each cell has a UIView in it that is fed from an XMLParser feed. If I leave it how it is, each time I refresh the views build upon each other because they are not getting released/removed, which makes total sense. How would I go about writing my code to avoid that problem, and not having to rebuild the view's each time I refresh. I am stuck in the logic of it and also the actual syntax. Thanks.
Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
JointCAD *currentCall = [[xmlParser calls] objectAtIndex:indexPath.row];
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"texture.png"]];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIView *selectionView = [[UIView alloc] initWithFrame:CGRectMake(10, 7, 200, 65)];
[selectionView setBackgroundColor: [UIColor clearColor]];
cell.selectedBackgroundView = selectionView;
}
// Display content in each cell
cellSeparator = [[UIView alloc] initWithFrame:CGRectMake(10, 7, 300, 65)];
[cellSeparator setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleWidth];
[cellSeparator setContentMode:UIViewContentModeTopLeft];
[cellSeparator setBackgroundColor: [UIColor colorWithRed:240.0/255.0 green:240.0/255.0 blue:240.0/255.0 alpha:1.0]];
cellSeparator.layer.borderWidth = 1.0;
cellSeparator.layer.borderColor = [UIColor blackColor].CGColor;
[cell addSubview:cellSeparator];
callTypeLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 2, 190, 21)];
callTypeLabel.text = [currentCall currentCallType];
callTypeLabel.backgroundColor = [UIColor clearColor];
callTypeLabel.font = [UIFont boldSystemFontOfSize:12.0];
[cellSeparator addSubview:callTypeLabel];
locationLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 17 , 190, 15)];
locationLabel.text = [currentCall location];
locationLabel.backgroundColor = [UIColor clearColor];
locationLabel.font = [UIFont systemFontOfSize:10.0];
[cellSeparator addSubview:locationLabel];
unitsLabel = [[UILabel alloc]initWithFrame:CGRectMake(4, 43, 190, 21)];
unitsLabel.text = [currentCall units];
unitsLabel.backgroundColor = [UIColor clearColor];
unitsLabel.font = [UIFont italicSystemFontOfSize:10.0];
[cellSeparator addSubview:unitsLabel];
stationLabel = [[UILabel alloc]initWithFrame:CGRectMake(195 , 25, 75, 20)];
NSString *station = [#"Station: " stringByAppendingString:currentCall.station];
stationLabel.text = station;
stationLabel.backgroundColor = [UIColor clearColor];
stationLabel.font = [UIFont boldSystemFontOfSize:11.0];
[cellSeparator addSubview:stationLabel];
if ([currentCall.county isEqualToString:#"W"]) {
UIImage *countyImage = [UIImage imageNamed:#"blue.png"];
CGRect countyImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageLabel = [[UIImageView alloc] initWithFrame:countyImageFrame];
countyImageLabel.image = countyImage;
[cellSeparator addSubview:countyImageLabel];
} else {
UIImage *countyImage = [UIImage imageNamed:#"green.png"];
CGRect countyImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageLabel = [[UIImageView alloc] initWithFrame:countyImageFrame];
countyImageLabel.image = countyImage;
[cellSeparator addSubview:countyImageLabel];
}
if ([currentCall.callType isEqualToString:#"F"]) {
UIImage *callTypeImage = [UIImage imageNamed:#"red.png"];
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageLabel = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageLabel.image = callTypeImage;
[cellSeparator addSubview:callTypeImageLabel];
} else {
UIImage *callTypeImage = [UIImage imageNamed:#"yellow.png"];
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageLabel = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageLabel.image = callTypeImage;
[cellSeparator addSubview:callTypeImageLabel];
}
return cell;
}
If I understand your question correctly, I think the solution you want is to subclass UITableViewCell, set up your subviews (UIImageViews and all that) and make them properties on your subclass. Then you can
if (!cell.imageView) {
cell.imageView = [[UIImageView alloc] initWithFrame:myFrame];
}
then just set the image. That way you're sure to not stack image views on top of one another and the correct image will get set when the cell is dequeued.
EDIT:
Make a class called MyTableViewCell (or whatever you want to call it but make sure it's a subclass of UITableViewCell)
Add #property (strong, nonatomic) UIImageView *imageView;
Then use MyTableViewCell instead of UITableViewCell in you cellForRowAtIndexPath and you can access the image property of your custom table view cell, check if it exists, if not create it (which is what the above code does) and then set the image. I would give you code but I'm on my phone. Google subclassing UITableviewCell. You should find a ton of examples.

iOS GCD use for a UITableView

I have a pretty intensive UITableView that needs to be optimized a little. The question is, how to use grand central station to do it effectively. Each cell has a UIView with a couple labels and two images. I have subclassed the TableViewCell and the view's are being reused though it is still a little laggy when the table gets bigger. How would I go about using GCD to optimize the table? OR is there a better way around it? I am not very strong in thread management and looking for some advice.
Here is the code to my tableview:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
JointCAD *currentCall = [[xmlParser calls] objectAtIndex:indexPath.row];
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"texture3.png"]];
TableViewCell *cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.callTypeLabel.text = currentCall.currentCallType;
cell.locationLabel.text = currentCall.location;
cell.unitsLabel.text = currentCall.units;
cell.stationLabel.text = [#"Station: " stringByAppendingString:currentCall.station];
cell.selectedBackgroundView = cell.selectionView;
if ([currentCall.callType isEqualToString:#"F"]) {
cell.imageType = Fire;
}
else {
cell.imageType = EMS;
}
if ([currentCall.county isEqualToString:#"W"]) {
cell.imageType1 = Washington;
}
else {
cell.imageType1 = Clackamas;
}
return cell;
}
Here is the subclassed tableviewcell:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
callView = [[UIView alloc] initWithFrame:CGRectMake(7.5, 7, 305, 65)];
[callView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleWidth];
[callView setContentMode:UIViewContentModeTopLeft];
[callView setBackgroundColor: [UIColor colorWithRed:240.0/255.0 green:240.0/255.0 blue:240.0/255.0 alpha:1.0]];
callView.layer.borderWidth = 1.0;
callView.layer.borderColor = [UIColor colorWithRed:(0/255.0) green:(0/255.0) blue:(0/255.0) alpha:1.0].CGColor;
[self.contentView addSubview:callView];
callTypeLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 2, 190, 21)];
callTypeLabel.font = [UIFont boldSystemFontOfSize:12.0];
callTypeLabel.textColor = [UIColor blackColor];
callTypeLabel.backgroundColor = [UIColor clearColor];
callTypeLabel.highlightedTextColor = [UIColor whiteColor];
callTypeLabel.adjustsFontSizeToFitWidth = YES;
[callView addSubview:callTypeLabel];
locationLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 17 , 190, 15)];
locationLabel.font = [UIFont systemFontOfSize:10.0];
locationLabel.textColor = [UIColor blackColor];
locationLabel.backgroundColor = [UIColor clearColor];
locationLabel.highlightedTextColor = [UIColor whiteColor];
locationLabel.adjustsFontSizeToFitWidth = YES;
[callView addSubview:locationLabel];
unitsLabel = [[UILabel alloc]initWithFrame:CGRectMake(4, 43, 190, 21)];
unitsLabel.font = [UIFont systemFontOfSize:10.0];
unitsLabel.textColor = [UIColor blackColor];
unitsLabel.backgroundColor = [UIColor clearColor];
unitsLabel.highlightedTextColor = [UIColor whiteColor];
unitsLabel.adjustsFontSizeToFitWidth = NO;
[callView addSubview:unitsLabel];
stationLabel = [[UILabel alloc]initWithFrame:CGRectMake(195 , 25, 75, 20)];
stationLabel.font = [UIFont systemFontOfSize:12.0];
stationLabel.textColor = [UIColor blackColor];
stationLabel.backgroundColor = [UIColor clearColor];
stationLabel.highlightedTextColor = [UIColor whiteColor];
stationLabel.adjustsFontSizeToFitWidth = YES;
[callView addSubview:stationLabel];
CGRect countyImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:countyImageFrame];
countyImageView.image = countyImage;
[callView addSubview:countyImageView];
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = callTypeImage;
[callView addSubview:callTypeImageView];
selectionView = [[UIView alloc] initWithFrame:CGRectMake(10, 7, 200, 65)];
[selectionView setBackgroundColor: [UIColor clearColor]];
}
return self;
}
- (void)setImageType:(CallType)newImageType {
imageType = newImageType;
if (imageType == Fire) {
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = [UIImage imageNamed:#"red.png"];
[callView addSubview:callTypeImageView];
}
else if (imageType == EMS) {
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = [UIImage imageNamed:#"yellow.png"];
[callView addSubview:callTypeImageView];
}
}
- (void)setImageType1:(County)newImageType1 {
imageType1 = newImageType1;
if (imageType1 == Washington) {
CGRect callTypeImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
countyImageView.image = [UIImage imageNamed:#"blue.png"];
[callView addSubview:countyImageView];
}
else if (imageType1 == Clackamas) {
CGRect callTypeImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
countyImageView.image = [UIImage imageNamed:#"green.png"];
[callView addSubview:countyImageView];
}
}
This is a little subtle, but the main area your code will hang on is in the setImageType: method.
You're adding a programmatically created Image View into your view hierarchy here:
UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = [UIImage imageNamed:#"red.png"];
[callView addSubview:callTypeImageView];
But you never actually remove the old image view. A better way to do this might be to cache the created image view in a property of the cell, then when you set the image type, send the message -[UIView removeFromSuperview] to the old image view before creating a new one.
As your code stands now, every time a cell is dequeued, a new image view is added to it, so every time the user scrolls up and down the table view, a new image view is created and added to the cell. It won't take long for there to be dozens of image views in each cell. I suspect this is causing many times more drawRect calls into image views than is actually necessary to achieve your purpose.
A better way of doing this would be to have both types of image views as properties that you create in the cell's init method, which are only configured in the setType methods. That way you only create one image view per type, and simply set configure its image in the appropriate setType method. Doing it this way, do bear in mind that removeFromSuperview will release the imageview, so you'll have to declare it as a strong property (assuming you're using ARC).
I appreciate neither of these solutions has anything to do with Grand Central Dispatch, but hopefully that should solve your problem without using a sledgehammer to crack a nut :).

UIView frame not updating size on time for creating scrolling text animation in UILabel

I'm doing the usual "add your own labels/images to cell.contentview" from within a controller's cellForRowAtIndexPath. And I'm trying to have one of the labels have animated scrolling text: that is, if the text in the label is overflows the viewCell width, the label in the cell should scroll the text (animated - not manual). Also, this whole tableview + scrolling text should work for both iPhone and iPad (so everything needs to autoresize accordingly).
Cutting to the chase, the question is:
How do I get a a subview of cell.contentView to update it's frame size on time for testing if the text inside this subview overflows or not.
Or perhaps, is this even the right way to go about it?
Here's an image of what I mean (secondLabel,etc are explained below):
Now you can keep reading for the details:
The way I tried going about it is having cellForRowAtIndexPath add a custom UISCrollLabelView instance to a cell's contentView. Where this custom class is really a UIView that manages internally a UILabel.
UISCrollLabelView should autoresize to it doesn't overflow the table cell (should work for both iPhone and iPad). And then, depending on the length of the text passed in to it by cellForRowAtIndexPath, it should autoresize its internal label to fit all the text and if the label ends up overflowing the view (self), animate the scrolling of the UILabel.
I have a couple problems with this, but the main one being: UIScrollableView triggers (or not) the animation based on comparing its internal label's frame.size.width with self.frame.size.width. But apparently, it takes some time for self's frame width to update from 0 to the size it ends up resizing to after inserted in the cell.contenView. Which means that when my custom UIScrollLabelView tests (label.frame.size.width > self.frame.size.width) this is always true and text that does not overflow still scrolls. A second or so later, self.frame does update to the correct size.
Here's cellForRowAtIndexPath (secondLabel is the scrollView here):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UIImageSmartView *cachedImage;
UILabel *mainLabel;
UIScrollLabelView *secondLabel;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
mainLabel = [[[UILabel alloc] initWithFrame:CGRectMake(70, 0, 0, 20)] autorelease];
mainLabel.font = [UIFont boldSystemFontOfSize:18];
mainLabel.textAlignment = UITextAlignmentLeft;
mainLabel.textColor = [UIColor blackColor];
mainLabel.backgroundColor = [UIColor clearColor];
mainLabel.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin);
mainLabel.tag = MAINLABEL_TAG;
secondLabel = [[[UIScrollLabelView alloc] initWithFrame:CGRectMake(70, 40, 0, 20)] autorelease];
secondLabel.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin);
//secondLabel.backgroundColor = [UIColor clearColor];
secondLabel.tag = SECONDLABEL_TAG;
cachedImage = [[UIImageSmartView alloc] initWithFrame:CGRectMake(5, 5, 57, 80)];
cachedImage.tag = PHOTO_TAG;
[cell.contentView addSubview:cachedImage];
[cell.contentView addSubview:mainLabel];
[cell.contentView addSubview:secondLabel];
}
else
{
cachedImage = (UIImageSmartView*)[cell.contentView viewWithTag:PHOTO_TAG];
mainLabel = (UILabel*)[cell.contentView viewWithTag:MAINLABEL_TAG];
secondLabel = (UIScrollLabelView*)[cell.contentView viewWithTag:SECONDLABEL_TAG];
}
// Configure the cell...
NSString *ImageName = [[dbData objectAtIndex:indexPath.row] objectAtIndex:2];
NSString *imageURL = [NSString stringWithFormat:#"http://someserver", referencingTable];
[cachedImage loadAndCacheImageFromFile:ImageName fromURL:imageURL inSize:CGSizeMake(57, 80) withBorderWidth:4];
mainLabel.text = [[dbData objectAtIndex:indexPath.row] objectAtIndex:0];
// -> At this point I load the text into the "scrolling label"
// (actually a UIView with a label)
[secondLabel setScrollingText:[[dbData objectAtIndex:indexPath.row] objectAtIndex:1]];
return cell;
}
And my UIScrollLabelView implementation looks like this so far:
#implementation UIScrollLabelView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
isScrolling = NO;
self.clipsToBounds = YES;
UILabel *label = [[[UILabel alloc] init] autorelease];
label.font = [UIFont systemFontOfSize:14.0];
label.textAlignment = UITextAlignmentLeft;
label.textColor = [UIColor darkGrayColor];
label.backgroundColor = [UIColor greenColor];
self.backgroundColor = [UIColor redColor];
//label.backgroundColor = [UIColor clearColor];
[self addSubview: label];
}
return self;
}
- (void)setScrollingText:(NSString*)text
{
[self setNeedsLayout];
UILabel *label = [[self subviews ] objectAtIndex:0];
label.text = text;
[label sizeToFit];
if(label.frame.size.width > self.frame.size.width)
[self scrollText];
}
- (void)scrollText
{
if(isScrolling)
return;
isScrolling = YES;
UILabel *label = [[self subviews ] objectAtIndex:0];
[UIView beginAnimations:#"scroll" context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDidStopSelector:#selector(scrollDidComplete)];
[UIView setAnimationDuration: label.frame.size.width/(float)100];
CGRect frame = label.frame;
if(frame.origin.x == 0)
frame.origin.x = frame.origin.x - (frame.size.width - self.frame.size.width);
else
frame.origin.x = 0;
label.frame = frame;
[UIView commitAnimations];
}
- (void)scrollDidComplete
{
isScrolling = NO;
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(scrollText) userInfo:nil repeats:NO];
}
#end
You are setting the label size when the size of the cell is not defined, yet. And then you never check for the actual size again.
You need to override setFrame and setBounds to catch frame size changes.

Resources