есть ли документированный способ установки ориентации iphone?

<p>у меня есть приложение, в котором я хотел бы поддерживать поворот устройства в определенных видах, но другие не имеют особого смысла в режиме «пейзаж», поэтому, меняя представления, я хотел бы установить поворот в портретный режим.</p><p>в uidevice есть недокументированный установщик свойств, который делает свое дело, но, очевидно, генерирует предупреждение компилятора и может исчезнуть с будущей версией sdk.</p><pre><code>[[uidevice currentdevice] setorientation:uiinterfaceorientationportrait]; </code></pre><p>есть ли документированные способы форсировать ориентацию?</p><p><strong> обновление: </strong>я подумал, что приведу пример, так как я не ищу shouldautorotatetointerfaceorientation, поскольку я это уже реализовал.</p><p>я хочу, чтобы мое приложение поддерживало альбомную ориентацию и портретную ориентацию в представлении 1, но только вертикальную ориентацию в представлении 2. я уже реализовал mustautorotatetointerfaceorientation для всех представлений, но если пользователь находится в горизонтальном режиме в представлении 1, а затем переключается на представление 2, я хочу принудительно вызвать телефон, чтобы повернуть обратно в портрет.</p>

<p>это больше не проблема на более позднем iphone 3.1.2 sdk. теперь кажется, что он выполняет заданную ориентацию представления, возвращаемого обратно в стек. это, вероятно, означает, что вам нужно будет обнаружить более старые версии iphone os и применять setorientation только тогда, когда это происходит до последней версии.</p><p>неясно, поймет ли статический анализ apple, что вы работаете над старыми ограничениями sdk. apple лично сказал мне убрать вызов метода в моем следующем обновлении, так что я пока не уверен, пройдет ли процесс одобрения для старых устройств.</p>

<p>это долго после факта, но на всякий случай приходит кто-то, кто не использует контроллер навигации и/или не хочет использовать недокументированные методы:</p><pre><code>uiviewcontroller *c = [[uiviewcontroller alloc]init]; [self presentmodalviewcontroller:c animated:no]; [self dismissmodalviewcontrolleranimated:no]; [c release]; </code></pre><p>достаточно представить и отклонить контроллер вида vanilla.</p><p>очевидно, вам все равно нужно будет подтвердить или отклонить ориентацию в переопределении shouldautorotatetointerfaceorientation. но это приведет к тому, что система должна снова вызывать autorotate ....</p>

<p>из того, что я могу сказать, метод <code>setorientation:</code> не работает (или, возможно, больше не работает). вот что я делаю, чтобы сделать это:</p><p>во-первых, поместите это определение вверху вашего файла, прямо под #imports:</p><pre><code>#define degreestoradian(x) (m\_pi * (x) / 180.0) </code></pre><p>затем в методе <code>viewwillappear:</code></p><pre><code>[[uiapplication sharedapplication] setstatusbarhidden:yes animated:no]; if (self.interfaceorientation == uiinterfaceorientationportrait) { self.view.transform = cgaffinetransformidentity; self.view.transform = cgaffinetransformmakerotation(degreestoradian(90)); self.view.bounds = cgrectmake(0.0, 0.0, 480, 320); } </code></pre><p>если вы хотите, чтобы это было анимировано, то вы можете обернуть все это в блок анимации, например так:</p><pre><code>[uiview beginanimations:@"view flip" context:nil]; [uiview setanimationduration:1.25]; [uiview setanimationcurve:uiviewanimationcurveeaseinout]; [[uiapplication sharedapplication] setstatusbarhidden:yes animated:no]; if (self.interfaceorientation == uiinterfaceorientationportrait) { self.view.transform = cgaffinetransformidentity; self.view.transform = cgaffinetransformmakerotation(degreestoradian(90)); self.view.bounds = cgrectmake(0.0, 0.0, 480, 320); } [uiview commitanimations]; </code></pre><p>затем в контроллере портретного режима вы можете сделать обратное - проверить, находится ли он в настоящее время в альбомной ориентации, и, если это так, повернуть его обратно в книжный режим.</p>

<p>если вы хотите заставить его вращаться от портрета до пейзажа, вот код. просто отметьте, что вам нужно отрегулировать центр вашего обзора. я заметил, что мой не поместил вид в правильном месте. в остальном все работало отлично. спасибо за чаевые.</p><pre><code>if(uiinterfaceorientationislandscape(self.interfaceorientation)){ [uiview beginanimations:@"view flip" context:nil]; [uiview setanimationduration:0.5f]; [uiview setanimationcurve:uiviewanimationcurveeaseinout]; self.view.transform = cgaffinetransformidentity; self.view.transform = cgaffinetransformmakerotation(degreestoradian(90)); self.view.bounds = cgrectmake(0.0f, 0.0f, 480.0f, 320.0f); self.view.center = cgpointmake(160.0f, 240.0f); [uiview commitanimations]; } </code></pre>

<p>я копал и копал в поисках хорошего решения этой проблемы. нашел этот пост в блоге, который делает трюк: удалите ваше внешнее представление из ключа <code>uiwindow</code> и добавьте его снова, система затем повторно запросит методы <code>shouldautorotatetointerfaceorientation:</code> из ваших контроллеров представления, принудительно применяя правильную ориентацию . смотрите это: <a href="http://goodliffe.blogspot.com/2009/12/iphone-forcing-uiview-to-reorientate.html">iphone заставляет uiview переориентироваться</a> </p>

<p>существует простой способ программно принудительно настроить iphone на нужную ориентацию - использовать два из уже предоставленных ответов<strong> kdbdallas </strong>,<strong> josh </strong>:</p><pre><code>//will rotate status bar [[uiapplication sharedapplication] setstatusbarorientation:uiinterfaceorientationlandscaperight]; //will re-rotate view according to statusbar uiviewcontroller *c = [[uiviewcontroller alloc]init]; [self presentmodalviewcontroller:c animated:no]; [self dismissmodalviewcontrolleranimated:no]; [c release]; </code></pre><p>работает как шарм :)</p><p>правка:</p><p>для ios 6 мне нужно добавить эту функцию: (работает на модальном viewcontroller)</p><pre><code>- (nsuinteger)supportedinterfaceorientations { return (uiinterfaceorientationmasklandscapeleft | uiinterfaceorientationmasklandscaperight); } </code></pre>

<p>у меня возникла проблема, когда у меня была <code>uiviewcontroller</code> на экране, в <code>uinavigationcontroller</code>, в альбомной ориентации. когда следующий контроллер вида был помещен в поток, мне понадобилось устройство, чтобы вернуться в портретную ориентацию.</p><p>я заметил, что метод <code>shouldautorotatetointerfaceorientation:</code> не вызывается, когда в стек помещается новый контроллер представления, но<strong> он вызывается, когда контроллер представления извлекается из стека </strong>.</p><p>воспользовавшись этим, я использую этот фрагмент кода в одном из моих приложений:</p><pre><code>- (void)selecthostingatindex:(int)hostingindex { self.transitioning = yes; uiviewcontroller *garbagecontroller = [[[uiviewcontroller alloc] init] autorelease]; [self.navigationcontroller pushviewcontroller:garbagecontroller animated:no]; [self.navigationcontroller popviewcontrolleranimated:no]; bbhostingcontroller *hostingcontroller = [[bbhostingcontroller alloc] init]; hostingcontroller.hosting = [self.hostings objectatindex:hostingindex]; [self.navigationcontroller pushviewcontroller:hostingcontroller animated:yes]; [hostingcontroller release]; self.transitioning = no; } - (bool)shouldautorotatetointerfaceorientation:(uiinterfaceorientation)tointerfaceorientation { if (self.transitioning) return (tointerfaceorientation == uiinterfaceorientationportrait); else return yes; } </code></pre><p>по сути, создав пустой контроллер представления, поместив его в стек и немедленно вытолкнув его, можно вернуть интерфейс в исходное положение. после того, как контроллер отключен, я просто нажимаю на контроллер, который я намеревался нажать в первую очередь. визуально это выглядит великолепно - пустой, произвольный контроллер представления никогда не будет виден пользователю.</p>

<p>ответ джоша отлично работает для меня.</p><p>однако я предпочитаю публиковать <em>"ориентация изменилась, обновите пользовательский интерфейс"</em>. когда это уведомление получено контроллером представления, он вызывает <code>shouldautorotatetointerfaceorientation:</code>, позволяя вам установить любую ориентацию, возвращая <code>yes</code> для нужной ориентации.</p><pre><code>[[nsnotificationcenter defaultcenter] postnotificationname:uideviceorientationdidchangenotification object:nil]; </code></pre><p>единственная проблема заключается в том, что это вызывает переориентацию<strong> без </strong>/ анимации. вам нужно было обернуть эту строку между <code>beginanimations:</code> и <code>commitanimations</code>, чтобы добиться плавного перехода.</p><p>надеюсь, это поможет.</p>

<p>fwiw, вот моя реализация ручной установки ориентации (чтобы перейти в корневой контроллер вашего приложения, естественно): </p><pre><code>-(void)rotateinterfacetoorientation:(uideviceorientation)orientation{ cgrect bounds = [[ uiscreen mainscreen ] bounds ]; cgaffinetransform t; cgfloat r = 0; switch ( orientation ) { case uideviceorientationlandscaperight: r = -(m\_pi / 2); break; case uideviceorientationlandscapeleft: r = m\_pi / 2; break; } if( r != 0 ){ cgsize sz = bounds.size; bounds.size.width = sz.height; bounds.size.height = sz.width; } t = cgaffinetransformmakerotation( r ); uiapplication *application = [ uiapplication sharedapplication ]; [ uiview beginanimations:@"interfaceorientation" context: nil ]; [ uiview setanimationduration: [ application statusbarorientationanimationduration ] ]; self.view.transform = t; self.view.bounds = bounds; [ uiview commitanimations ]; [ application setstatusbarorientation: orientation animated: yes ]; } </code></pre><p>в сочетании со следующим методом <code>uinavigationcontrollerdelegate</code> (при условии, что вы используете <code>uinavigationcontroller</code>):</p><pre><code>-(void)navigationcontroller:(uinavigationcontroller *)navigationcontroller willshowviewcontroller:(uiviewcontroller *)viewcontroller animated:(bool)animated{ // rotate interface, if we need to uideviceorientation orientation = [[ uidevice currentdevice ] orientation ]; bool bviewcontrollerdoessupportcurrentorientation = [ viewcontroller shouldautorotatetointerfaceorientation: orientation ]; if( !bviewcontrollerdoessupportcurrentorientation ){ [ self rotateinterfacetoorientation: uideviceorientationportrait ]; } } </code></pre><p>это обеспечивает поворот корневого представления в зависимости от того, поддерживает ли входящая <code>uiviewcontroller</code> текущую ориентацию устройства. наконец, вам нужно подключить <code>rotateinterfacetoorientation</code> к фактическим изменениям ориентации устройства, чтобы имитировать стандартную функциональность ios. добавьте этот обработчик событий в тот же корневой контроллер вида:</p><pre><code>-(void)onuideviceorientationdidchangenotification:(nsnotification*)notification{ uiviewcontroller *tvc = self.rootnavigationcontroller.topviewcontroller; uideviceorientation orientation = [[ uidevice currentdevice ] orientation ]; // only switch if we need to (seem to get multiple notifications on device) if( orientation != [[ uiapplication sharedapplication ] statusbarorientation ] ){ if( [ tvc shouldautorotatetointerfaceorientation: orientation ] ){ [ self rotateinterfacetoorientation: orientation ]; } } } </code></pre><p>наконец, зарегистрируйтесь для получения уведомлений <code>uideviceorientationdidchangenotification</code> в <code>init</code> или <code>loadview</code> следующим образом:</p><pre><code>[[ nsnotificationcenter defaultcenter ] addobserver: self selector: @selector(onuideviceorientationdidchangenotification:) name: uideviceorientationdidchangenotification object: nil ]; [[ uidevice currentdevice ] begingeneratingdeviceorientationnotifications ]; </code></pre>

<p>это работает для меня (спасибо генри кук):</p><p>цель для меня состояла в том, чтобы иметь дело только с изменениями ландшафтных ориентаций.</p><h2>метод init:</h2><pre><code>[[uidevice currentdevice] begingeneratingdeviceorientationnotifications]; [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(orientationchanged:) name:uideviceorientationdidchangenotification object:nil]; </code></pre><hr><pre><code>- (void)orientationchanged:(nsnotification *)notification { //[[uidevice currentdevice] endgeneratingdeviceorientationnotifications]; uideviceorientation orientation = [uidevice currentdevice].orientation; cgrect bounds = [[ uiscreen mainscreen ] bounds ]; cgaffinetransform t; cgfloat r = 0; switch ( orientation ) { case uideviceorientationlandscaperight: r = 0; nslog(@"right"); break; case uideviceorientationlandscapeleft: r = m\_pi; nslog(@"left"); break; default:return; } t = cgaffinetransformmakerotation( r ); uiapplication *application = [ uiapplication sharedapplication ]; [ uiview beginanimations:@"interfaceorientation" context: nil ]; [ uiview setanimationduration: [ application statusbarorientationanimationduration ] ]; self.view.transform = t; self.view.bounds = bounds; [ uiview commitanimations ]; [ application setstatusbarorientation: orientation animated: yes ]; } </code></pre>

<blockquote> <p>у меня есть приложение, в котором я хотел бы поддерживать поворот устройства в определенных видах, но другие не имеют особого смысла в режиме «пейзаж», поэтому, меняя представления, я хотел бы установить поворот в портретный режим.</p> </blockquote><p>я понимаю, что вышеприведенный оригинальный пост в этой теме сейчас очень старый, но у меня была похожая проблема - т.е. все экраны в моем приложении только портретные, за исключением одного экрана, который пользователь может поворачивать между альбомным и портретным.</p><p>это было достаточно просто, но, как и в других публикациях, я хотел, чтобы приложение автоматически возвращалось в портретную ориентацию независимо от текущей ориентации устройства при возврате к предыдущему экрану.</p><p>решение, которое я реализовал, заключалось в том, чтобы скрыть панель навигации в ландшафтном режиме, а это означает, что пользователь может вернуться только к предыдущим экранам в портретном режиме. поэтому все остальные экраны могут быть только в портретном режиме.</p><pre><code>- (void)didrotatefrominterfaceorientation:(uiinterfaceorientation)pinterfaceorientation { bool lhidenavbar = self.interfaceorientation == uiinterfaceorientationportrait ? no : yes; [self.navigationcontroller setnavigationbarhidden:lhidenavbar animated:yes]; } </code></pre><p>это также имеет дополнительное преимущество для моего приложения в том, что в альбомном режиме доступно больше места на экране. это полезно, потому что рассматриваемый экран используется для отображения pdf файлов.</p><p>надеюсь это поможет.</p>

<p>решение для ios 6:</p><pre><code>[[[self window] rootviewcontroller] presentviewcontroller:[[uiviewcontroller alloc] init] animated:no completion:^{ [[[self window] rootviewcontroller] dismissviewcontrolleranimated:no completion:nil]; }]; </code></pre><p>точный код зависит от приложения, а также от того, где вы его разместили (я использовал его в своем appdelegate). замените <code>[[self window] rootviewcontroller]</code> на то, что вы используете. я использовал <code>uitabbarcontroller</code>.</p>

<p>я решил это довольно легко в конце. я перепробовал все предложенные выше предложения, но все равно потерпел неудачу, так что это было мое решение:</p><p>в viewcontroller, который должен оставаться альбомным (левым или правым), я слушаю изменения ориентации:</p><pre><code> [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(didrotate:) name:uideviceorientationdidchangenotification object:nil]; </code></pre><p>тогда в didrotate:</p><pre><code>- (void) didrotate:(nsnotification *)notification { if (orientationa == uideviceorientationportrait) { if (hasrotated == no) { nslog(@"rotating to portait"); hasrotated = yes; [uiview beginanimations: @"" context:nil]; [uiview setanimationduration: 0]; self.view.transform = cgaffinetransformidentity; self.view.transform = cgaffinetransformmakerotation(degrees\_to\_radians(-90)); self.view.bounds = cgrectmake(0.0f, 0.0f, 480.0f, 320.0f); self.view.frame = cgrectmake(0.0f, 0.0f, 480.0f, 320.0f); [uiview commitanimations]; } } else if (uideviceorientationislandscape( orientationa)) { if (hasrotated) { nslog(@"rotating to lands"); hasrotated = no; [uiview beginanimations: @"" context:nil]; [uiview setanimationduration: 0]; self.view.transform = cgaffinetransformidentity; self.view.transform = cgaffinetransformmakerotation(degrees\_to\_radians(0)); self.view.bounds = cgrectmake(0.0f, 0.0f, 320.0f, 480.0f); self.view.frame = cgrectmake(0.0f, 0.0f, 320.0f, 480.0f); [uiview commitanimations]; } } </code></pre><p>имейте в виду любые super views/subviews, которые используют авторазмер, так как view.bounds/frame сбрасывается явно ... </p><p>единственное предостережение этого метода для сохранения ландшафта вида - это внутреннее переключение анимации между ориентациями, которое должно произойти, когда было бы лучше, чтобы оно казалось без изменений. </p>

<p>я нашел решение и написал что-то по-французски (но код на английском). <a href="http://www.geckogeek.fr/iphone-forcer-le-mode-landscape-ou-portrait-en-cours-dexecution.html">вот</a> </p><p>способ заключается в том, чтобы добавить контроллер в окно (контроллер должен обладать хорошей реализацией функции shouldrotate ....).</p>