2010-05-12 4 views
34

Это более общий вопрос для людей, которые предоставляют мне рекомендации, в основном, о том, как я изучаю разработку iPad/iPhone и, наконец, столкнулись с вопросом поддержки нескольких ориентаций.Управление ориентацией iphone/ipad

Я искал большое количество doco, и моя книга «Начало разработки iPhone 3» имеет приятную главу.

Но мой вопрос в этом, если бы я хотел программно изменить свои элементы управления (или даже использовать разные виды для каждой ориентации), как люди поддерживают свою базу кода? Я могу представить себе столько проблем с кодами спагетти/тысячами «если» проверяет повсюду, что это заставило бы меня замочить, чтобы сделать небольшое изменение в настройке пользовательского интерфейса.

У кого-нибудь есть опыт работы с этой проблемой? Какой хороший способ контролировать это?

Большое спасибо Марк

ответ

41

я сделать это с помощью двух простых методов, на мой взгляд контроллера:

- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 
    [self adjustViewsForOrientation:toInterfaceOrientation]; 
} 

- (void) adjustViewsForOrientation:(UIInterfaceOrientation)orientation { 
    if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) { 
     titleImageView.center = CGPointMake(235.0f, 42.0f); 
     subtitleImageView.center = CGPointMake(355.0f, 70.0f); 
     ... 
    } 
    else if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) { 
     titleImageView.center = CGPointMake(160.0f, 52.0f); 
     subtitleImageView.center = CGPointMake(275.0f, 80.0f); 
     ... 
    } 
} 

Чтобы сохранить этот чистый можно легко полочкам корректировки просмотра/перезагрузки/и т.д.. с методами, вызванными изнутри одиночного if-else условным.

+0

да, это своего рода то, что я делаю сейчас ... спасибо – Mark

+1

метод willRotateToInterface для меня никогда не называется. Вам нужно что-то подключить или добавить слушателя в IB или что-то еще? –

+0

Это отличный пример, который я искал. любой альтернативный пример? –

2

iPhone SDK построен вокруг, имеющий архитектуру MVC, так что в теории, если вы сохраняете всю свою логику (модель), отделенный от вашего UI (вид), то вам нужно будет только беспокоиться о пользовательском интерфейсе в одном месте: контроллеры просмотра. Для них у вас может быть отдельный контроллер просмотра для каждой ориентации, каждый из которых затем будет загружен только одним, если/else, чтобы выбрать, какой контроллер просмотра загрузить.

Такая же идея предназначена для поддержки iPhone/iPad, где вы можете загрузить другой контроллер представления, который может обрабатывать большие дисплеи.

+0

Да, я видел, что кто-то делает что-то подобное, его хорошая идея, спасибо – Mark

7

Это действительно зависит от того, что именно вы планируете.

Если вы посмотрите приложение Apple Settings, вы увидите, что они используют представления таблиц для макета с настраиваемыми ячейками для большинства строк. Благодаря этому вы можете позволить простому интерфейсу вращаться довольно дешево, просто заполнив ширину ячеек. Это относится даже к вещам вроде Mail, где в каждой строке есть текстовые ячейки редактирования. И таблицы могут быть легко прозрачными, только видимыми только кнопки или ярлыки, поэтому они не выглядят как таблицы.

Вы можете получить много средств из авторезистивного макета каждого UIView. Если у вас есть один или несколько элементов, которые могут иметь гибкую высоту, вы обычно можете получить макет интерфейса, который хорошо выглядит в любой ориентации. В зависимости от того, как это выглядит, иногда вы можете просто прикрепить все к вершине.

В редких случаях, если все элементы интерфейса соответствуют квадрату, вы можете просто повернуть их на место.

Существует два раза, когда вы должны явно обрабатывать изменения ориентации. Один из них - это когда вид поворачивается рядом с другим под вращением. Другая - когда у вас разные изображения для каждой ориентации, например, если вы всегда хотите иметь полную ширину.

Иногда есть способы обойти их оба. Вы можете использовать растягивающиеся изображения или ограничить себя одним видом на строку. Или вы можете заблокировать ориентацию для определенных видов.

Если вы должны изменить макет представлений, существует явный метод layoutSubviews.Вы должны попытаться обработать все условные макеты в этом методе. Он вызывается только тогда, когда изменяются границы вида, например, при вращении или если вы освободили место для клавиатуры. Создайте пользовательский вид для каждой иерархии представлений, которая должна отвечать на поворот, и отложите подпрограммы оттуда.

0

Я не могу поручиться за этот код, и во всей честности выше willRotateToInterfaceOrientation работает. Вот еще один пример с FBDialog.m от Facebook для iphone/ipad. (Хотя, я думаю, что это было для WebView)

вот суть

[[NSNotificationCenter defaultCenter] addObserver:self 
    selector:@selector(deviceOrientationDidChange:) 
    name:@"UIDeviceOrientationDidChangeNotification" object:nil]; 


- (void)deviceOrientationDidChange:(void*)object { 
    UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 
    if ([self shouldRotateToOrientation:orientation]) { 


    CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration; 
    [UIView beginAnimations:nil context:nil]; 
    [UIView setAnimationDuration:duration]; 
    [self sizeToFitOrientation:YES]; 
    [UIView commitAnimations]; 
    } 
} 


-(CGAffineTransform)transformForOrientation { 
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 
    if (orientation == UIInterfaceOrientationLandscapeLeft) { 
    return CGAffineTransformMakeRotation(M_PI*1.5); 
    } else if (orientation == UIInterfaceOrientationLandscapeRight) { 
    return CGAffineTransformMakeRotation(M_PI/2); 
    } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { 
    return CGAffineTransformMakeRotation(-M_PI); 
    } else { 
    return CGAffineTransformIdentity; 
    } 
} 

- (void)sizeToFitOrientation:(BOOL)transform { 
    if (transform) { 
    self.transform = CGAffineTransformIdentity; 
    } 

    CGRect frame = [UIScreen mainScreen].applicationFrame; 
    CGPoint center = CGPointMake(
    frame.origin.x + ceil(frame.size.width/2), 
    frame.origin.y + ceil(frame.size.height/2)); 

    CGFloat scale_factor = 1.0f; 
    if (FBIsDeviceIPad()) { 
    // On the iPad the dialog's dimensions should only be 60% of the screen's 
    scale_factor = 0.6f; 
    } 

    CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2; 
    CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2; 

    _orientation = [UIApplication sharedApplication].statusBarOrientation; 
    if (UIInterfaceOrientationIsLandscape(_orientation)) { 
    self.frame = CGRectMake(kPadding, kPadding, height, width); 
    } else { 
    self.frame = CGRectMake(kPadding, kPadding, width, height); 
    } 
    self.center = center; 

    if (transform) { 
    self.transform = [self transformForOrientation]; 
    } 
} 
0

В вашем вопросе, Вы писали:

Я могу только представить себе так много проблем с спагетти кода/тысячи «if» проверяет повсюду, что это заставило бы меня замочить, чтобы внести небольшое изменение в схему пользовательского интерфейса.

Один из способов уклониться от этого заключается в том, чтобы создать иерархию представлений, которая с самого начала разделяет обработку конкретных изменений iPhone/iPad. Вам нужно было только установить, какой вид изначально загружен для каждого устройства. Затем вы создаете viewcontroller, как обычно, но вы также подклассифицируете созданный контроллер представления. Один подкласс для каждого устройства. Здесь вы можете поместить код конкретного устройства, например, ориентацию. Как это:

MyViewController.h   // Code that is used on both devices 
    MyViewController_iPhone.h // iPhone specific code, like orientation handling 
    MyViewController_iPad.h // iPad specific code, like orientation handling 

Если вы заинтересованы в таком подходе, я предлагаю вам прочитать this article. Это объясняет это очень красиво.

Одна из вещей, статья упоминает, это:

--start из quote--

красоты этого узора мы не засорять наш код с гречихой выглядит следующим образом:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 
    // The device is an iPad running iPhone 3.2 or later. 
    // set up the iPad-specific view 
} else { 
    // The device is an iPhone or iPod touch. 
    // set up the iPhone/iPod Touch view 
} 

--- конец quote--

Надеюсь, это поможет. Удачи!