Reputation: 2830
I need to change the position of UIButton dynamically. I do this in cellForRowAtIndexPath:
. I alter the frame of the button in that method. The change is not displayed when the table is initially displayed. But when I scroll past the cells and come back to it, it gets displayed. Similarly, when I first scroll to cells not visible initially, there is no change. The change occurs when I scroll to it the second time.
I have tried setNeedsDisplay:
on both the custom button and the table view. I have done this even in willDisplayCell:forRowAtIndexPath:
. How do I solve this?
EDIT: I forgot to mention that I am loading the UITableViewCell from a nib file. Here is the code to resize the frame.
label1.text = //text from some source
label1.text = [label1.text stringByAppendingString:@" |"];
[label1 sizeToFit];
CGRect frameAfterResize=label1.frame;
float x=frameAfterResize.origin.x+frameAfterResize.size.width;
button.frame=CGRectMake(x+2, button.frame.origin.y, button.frame.size.width,button.frame.size.height);
Upvotes: 2
Views: 5813
Reputation: 19310
I had the same issue in which I was loading cell from a nib, but none of the above solutions completely worked for me. They solved the problem for few scenarios but not all of them.
Here is the solution which worked for all scenarios.
@implementation MyChannelCell
-(void)drawRect:(CGRect)rect
{
[super drawRect:rect];
//Calling from here fixed issue for first time cell load
[self alignCellViews];
}
-(void)layoutSubviews
{
[super layoutSubviews];
//Calling from here fixed issue for coming back to the tableview from other ViewConroller
[self alignCellViews];
}
/**
Method to change the layout and positions of sub-views
*/
-(void)alignCellViews
{
//Code to position sub-views
//self.lblSubscribers is an outlet from nib of type UILabel
[self.lblSubscribers setFrame:CGRectMake(140, 26, 36, 26)];
[self setNeedsDisplay];
}
@end
Upvotes: 3
Reputation: 3303
in cellForRowAtIndexPath: use this method to change frame and redraw cell
[cell setNewFrame:....];
it works fine for me
-(void)setNewFrame:(CGRect)newFrame
{
myButton.frame=newFrame;
[self setNeedsDisplay];
}
if you want to adjust button to text
-(void)setNewCaption:(NSString)newCaption
{
label1.text = newCaption
label1.text = [label1.text stringByAppendingString:@" |"];
// calculate new frame
myButton.frame=//new frame
[self setNeedsDiplay];
}
Upvotes: 1
Reputation: 39512
Make your own UITableViewCell subclass. Create and add the button to the cell's contentView in your init method, or create and add it lazily via an accessor property. Override layoutSubviews and postion the button as desired.
Something like this:
@implementation MyCustomCell
- (void) init
{
self = [super initWithStyle: UITableViewCellStyleDefault reuseIdentifier: nil];
if ( self != nil )
{
_myButton = [[UIButton buttonWithType: UIButtonTypeRoundedRect] retain];
[self.contentView addSubview: _myButton];
}
return self;
}
- (void) layoutSubviews
{
[super layoutSubviews];
// dynamic layout logic:
if ( ... )
{
_myButton.frame = CGRectMake( 10, 10, 100, 30 );
}
else
{
_myButton.frame = CGRectMake( 20, 10, 50, 30 );
}
}
Alternatively, you can attempt to do cell layout in - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
Upvotes: 6
Reputation: 166
When drawing UITableViews, table cells are re-used so there is only one instance of a UITableViewCell identified by the string passed to the dequeueReusableCellWithIdentifier:.
If you update the cell in the cellForRowAtIndexPath: method it will not have the effect you expect - each time you will be referring to the same cell (so each cell will have the button in the same position). Hence the problem you are seeing that scrolling makes the button change position.
The easiest thing to fix your problem is alter the code to stop re-using cells by creating a new cell each time in cellForRowAtIndexPath. Update the code like this:
// comment out this line
// cell = [tableView dequeueReusableCellWithIdentifier:identifier];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:nibName];
cell = [nib objectAtIndex:0];
Please note though that re-using cells is preferred for efficiency reasons (to save memory and reduce memory allocations).
Your ideal solution is to create a custom sub-class of UITableViewCell and update the postion of the UIButton in the layoutSubviews method.
Upvotes: 0
Reputation: 919
Have you tried reloading the table after changing the cell's frame by using
[self.tableView reloadData]
I think it should solve your problem.
Upvotes: 1
Reputation: 119242
If it doesn't display as required initially, but does after scrolling, then my guess is that you are altering the label position only when a cell is dequeued and not when it is originally loaded from the nib.
You havent given this part of your cellForRowAtIndexPath method so I can't give any more specific advice at this point, but either the code above is not being executed, or label1
is nil when a new cell is made (ie when the dequeue method returns nil and you load from the nib).
Upvotes: 0
Reputation: 17478
Call setNeedsDisplay
with your UITableViewCell
object.
[cell setNeedsDisplay];
in cellForRowAtIndexPath:
Upvotes: 0