I have a cell. Whenever the text in cell row is equal to "(null)" I want the label to be on the right hand side of the the cell.
Here is my code at the moment, but it isn't doing anything. No errors, it just doesn't align to the right hand side of the cell. Any ideas?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"ChatListItem";
NSDictionary *itemAtIndex = (NSDictionary *)[messages objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if([[itemAtIndex objectForKey:#"user"] isEqualToString:#"(null)"]){
cell.textLabel.textAlignment=UITextAlignmentRight;
cell.detailTextLabel.textAlignment=UITextAlignmentRight;
}
cell.textLabel.text = [itemAtIndex objectForKey:#"text"];
cell.detailTextLabel.text = [itemAtIndex objectForKey:#"user"];
return cell;
}
First, did you step through the code and check the contents of the value for keys "user" and "text"?
If all is as expected, you should do the following:
Replace UITextAlignmentRight with NSTextAlignmentRight to silence compiler warnings.
Explicitly set NSTextAlignmentRight and NSTextAlignmentLeft, otherwise you will not get the correct update in recycled cells.
Finally, make sure the label's width is fixed. Otherwise, the width of the label will be based on its content, so that the alignment (within the label) loses its effect.
The only working solution for your case (without subclassing of the UITableViewCell of course)
is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ChatListItem";
NSDictionary *dict = [_tableData objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = dict[#"text"];
cell.detailTextLabel.text = dict[#"user"];
if ([dict[#"user"] isEqualToString:#"(null)"]) {
[self performSelector:#selector(alignText:) withObject:cell afterDelay:0.0];
}
return cell;
}
- (void)alignText:(UITableViewCell*)cell
{
CGRect frame = cell.textLabel.frame;
frame.origin.x = cell.frame.size.width - (frame.size.width + 10.0);
cell.textLabel.frame = frame;
frame = cell.detailTextLabel.frame;
frame.origin.x = cell.frame.size.width - (frame.size.width + 10.0);
cell.detailTextLabel.frame = frame;
[cell setNeedsDisplay];
}
As for me, I would better make a subclass.
Related
I have been struggling for 2 days with this problem.
I have a UIViewController with a UITableView on the storyboard.
But I want to reuse the design for a custom cell so I use an Xib file to design the cell.
The cells contains a label that gets the content at runtime so the height of it varies.
I am using autolayout I have all the constraints and set lines of my label as 0;
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.tableView.dataSource = self;
self.tableView.delegate = self;
[self.tableView registerNib:[UINib nibWithNibName:#"PostingTableViewCell" bundle: [NSBundle mainBundle]] forCellReuseIdentifier:#"PostingCell"];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PostingCell";
self.customCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (self.customCell == nil)
{
self.customCell = [[PostingTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *post = [self.posts objectAtIndex:indexPath.section];
NSString *contentString = [post objectForKey:#"content"];
self.customCell.contentLabel.text = contentString;
self.customCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(self.customCell.bounds));
[self.customCell setNeedsLayout];
[self.customCell layoutIfNeeded];
CGFloat height = [self.customCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
}
My code works when I put my custom cell on my tableViewController in the storyboard, but when I migrate it to the xib file, the height of the tableviewcell no longer adjusts.
here is a screen shot of my xib file and constraints
Here is my cellForRowAtIndexPath method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PostingCell";
PostingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *post = [self.posts objectAtIndex:indexPath.section];
NSString *contentString = [post objectForKey:#"content"];
cell.contentLabel.text = contentString;
}
Simulator Screenshot
When I hard code the height to 150 screenshot below:
I'm still not sure why you're doing any of this in heightForRowAtIndexPath
static NSString *CellIdentifier = #"PostingCell";
self.customCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (self.customCell == nil)
{
self.customCell = [[PostingTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Try this
1. Adjust the height of the cell in xib.
2. Try something like this
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return self.customCell.bounds.size.height;
}
I have a table. Table has 1 simple custom cell. There is only label in this cell.
Here is code of cellForRow function:
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.myLabel.text = [NSString stringWithFormat:#"%ld", (long)indexPath.row];
cell.myLabel.frame = CGRectOffset(cell.myLabel.frame, 0, -20);
cell.myLabel.backgroundColor = [UIColor redColor];
return cell;
Everything works fine except this:
cell.myLabel.frame = CGRectOffset(cell.myLabel.frame, 0, -20);
Label don't want to move!
I found this problem in iOS8.
Anybody help please :)
Ok, I found the answer here https://stackoverflow.com/a/13539782/1928161 :)
The trick is to add
cell.myLabel.translatesAutoresizingMaskIntoConstraints=YES;
in MyCell.m file add layoutSubviews method and change myLabel frame
- (void )layoutSubviews {
// always try to set frame in layoutSubviews
[super layoutSubviews];
self.myLabel.frame = CGRectOffset(self.myLabel.frame, 0, -20);
}
and please modify your code like this
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier;
cellIdentifier = #"Cell";
MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.myLabel.backgroundColor = [UIColor redColor];
}
cell.myLabel.text = [NSString stringWithFormat:#"%ld", (long)indexPath.row];
return cell;
}
I've got an UITableView with 30 objects.
Controller shows correctly first 13 rows, on 14th row use a "joker" row which changes his content scrolling, then start again with first thirteen row and "joker" row until the end.
That's code of cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: #"cell" forIndexPath:indexPath];
UIImageView * flagImageView = (UIImageView *) [self.view viewWithTag:1];
UILabel * nationLabel = (UILabel *) [self.view viewWithTag:2];
nationLabel.text = [_nationsArray objectAtIndex:indexPath.row];
nationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
NSLog(#"%i", indexPath.row);
return cell;
}
Strange thing is that configuring cell in if (cell == nil) { ... } it doesn't work...
The problem seems to be with the nationLabel. When I replaced
UILabel * nationLabel = (UILabel *) [self.view viewWithTag:2];
nationLabel.text = [_nationsArray objectAtIndex:indexPath.row];
with
cell.textLabel.text = [_nationsArray objectAtIndex:indexPath.row];
it's working fine (at least the text). So I think you should try to make a UITableViewCell subclass, make property for that label and see if it's ok then.
Don't use this
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: #"cell" forIndexPath:indexPath];
Change your code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: #"cell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
UIImageView * flagImageView = (UIImageView *) [self.view viewWithTag:1];
UILabel * nationLabel = (UILabel *) [self.view viewWithTag:2];
nationLabel.text = [_nationsArray objectAtIndex:indexPath.row];
nationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
NSLog(#"%i", indexPath.row);
return cell;
}
I'm having a bit of difficulty understanding what is going wrong and how to fix this.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
NSUInteger row = [indexPath row];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
UILabel *where = [[UILabel alloc] initWithFrame:CGRectMake(88.0, 0.0, 155.0, 22.0)];
where.text = [delegate.destinationArray1 objectAtIndex:row];
where.font = [UIFont fontWithName:#"Helvetica" size:12.0];
where.textColor = [UIColor blueColor];
[cell.contentView addSubview:where];
return cell;
}
This doesn't work properly but this does:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSUInteger row = [indexPath row];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
UILabel *where = [[UILabel alloc] initWithFrame:CGRectMake(88.0, 0.0, 155.0, 22.0)];
where.text = [delegate.destinationArray1 objectAtIndex:row];
where.font = [UIFont fontWithName:#"Helvetica" size:12.0];
where.textColor = [UIColor blueColor];
[cell.contentView addSubview:where];
return cell;
}
They both get populated by "delegate.destinationArray1" but when all the code is inside the curly braces of
if(cell == nil)
the list gets unordered and repeats cells and misses some out. I can't use the latter way as it creates a MASSIVE memory leak when scrolling.
Any ideas?
I did the exact same thing when I started using UITableViews. The reason for the memory leak is that in the second implementation (the one that works) you are actually creating every cell, every single time. Let me try to explain a bit more.
You never want to set content of a cell between the (cell == nil). The reason for this is the reuseIdentifier. If the table needs to display a new cell it will grab one and see if it has already been alloced/inited. If it has it will just use it. If that is the case the content will already be set in the cell you grabbed and you are not telling it to set it any differently.
between the (cell == nil) only create and establish the view. Not the content. All content should be set after. So then no matter what cell it grabs it can always set the content. So this is what you want:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell) // or (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
UILabel *where = [[UILabel alloc] initWithFrame:CGRectMake(88.0, 0.0, 155.0, 22.0)];
where.font = [UIFont fontWithName:#"Helvetica" size:12.0];
where.textColor = [UIColor blueColor];
where.tag = 1;
[cell addSubview:where];
}
NSUInteger row = indexPath.row;
UILabel *where = [cell viewWithTag:1];
where.text = [delegate.destinationArray1 objectAtIndex:row];
return cell;
}
I just coded this in StackoverFlow so sorry if there are any small syntax errors.
The cell object is reused or created by the first statement. After checking cell for nil and creating a cell, you must not create another cell.
So delete the line
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
which comes after
NSUInteger row = [indexPath row];
and you'll work with the correct cell object.
When the tableview reuses cells it is based on the CellIdentifier. The tableview doesn't care what attributes you've set on the cell. In the first case the reuse it happening and it recognizes a cell it can use but that cell has the wrong information on it.
What I do is subclass UITableViewCell and do all the work inside of that class. Here is a quick snippet
#implementation AlertCell
//Custom init method
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier withHeight:(float)height {
//Whatever you need to do
}
//Place the views
- (void)layoutSubviews {
}
//Custom Setter method
- (void)setAlert:(CWAlert *)incomingAlert withAssets:(NSDictionary *)assets {
}
#end
Then you do something like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier;
CWAlertCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[AlertCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier withHeight:[self convertAssetsLengthToCellHeight:assetsLength]];
UIView *selectedView = [[UIView alloc] init];
selectedView.backgroundColor = [UIColor colorWithHexString:#"F6F6F6"];
cell.selectedBackgroundView = selectedView;
}
NSDictionary *alertInfo = [AlertCell getNeededCellAssets:alert];
[cell setAlert:alert withAssets:alertInfo];
return cell;
}
I can show more code from the subclass if needed.
I am filling a UITableView table with nutrition facts. Each row includes the absolute amount of the nutrient as well as the percent daily value. I would like to align the amount to the left side of each row and the percent daily value to the right side so that the information looks neater and so that all of the values line up. Is there any way I can do this? Thanks!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"NutritionCell" forIndexPath:indexPath];
if(!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"NutritionCell"];
}
CGRect oldFrame = cell.frame;
cell.textLabel.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, tableView.frame.size.width/2, oldFrame.size.height);
cell.detailTextLabel.frame = CGRectMake(oldFrame.origin.x + tableView.frame.size.width/2, oldFrame.origin.y, tableView.frame.size.width/2, oldFrame.size.height);
cell.textLabel.text = [factamount objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [percentDV objectAtIndex:indexPath.row];
return cell;
}
You can also do this with UITableViewCellStyleValue1. Which automatically adds 2 labels to the cell:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"CELLID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if(!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID];
}
cell.textLabel.text = #"AMOUNT TEXT";
cell.detailTextLabel.text = #"PERCENT TEXT";
return cell;
}
You can use the following code,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"Left";
cell.detailTextLabel.text = #"Right";
return cell;
}
If you want to use multiple custom labels in cells(more than two), you can do that as well and add it as subview of cell.contentView and align using textAlignment property. You can set the frame for these labels to display in appropriate places.
In that case you need to do it as
myLabel1.textAlignment = NSTextAlignmentLeft;
myLabel2.textAlignment = NSTextAlignmentRight;