开发者

Problem updating UITableViewCells when rotating UITableView

开发者 https://www.devze.com 2023-01-15 14:07 出处:网络
I have a UILabel in a custom UITableViewCell that开发者_运维问答 gets resized when the device is rotated.The text in this label needs to be recalculated after the rotation because I am cutting it down

I have a UILabel in a custom UITableViewCell that开发者_运维问答 gets resized when the device is rotated. The text in this label needs to be recalculated after the rotation because I am cutting it down to size and appending some text at the end.

E.g. the datamodel has: "This is a run-on sentence that needs to stop."

In portrait mode it becomes "This is a run-on sent... more"

In landscape mode it becomes "This is a run-on sentence that... more"

From (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation I am able to access the visible UITableViewCells and update the descriptions.

The problem seems to be that there are UITableViewCells that are cached but I can't get to. When I scroll the UITableView after a rotation, one or two cells that are below the visible area after the rotation don't have the correct text in the label. So they haven't been rendered via (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - but they weren't returned by [tableView visibleCells] (or via looping through all views returned via [tableView subViews]).

I've tried to access the "extra" cells via this method:

for (int index=max + 1; index < max + 3 && index < [cellTypes count]; index++) {
    NSIndexPath *updatedPath = [NSIndexPath indexPathForRow:index inSection:0];
    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:updatedPath];
    if (cell == nil) { continue; }
    [self updateCellForRotate:cell forRow:index];
}

(where max is the biggest row returned from visibleCells) but cell is always nil.

Is there anyway to flush the cache of UITableViewCells so that they don't get re-used? Or to access them so I can update them?

Thanks!


Two things. First. In your didRotateFromInterfaceOrientation method you can simply reload the visible rows like so:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation) fromInterfaceOrientation
{
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];

    NSLog(@"didRotateFromInterfaceOrientation:%d",fromInterfaceOrientation);
    [tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}

Then I would recommend you add either the interfaceOrientation number or simply the table width to the dequeue cell name that way the tableView knows that cells in one rotation are different from those in another. Like so:

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath withType:(NSString *)s_type
{
    UITableViewCell *cell = nil;
    // add width of table to the name so that rotations will change the cell dequeue names
    s_cell = [s_cell stringByAppendingString:[NSString stringWithFormat:@"%@%d",@"Width",(int)tv.bounds.size.width]];

    NSLog(@"%@",s_cell);
    cell = [tv dequeueReusableCellWithIdentifier:s_cell];
    if( cell == nil ) { 
        cell = [[[UITableViewCell alloc];
        initWithFrame:CGRectZero reuseIdentifier:s_cell] autorelease];
    }
}


Firstly, to reload all of your table cells use [self.tableView reloadData]

Secondly, add the line of code that is responsible for the shrinking inside the (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method.

Example:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    //Some identifier and recycling stuff

    if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
        //Make labels smaller
    }
    else {
        //Make them bigger
    }
}

Or you can just call your updateCellForRotate:forRow: method when making them. But I'm not sure how that function works, so I can't be too specific.


When you create the cell in cellForRowAtIndexPath:, add it to an array. Then, loop through the array, updating the text as necessary.

Hope this helps,
jrtc27

EDIT:

You say they are custom cells - could you not update your text in your UITableViewCell subclass?


So, I was having (what I think was) a very similar problem recently, and none of the posted answers helped me, I'm sorry to say.

My issue was that I deliberately resized and repositioned the UITableView upon rotation, and I did that programatically. The table cells in portrait took up the width of the view, and in Landscape were made somewhat higher but less wide. I then repositioned the elements of the cell depending on the orientation we'd come to.

Upon application start, the first viewing of the table was fine. Then I rotated and found that I appeared to have two instances of some elements, and these appeared to be where the cells had been visible in the first table. Rotating back then corrupted the initial orientation table with elements from the previous table.

I tried all of the applicable answers above, until I looked closer at the cellForRowAtIndexPath code:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}

I understand cell re-use is a great idea and all, but I really didn't need to retain (as in preserve) any cells and wanted them all bright, spangly and new after each rotation.

EDIT: In my own app I'll have maybe 20-30 rows maximum, as I personally don't like hugely long tables. If there were going to be lots of rows returned for a particular query I'd have some filters available to the user to help them sort out which rows they wanted. If you're going to have loads of rows displayed, then dequeuing them may cause you a performance impact that you don't want.

All I did was comment out the if and the following bracket, and my table cells renewed exactly as I wanted them to:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//}

Apologies for the waffle, and the late answer to an old question.

Ben.

Waffles and cream, or syrup.


You can use this simple line on the shouldAutorotateToInterfaceOrientation method :

self.view.autoresizesSubviews = YES;

For me it works always successfully

0

精彩评论

暂无评论...
验证码 换一张
取 消