Changing position of a UILabel for a custom UITableVIewCell - ios

Ok so i have been trying to fix a problem that i got for a couple of days now without success. Today i found a solution but not a FULL solution to my problem.
So this is the problem.
It starts like this, please note the alignment of the time labels(the ones to the left)
But after the table reloads for the second time OR when i switch tabs back and forth it THEN changes to what i want it to look like from the beginning. Like this.
This is the code that does this inside cellForRowAtIndexPath:
if ([gameInfoObject.GameTime isEqual: #"FT"] || ([gameInfoObject.GameTime rangeOfString:#":"].location != NSNotFound)) { // CHeck to see if its FT or string contains ":" then hide liveB
cell.liveButton.hidden = YES;
CGRect frame = cell.gameTimeLabel.frame;
frame.origin.x= 27; // move the label 10pts to the left since no image will be present
cell.gameTimeLabel.frame= frame;
I found a solution from this post Changing the position of custom UIButton in custom UITableViewCell but the problem is that it changes FOR ALL THE CELLS. As you can see i only need it to change for a few cells. Please help me what can i do im out of ideas...
EDIT 1 the whole code for cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"Cell";
GamesInfoTableViewCell *cell = (GamesInfoTableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
// Configure the cell...
GameInfo *gameInfoObject;
gameInfoObject =[gamesInfoArray objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.backgroundColor = TABLECOLOR;
cell.homeTeamLabel.textColor = TEXT;
cell.awayTeamLabel.textColor = TEXT;
cell.gameTimeLabel.textColor = TEXT;
cell.homeTeamLabel.text = gameInfoObject.HomeTeam;
cell.awayTeamLabel.text = gameInfoObject.AwayTeam;
cell.homeTeamScoreLabel.text = gameInfoObject.HomeScore;
cell.awayTeamScoreLabel.text = gameInfoObject.AwayScore;
cell.liveButton.image = [UIImage imageNamed:#"1675447.png"]; //Load the green image
if ([gameInfoObject.GameTime isEqual: #"FT"] || ([gameInfoObject.GameTime rangeOfString:#":"].location != NSNotFound)) { // CHeck to see if its FT or string contains ":" then hide liveB
cell.liveButton.hidden = YES;
CGRect frame = cell.gameTimeLabel.frame;
frame.origin.x= 27; // move the label 10pts to the left since no image will be present
cell.gameTimeLabel.frame= frame;
}
else
cell.liveButton.hidden = NO;
if (([gameInfoObject.GameTime rangeOfString:#":"].location != NSNotFound)) {
cell.accessoryType = FALSE;
cell.userInteractionEnabled = NO;
cell.homeTeamScoreLabel.hidden = YES;
cell.awayTeamScoreLabel.hidden = YES;
}
cell.gameTimeLabel.text = gameInfoObject.GameTime;
return cell;
}

Just check for the indexpath.row
if (indexpath.row == 2){
cell.liveButton.hidden = YES;
CGRect frame = cell.gameTimeLabel.frame;
frame.origin.x= 27; // move the label 10pts to the left since no image will be present
cell.gameTimeLabel.frame= frame;}
EDIT ---
Its still not 100% clear what exactly the problem is but heres a couple of things you could try.
Reset the layout in layoutSubviews [self.view setNeedsLayout];
Reload the data of the UITableView instance after the view loads initially.

Related

Scroll to the last two rows of table

when the table has more records than the screen let you see, and the user scroll to the bottom for the last records in the table, the last two rows are not accessible (just in iOS7, in iOS8 everything is fine). Once the user take the finger from screen, the table goes up, and the last two rows are hidden.
This is one of the method used for tableView but i dont know if this come from here:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if (selectionCategMsg == 0)
{
if ([self.tableauMsgReceived count] < 1) {
cell.textLabel.text = NSLocalizedString(#"noMessagesYet", nil); //#"No messages yet !";
}
else
{
cell.textLabel.text = [NSString stringWithFormat:#"%#", [self.tableauMsgReceived objectAtIndex:indexPath.row]];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
}
else
{
if ([self.tableauMsgSent count] < 1) {
cell.textLabel.text = NSLocalizedString(#"noReplyYet", nil);
}
else
{
cell.textLabel.text = [NSString stringWithUTF8String:[NSString stringWithFormat:#"%#", [self.tableauMsgSent objectAtIndex:indexPath.row]].UTF8String];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
}
[cell setAccessoryType:UITableViewCellAccessoryNone];
return cell;
}
Can someone give an advice ? Thank you.
THIS IS THE SOLUTION THAT I FOUND:
// -> SET TABLE FRAME
CGFloat sideMargin = 0;
CGFloat originX = sideMargin;
CGFloat topBottomMargin = 100;
CGFloat originY = topBottomMargin;
// Width based on view size
CGFloat sizeWidth = self.view.bounds.size.width);
// Height based on view size
CGFloat sizeHeight = (self.view.bounds.size.height - topBottomMargin);
self.myTableView.frame = CGRectMake(originX, originY, sizeWidth, sizeHeight);
// <- END SET tableView frame
UITableView has the method scrollToRowAtIndexPath:atScrollPosition:animated:. That method lets you scroll the table view so a given indexPath is visible. Is that what you're looking for?
EDIT:
#Daij-Djan's post is a good theory on what's wrong. If your table view goes off the screen then it will position the last couple of cells inside it's view, but that view won't be visible. You're going to need to do some debugging to figure out what's wrong. You might try setting the table view's layer's borderWidth to a non-zero value so you can see the bounds of the table view.
In your viewDidLoad, add code like this:
myTableView.layer.borderWidth = 1;
myTableView.layer.borderColor= [UIColor redColor].CGColor;
(Where you'd replace "myTableView" with the name of your table view instance variable or property.)
You'll have to import QuartzCore.h in order for the code above to compile:
#import <QuartzCore/QuartzCore.h>

UItableviewcell dequeueReusableCellWithIdentifier removeFromSuperview

This is probably a simple problem, but I haven't found the right solution yet, so I am hoping somebody can help.
I have a tableview from storyboard with a cell with three labels.
All labels are connected via IBOutlet and have correct constrains.
The issue is that I want to remove the second label based on data so the constraints are kept and the third label uses its lower constraints to move closer to the first label.
But when I run the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"GroupMaterialCell";
GroupMaterialCell *cell = (GroupMaterialCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
// get data and populate row
if([self.materialitems count] >= indexPath.row) {
Material *material = [self.materialitems objectAtIndex:indexPath.row];
cell.folder.text = [NSString stringWithFormat:#"%#: %#", NSLocalizedString(#"Folder", nil), material.folder];cell.name.text = material.name;;
cell.member.text = material.member_name;
cell.date.text = [material getDate];
cell.info.text = [NSString stringWithFormat:#"%#, %#", [material getType], [material getFilesize]];
if([material.folder length] <= 0) {
[cell.folder removeFromSuperview];
}
}
return cell;
}
The code works perfect until I scroll down and it reuses the cells.
Then the second label is "gone" (removeFromSuperview) and therefore not visible.
Is there a quick way to do this without creating the label in code (with constrainst) and add / remove it?
Hope it all makes sense, otherwise ask.
UPDATE
The solution is to hide to label and set the priorities on the constraints.
Create IBOutlet of the constraints you want to switch
Edit code with following.
if([material.folder length] <= 0) {
[cell.folder setHidden:YES];
cell.memberToFolder.priority = 500;
cell.memberToName.priority = 900;
} else {
[cell.folder setHidden:NO];
cell.memberToFolder.priority = 900;
cell.memberToName.priority = 500;
}
Do not remove any thing from cell just handle it with it's visibility
if([material.folder length] <= 0) {
//set frame if required
[cell.folder setHidden:true];
} else {
//set frame if required
[cell.folder setHidden:false];
}

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];

Multi-line UILabel

I've looked over older questions and tried all the suggestions, but still cannot seem to get a multi-line UILabel to work. I have a UITableView and the cell is created by tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *fieldValue = [self fieldValueAtIndexPath:indexPath];
NSString *fieldName = [self fieldNameAtIndexPath:indexPath];
NSString *title = [[self appDelegate] displayNameForFieldName:fieldName];
Field fieldCode = [[self appDelegate] fieldCodeForFieldName:fieldName];
DetailCell *cell = nil;
NSString *identifier = nil;
BOOL isNotes = [fieldName caseInsensitiveCompare:#"Notes"] == NSOrderedSame;
switch( isNotes ) {
case NO:
{
identifier = #"DetailCell";
cell = (DetailCell*)[tableView dequeueReusableCellWithIdentifier:identifier];
NSInteger rows = [self heightForText:fieldValue andFont:[self textFont] andWidth:cell.value.frame.size.width] / _oneRowSize.height;
cell.value.text = fieldValue;
cell.name.text = [title lowercaseString];
cell.name.numberOfLines = MAX( 1, rows );
cell.value.numberOfLines = cell.name.numberOfLines;
break;
}
case YES:
{
cell = (DetailCell *)[tableView dequeueReusableCellWithIdentifier:#"DetailCellNotes" forIndexPath:indexPath];
// cell = (DetailCell *)[tableView dequeueReusableCellWithIdentifier:#"DetailCellNotes"];
cell.value.text = #"This is a very long line of text which should take up several lines";
cell.name.text = [title lowercaseString];
cell.value.numberOfLines = 5; // No more than 5 lines of text
cell.value.backgroundColor = [UIColor purpleColor];
cell.value.lineBreakMode = NSLineBreakByWordWrapping;
cell.value.frame = CGRectMake(cell.value.frame.origin.x, cell.value.frame.origin.y, 180, 70);
[cell.value sizeThatFits:CGSizeMake(180., 70.)];
break;
}
}
cell.fieldName = fieldName;
return cell;
}
The height in the table view is defined like so
- (CGFloat) tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
NSString *fieldName = [self fieldNameAtIndexPath:indexPath];
CGFloat height = 0.0;
if([fieldName isEqualToString:#"Notes"])
{
height = 70.;
}
else if([fieldName isEqualToString:#"Image"])
{
height = 100.;
};
return height;
}
which makes the cell large enough to hold a 3-line label. However when the cell appears the label is only one line (shown by the background being purple).
The tableview uses prototype cells, and I've also tried to set it to numberOfLines=5 and WordWrapping, but that didn't change the effects either. I've also tried both of the commented out lines (though searches suggest that sizeToFit might actually reset numberOfLines to 1).
I wonder what I've missed. I can't see any other place where the it might be overridden.
Thanks.
You are calling dequeueReusableCellWithIdentifier: to create your cell. This is a mistake, because it means that the cell has not assumed its final size. It is much better to call dequeueReusableCellWithIdentifier:forIndexPath:. This means that the cell will actually have the height that you are giving it in heightForRowAtIndexPath:. You should then be able to set the height of the label successfully.

UILabel upon a few UITableViewCells

Am I able to create a UILabel that is layouted upon many UITableViewCells?
I'm trying to make something like (that is just one section of my UITableView, each section can have one or more rows):
---------------------------------------------
| Multi-lined label | row1 values |
| with some useless | row2 values |
| text | row3 values |
---------------------------------------------
I managed to create a UILabel (in the first row of a section) that is multi-lined and is not clipping to bounds. That works really well (it was a bit tricky to count each sections row heights, but doable) besides one case: when I'm scrolling UITableView from bottom to top - UITableView renders last row (without UILabel) so it has "no evidence" of having UILabel (because it is maintained in the first row of section). Can I force some kind of relayouting first cell in section? I tried reloadRowsAtIndexPaths:withRowAnimation: with first row in each section whenever I layouted not first cell in section but it gave me layouting errors that I really do not understand. Or maybe there is another idea to do so?
-- EDITED
To be clear: I have a custom UITableViewCell with an IB view, it has a few labels that each row consist of and a label named labelName that I want to be "multi-lined" along rows in that section. LabelName.text is empty for each row besides first one in each section.
I am adding somescreenshots:
Good screenshot - when I am scrolling to bottom I'm getting proper effect:
Bad screenshot - when I am scrolling up, UITableView renders last row of section firstly, and afterwards renders upper rows - that gives effect of cut label (because multi-line label is in the first row)
I am not sure if code here will add anything to question - it is rather simple and almost whole logic is in tableView:heightForRowAtIndexPath. I can only present how do I create custom UITableViewCell:
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[CustomTableViewCell reuseIdentifier]];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithOwner:self];
cell.clipsToBounds = NO;
cell.labelName.clipsToBounds = NO;
cell.contentView.superview.clipsToBounds = NO;
}
-- EDIT 2
Here is most of the code:
- (void) reloadData
{
NSUInteger index = 0;
for (NSDictionary *object in self.list) {
CGFloat height = [[object objectForKey:#"name"] sizeWithFont:self.labelFont constrainedToSize:self.labelSize].height;
[self.labelHeights addObject:NSNumberFloat(ceilf(height))];
index++;
}
[self.tableView reloadData];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *object = [self.list objectAtIndex:indexPath.section];
CGFloat height = [[self.labelHeights objectAtIndex:indexPath.section] floatValue];
NSUInteger count = [[object objectForKey:#"list"] count];
CGFloat cellHeight = 30.f;
if((indexPath.row + 1) == count){
cellHeight = MAX(8.f + height - 30.f * indexPath.row, 30.f);
}
return cellHeight;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.list count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[self.list objectAtIndex:section] objectForKey:#"list"] count];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *person = [self.list objectAtIndex:indexPath.section];
NSDictionary *object = [[person objectForKey:#"list"] objectAtIndex:indexPath.row];
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[CustomTableViewCell reuseIdentifier]];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithOwner:self];
cell.backgroundColor = [UIColor clearColor];
cell.userInteractionEnabled = NO;
cell.clipsToBounds = NO;
cell.labelName.clipsToBounds = NO;
[cell.contentView.superview setClipsToBounds:NO];
}
if(indexPath.row == 0){
cell.labelName.text = [person objectForKey:#"name"];
CGFloat height = [[self.labelHeights objectAtIndex:indexPath.section] floatValue];
cell.labelName.numberOfLines = (int)(height / self.fontSizeHeight);
cell.labelName.frame = CGRectChangeHeight(cell.labelName.frame, height);
}
else{
cell.labelName.text = #"";
}
CGFloat cellHeight = [self tableView:self.tableView heightForRowAtIndexPath:indexPath];
cell.borderTop.hidden = YES;
cell.borderBottom.hidden = YES;
cell.borderBottomSmall.hidden = NO;
if(indexPath.row == 0){
cell.borderTop.hidden = NO;
}
if(indexPath.row + 1 == [[person objectForKey:#"list"] count]){
cell.borderBottom.hidden = NO;
cell.borderBottom.frame = CGRectChangeY(cell.borderBottom.frame, cellHeight - 1.f);
cell.borderBottomSmall.hidden = YES;
}
cell.labelDate.text = [object objectForKey:#"date"];
cell.labelPremium.text = [[object objectForKey:#"premium"];
return cell;
}
-- PARTIAL ANSWER
I managed to create a hack, that makes multi-line UILabel visibile when scrolling bottom to up at some point:
- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
NSArray *cells = [self.tableView visibleCells];
UITableViewCell *cell = [cells objectAtIndex:0];
[cell.superview bringSubviewToFront:cell];
}
I noticed that the part of the UILabel is covered by a row thats below of the UILabels row and that hack makes it would be properly displayed. But it has a drawback, when scrolling slowly from bottom to top it generates a flicker when label is created (part of it should be visible before real creation of UILabel).
Up mentioned answers are not solutions, but "hacks".
In the cell == nil block should be only the initialization.
You should not add any subviews in cell in cellForRowAtIndexPath.
The reason is simple: I will reuse a cell with some labels already added and add a new label.
Either use the default cell.textLabel, either create a subclass for UITableViewCell, with a
-(void)setData:(dictionary or string)object;
and in implementation just set the proper data to proper UI controls.
Add/create controls either in init method in the subclass, or in IB/Storyboard.
Call the dictionary or string should be picked in correspondence to indexPath, so you will always get proper data for proper cell at proper indexPath.
Try This
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellId = #"cellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell==nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
}
for (UIView *subview in [cell.contentView subviews]) {
[subview removeFromSuperview];
}
/// your UI on cell goes here
return cell;
}

Resources