0
votes

As a little background, im building a rotated UITableView as a sort of sideways "picker" view. To do this, im taking a UITableView, appling a rotation transform to it, and then rotating again the UITableViewCells inside the tableview.

The problem im having is that some of the table cells become "misaligned" - their frame gets drawn at a certain distant offset (in both the x and y dimension) from the other table cells.

I've narrowed down that this bug occurs on the first table cell completely out of the visible tableview rect after a [tableView reloadData] call is made. (i.e. if I have 4 table cells, A which is completely visible and drawn, B which is half on/half off the view, and C and D which are completely off the screen and not yet rendered, when i scroll to C it is bugged, but when i scroll to D, it is not).

Now for some code -

the containing view's init

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        ...
        self.tableView = [[UITableView alloc] init];
        [self addSubview:_tableView];
        [_tableView setDelegate:self];
        [_tableView setShowsVerticalScrollIndicator:NO];
        [_tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
        CGAffineTransform transform = CGAffineTransformMakeRotation(-1.5707963);    
        _tableView.transform = transform;
        _tableView.frame = self.bounds;
        ...
    }
    return self;
}

the relevant delegate methods

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    return [tableView.dataSource tableView:tableView cellForRowAtIndexPath:indexPath].frame.size.height;
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{ 
    CGAffineTransform transform = CGAffineTransformMakeRotation(1.5707963);
    cell.transform = transform;
}

the table cell's layoutSubviews
edit: I manually set the size of the cell (mainly the width) based on the length on the content of the cell

- (void)layoutSubviews {
    [super layoutSubviews];

    // some calculations and sizing of subviews

    // height and width are swapped here, because the table cell will be rotated.
    self.frame = (CGRect){self.frame.origin.x,self.frame.origin.y,calculatedHeight,calculatedWidth};
}

It would seem that the bugged tablecell's frame.origin is set incorrectly when it reaches layout subviews. Setting the frame's origin.x value to 0 fixes the x dimension offset problem, but obviously I can't do the same for the y dimension because this value determines the cell's position in the tableview.

Please let me know if there's some crucial info I might be leaving out. Thanks!

3

3 Answers

0
votes

Have you tried to set the anchor point of the cells layer, which is the point the layer is rotated (transformed) about. It defaults to .5, .5 which is the centre of the layer, it may need to be set to 0, 0 (or 1, 1 - i can't remember if the layer coordinates are inverted off the top of my head)

or try setting the frame in willDisplayCell immediately after applying the transform instead of doing it in layout subviews

0
votes

Good news - after spending many many previous hours trying to figure this out, I just stumbled upon the solution.

This code was getting called multiple times for the 'bugged' cell, and apparently due to some intricacies of CALayer and CGAffineTranform's, assigning the tranform had an additive affect.

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{ 
    CGAffineTransform transform = CGAffineTransformMakeRotation(1.5707963);
    cell.transform = transform;
}

The solution was to move the transform into the cell's init method, so that it is guaranteed to be set only once per cell.

// ... init stuff  
self.transform = CGAffineTranformMakeRotation(1.5707963);
// ... more init stuff
0
votes

Make a subclass of UITableViewCell and it its layoutSubviews override make sure to set the transform there:

class InvertedTableViewCell: UITableViewCell {
    override func layoutSubviews() {
            self.transform = CGAffineTranformMakeRotation(1.5707963)
        }
}