Search code examples
iosuiviewautolayoutlayoutsubviews

Rearranging subviews from 2 line to 1 according to the device orientation


G’day guys,

I am initially targetting the iPhone, with iOS6.1 but hints and code able to run flawlessly also on the iPhone with iOS5.1 is welcome.

I have a custom UITableViewCell with 7 different labels as subviews:

-(id) initWithStyle: (UITableViewCellStyle) style reuseIdentifier: (NSString*) reuseIdentifier
{
    self = [super initWithStyle : style reuseIdentifier : reuseIdentifier] ;

    if (self){

//Adding Subviews

[self.contentView addSubView : self.myLabel1] ;
[self.contentView addSubView : self.myLabel2] ;
[self.contentView addSubView : self.myLabel3] ;
[self.contentView addSubView : self.myLabel4] ;
[self.contentView addSubView : self.myLabel5] ;
[self.contentView addSubView : self.myLabel6] ;
[self.contentView addSubView : self.myLabel7] ;
}
return self;
}

When I lazily instantiate the labels I suppose the starting orientation is portrait and the labels are arranged on two different lines:

-(UILabel*) myLabel1
{
    if (!_myLabel1){
        _myLabel1 = [UILabel alloc] initWithFrame: CGRectMake(10,30,40,20);
        _myLabel1.numberOfLines = 1;
        _myLabel1.opaque = YES;
}
return _myLabel1; 
}

-(UILabel*) myLabel2
{
    if (!_myLabel2){
        _myLabel2 = [UILabel alloc] initWithFrame: CGRectMake(50,30,40,20);
        _myLabel2.numberOfLines = 1;
        _myLabel2.opaque = YES;
}
return _myLabel2; 
}

-(UILabel*) myLabel3
{
    if (!_myLabel3){
        _myLabel3 = [UILabel alloc] initWithFrame: CGRectMake(90,30,40,20);
        _myLabel3.numberOfLines = 1;
        _myLabel3.opaque = YES;
}
return _myLabel3; 
}


-(UILabel*) myLabel4
{
    if (!_myLabel4){
        _myLabel4 = [UILabel alloc] initWithFrame: CGRectMake(10,60,40,20);
        _myLabel4.numberOfLines = 1;
        _myLabel4.opaque = YES;
}
return _myLabel4; 
}

-(UILabel*) myLabel5
{
    if (!_myLabel5){
        _myLabel5 = [UILabel alloc] initWithFrame: CGRectMake(50,60,40,20);
        _myLabel5.numberOfLines = 1;
        _myLabel5.opaque = YES;
}
return _myLabel5; 
}


-(UILabel*) myLabel6
{
    if (!_myLabel6){
        _myLabel6 = [UILabel alloc] initWithFrame: CGRectMake(90,60,40,20);
        _myLabel6.numberOfLines = 1;
        _myLabel6.opaque = YES;
}
return _myLabel6; 
}


-(UILabel*) myLabel7
{
    if (!_myLabel7){
        _myLabel7 = [UILabel alloc] initWithFrame: CGRectMake(130,60,40,20);
        _myLabel7.numberOfLines = 1;
        _myLabel7.opaque = YES;
}
return _myLabel7; 
}

I would like to ask what is the best way to accomplish this:

“If the orientation is portrait then arrange the labels on 2 different lines as above, if the orientation is landscape then arrange all the labels to be displayed on a single line. The rearrange should be automatic if the user change the orientation.

The rearrange in the landscape mode should have all the labels aligned with an y value of 30 (instead of 30 for the first line and 60 for the second line). The x value of the labels 4, 5, 6 ,7 should also change because instead of being placed below the labels 1,2,3 they’ll be placed at the right of the label 3.”

Btw, I found that sometime starting the app in a real iPhone kept “portrait” on a desk, the orientation is wrongly reported as “landscape” both with iOS 5.1 and iIOS 6.1. I found this because I started playing with layoutSubviews: ‘cause I thought it was the best spot to rearrange the views creating a new frame for each one of them according to the orientation of the device. Is this a best case for autolayout? The view is and will be created programmatically.

Thanks

Nicola


Solution

  • Thanks for your answer Kalpesh but actually after more trials I found that the best way to handle it is to have a pointer in the UITableViewCell to its controller and use it to get the new orientation then do the rearrangement in layoutSubviews:

    @property(weak,nonatomic) UITableViewController *controller;
    
    -(void) layoutSubviews
    {
        [super layoutSubviews];
    
    
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone){
    
            // I am on a Phone
    
            NSLog(@"The new controller orientation is: %u", self.controller.interfaceOrientation);
    
            if(self.controller.interfaceOrientation == UIInterfaceOrientationPortrait){
                NSLog(@"Phone - Controller orientation: Portrait.");
    
                //Layout the subviews for portrait orientation
    
                self.myLabel1.frame = CGRectMake(10,70,(self.frame.size.width-20)/4,20);
    
                //..
    
            } else{
                NSLog(@"Phone - Controller orientation: Landscape.");
    
                //Layout the subviews for landscape orientation
    
                self.myLabel1.frame = CGRectMake(10,30,(self.frame.size.width-20)/4,20);
    
                //..
            }
    
        } else if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad){
    
            // I am on a Pad
    
            if(self.controller.interfaceOrientation == UIInterfaceOrientationPortrait){
                NSLog(@"Pad - Controller orientation: Portrait.");
    
                //Layout the subviews for portrait orientation
    
            } else{
                NSLog(@"Pad - Controller orientation: Landscape.");
    
                //Layout the subviews for landscape orientation
            }
    
        }
    }
    

    Anyway the refresh of the table as suggested by you can be useful to change the eight of the rows!

    EDIT: The cell height is automatically reloaded when the orientation change so no need to force a reload of the table. Nicola