I'm modifying a table view cell during a call to tableView:cellForIndexPath
, but the modifications do not appear until the cell is scrolled off and then back on. I realize that I can modify the .xib file or can alloc/init a cell rather than calling dequeue
, but I'd like to understand what is going on.
The changes involve masking the cell to achieve rounded bottom corners. If I set the corner radius instead (i.e. cell.layer.cornerRadius = ...
), which rounds all the corners, I don't see the problem.
Update:
I didn't post the code initially because it was proprietary, involved a lot of complexity and I thought the question was a reasonable one in absence of any specifics. In light of the responses, though, here is a reduced fragment which exhibits the problem, with the only change being the actual cell identifier. I also updated the description/question to simplify the scenario.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TheCorrectCellIdentifier" forIndexPath:indexPath];
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(4., 4.)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = cell.bounds;
maskLayer.path = maskPath.CGPath;
cell.layer.masksToBounds = YES;
cell.layer.mask = maskLayer;
return cell;
}
Your code working fine . But if you still facing Corner radius issue in cellForRowAtIndexPath:
then try in willDisplayCell:
. I tried in both methods and working fine.
willDisplayCell:
Tells the delegate the table view is about to draw a cell for a particular row.
A table view sends this message to its delegate just before it uses cell to draw a row, thereby permitting the delegate to customize the cell object before it is displayed. This method gives the delegate a chance to override state-based properties set earlier by the table view, such as selection and background color. After the delegate returns, the table view sets only the alpha and frame properties, and then only when animating rows as they slide in or out. Here is my code.
According to me, Apple provide two different set of methods (Protocol) named UITableViewDataSource
and UITableViewDelegate
to manage UITableView.
UITableViewDataSource : Data source provides actual data for cell to fill in the details.
UITableViewDelegate : At the other end delegate is responsible for give information about visual layout of tableview and handles user interaction.
So, conclusion is that DataSource mainly deal with content(Data) of table and Delegate deal with presentation and interaction of tableview component.
Lets come to way we dealing with TableView.
We all are very personal with UITableViewDataSource method tableView:cellForRowAtIndexPath:
, This method is responsible for to create or reuse valid UITableViewCell with proper detailed information for each index path.What we tend to do cell layout configuration and UI modification in this method.
After tableView:cellForRowAtIndexPath:
is called, the system does a layout configuration, then calls tableView:willDisplayCell:forRowAtIndexPath:
method before cells display on screen.
So we can use this method for view configuration of Tableview cell(May be, Apple propose this method for us!!!).
So I persionally prefer to use tableView:cellForRowAtIndexPath:
to create cell and left cell UI configuration task for tableView:willDisplayCell:forRowAtIndexPath:
method.
Apply mask in willDisplayCell:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(10.0, 10.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = cell.bounds;
maskLayer.path = maskPath.CGPath;
cell.layer.masksToBounds = YES;
cell.layer.mask = maskLayer;
}
Here is my cellForRowAtIndexPath:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:@"Row : %ld ", (long)indexPath.section];
return cell;
}
Output :
Reload the tableView in viewDidAppear
or viewDidLayoutSubviews
method will make it to work.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView reloadData];
}
Reason why your code not worked:
Actually, as per view life cycle, the methods are called in following manner, init
,loadView
,viewDidLoad
,viewWillAppear
,viewWillLayoutSubviews
(called more than once),viewDidLayoutSubviews
(called multiple time) and lastlyviewDidAppear
.
Now, actually the tableview get loaded in method viewDidLoad
, whereas the autolayout constraints that you apply were going to be applied after that method. Thats why, it is not showing expected result. Reloading it again after autolayout constraints get applied make it work. Thats'why above code will surely work.
One more point to note: In storyboard if you have designed your viewController by using iphone 5 size and then if you run the code in iphone 5, then without reloading it, it must work, but if you run it in any other sized viewController, then it will not work. The reason behind it is, viewDidLoad
method get called, then any view have size that was in its storyboard.
If you have any doubts, let me know
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With