Как разрешить только один UIViewController вращаться в направлении "Пейзаж" и "Портрет"?
Мое приложение предназначено только для устройства iphone
(как для iphone 4 и 5), так и для поддержки только ios 6
.
Все мое приложение поддерживает только режим portrait
. Но есть одно представление под названием "ChatView
", которое я хочу поддерживать как в режимах landscape
, так и portrait
.
Я установил необходимые вращения устройства следующим образом:
![enter image description here]()
Я также пробовал следующий код для поддержки вращения в "ChatView" -
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
Но он не мог повернуть этот вид.
Я много искал для этого, но не смог найти решение для своей проблемы.
А также в "ChatView" есть некоторые объекты, такие как кнопки, текстовые поля, чьи кадры заданы программно. Так что я хочу знать, должен ли я также устанавливать кадры всех этих объектов для ландшафтного режима?
Пожалуйста, помогите мне.
Спасибо.....
Ответы
Ответ 1
Я думаю, что если вы хотите поддерживать только один поворот viewcontroller, это невозможно, так как приложение будет следовать настройкам, установленным вами в файле .plist
. Альтернативой, которую вы можете использовать, является поддержка вашего приложения как для пейзажа, так и для портрета, затормозить вращение всех зрителей до портрета, за исключением просмотра чата.
ИЗМЕНИТЬ
В подкласс UINavigationController
создайте новый файл с именем, например. CustomNavigationController
и сделать его подклассом UINavigationController
.
.h файл
#import <UIKit/UIKit.h>
@interface CustomNavigationController : UINavigationController
@end
.m файл
#import "CustomNavigationController.h"
@interface CustomNavigationController ()
@end
@implementation CustomNavigationController
-(BOOL)shouldAutorotate
{
return NO;
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
@end
Задайте класс вашего UINavigationController
в вашем основном классе xib как CustomNavigationController
. Надеюсь, это поможет ypu..
Ответ 2
Простой, но он работает очень хорошо. IOS 7.1 и 8
AppDelegate.h
@property () BOOL restrictRotation;
AppDelegate.m
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.restrictRotation)
return UIInterfaceOrientationMaskPortrait;
else
return UIInterfaceOrientationMaskAll;
}
ViewController
-(void) restrictRotation:(BOOL) restriction
{
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate.restrictRotation = restriction;
}
viewDidLoad
[self restrictRotation:YES]; or NO
Ответ 3
Контроллер вашего представления никогда не будет вращаться в любую позицию, которая не поддерживается самим приложением. Вы должны включить все возможные вращения, а затем на виду контроллеры, которые не должны вращаться, поместите следующие строки
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
В ChatView это должно быть:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
Если вам нужно изменить макет после поворота, вы должны реализовать соответствующие изменения в своих подзонах в
- (void)viewWillLayoutSubviews
Используйте self.view.bounds
для проверки текущего размера view
, так как self.view.frame
не изменяется после поворотов.
Ответ 4
для конкретного viewcontroller.m
, который вы хотите повернуть
добавьте этот метод:
- (BOOL)canAutoRotate
{
return YES;
}
затем внутри вашего AppDelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
UIViewController *currentViewController = [self topViewController];
if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) {
NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:@selector(canAutoRotate)];
[invocation setTarget:currentViewController];
[invocation invoke];
BOOL canAutorotate = NO;
[invocation getReturnValue:&canAutorotate];
if (canAutorotate) {
return UIInterfaceOrientationMaskAll;
}
}
return UIInterfaceOrientationMaskPortrait;
}
- (UIViewController *)topViewController
{
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController
{
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
Ответ 5
Тед-ответ хорошо работает с вопросом, упомянутым Александром из Норвегии.
Но я подумал, что вопрос не происходит так, как объяснил Александр,
Когда ViewController B, который в настоящее время находится в ландшафте (All ориентации включены) возвращается обратно в ViewController A. (Портрет только) после того, как пользователь нажимает кнопку "Назад", supportInterfaceOrientationsForWindow не вызывается и ViewController A заканчивается в ландшафте
Фактически, когда ViewController B, который в настоящее время находится в ландшафте (все ориентации включены), возвращается обратно в ViewController A (только портрет) после того, как пользователь нажимает кнопку "Назад", Appdelegate
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
вызывается. Но все же контроллер корневого представления - ViewController B (этот контроллер с поддержкой вращения включен), ViewController A не возвращается к портретной ориентации, поскольку ViewController B все еще возвращает
-(BOOL)shouldAutorotate{
return YES;
}
Итак, когда вы нажмете кнопку возврата назад, "shouldAutorotate → NO" в ViewController B. Затем ViewController A перейдет в портретную ориентацию. Это то, что я сделал
@property (nonatomic, assign) BOOL canAutoRotate;
#pragma mark - Public methods
- (BOOL)canAutoRotate
{
return _canAutoRotate;
}
#pragma mark - Button actions
- (void)backButtonPressed:(UIButton *)sender {
_canAutoRotate = NO;
(...)
}
#pragma mark - Init
- (id)init{
if(self=[super init]) {
_canAutoRotate = YES;
}
return self;
}
Ответ 6
Swift 3 кошерная версия
Я оставил это здесь только на случай, если у кого-то есть проблема.
Документация Apple для supportedInterfaceOrientations
гласит:
Когда пользователь меняет ориентацию устройства, система вызывает этот метод на корневом контроллере представления или самом верхнем представленном контроллере представления, который заполняет окно. Если контроллер вида поддерживает новую ориентацию, окно и контроллер вида поворачиваются в новую ориентацию. Этот метод вызывается только в том случае, если метод viewAutorotate контроллера представления возвращает значение true.
В нескольких словах вы должны переопределить supportedInterfaceOrientations
в корневом контроллере представления, чтобы он возвращал значение для своего верхнего дочернего контроллера представления и значение по умолчанию в противном случае.
Что вы должны сделать, это проверить, поддерживает ли приложение все режимы (перейдите к разделу Информация о развертывании в общих настройках целей или Info.plist), выясните класс вашего корневого контроллера представления. Это может быть универсальный UIViewController, UINavigationController, UITabBarController или некоторый пользовательский класс. Вы можете проверить это следующим образом:
dump(UIApplication.shared.keyWindow?.rootViewController)
Или любым другим способом, который вам нравится.
Пусть это будет какой-то CustomNavigationController
. Таким образом, вы должны переопределить supportedInterfaceOrientations
следующим образом:
class CustomNavigationController: UINavigationController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
}
}
В любом контроллере представления, который должен поддерживать только книжную ориентацию, например, переопределить supportedInterfaceOrientations
следующим образом:
class ChildViewController: UIViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
Тогда не забудьте проверить, должен ли shouldAutorotate
контроллер представления и самый верхний представленный контроллер представления уже вернуть true
. Если нет, добавьте это в определения классов:
override var shouldAutorotate: Bool {
return true
}
В противном случае supportedInterfaceOrientations
не будет вызываться вообще.
Ну вот!
Если вам нужно исправить противоположную проблему, когда только один контроллер представления должен поддерживать несколько ориентаций, а другие нет, внесите эти изменения в каждый контроллер представления, кроме этого.
Надеюсь, это поможет.
Ответ 7
На основе ответа @iAnum я включил определение авторотации и определения класса UIViewController.
Это связано с тем, что в противном случае переход в "специальный контроллер просмотра" и из него не будет корректироваться в портретной ориентации, и вы будете застревать в неподдерживаемой ориентации.
У меня был только один вид поддержки ландшафта, поэтому я просто закодировал его в настраиваемом контроллере представления навигации:
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
//Access the current top object.
UIViewController *viewController = [self.viewControllers lastObject];
//Is it one of the landscape supported ones?
if ([viewController isMemberOfClass:[SpecialViewController class]]) {
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
} else
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
//Access the current top object.
UIViewController *viewController = [self.viewControllers lastObject];
//Is it one of the landscape supported ones?
if ([viewController isMemberOfClass:[SpecialViewController class]]) {
return interfaceOrientation;
} else
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
Здесь обсуждаются проблемы, связанные с VC, которые обсуждаются здесь fooobar.com/questions/67650/..., где отбрасывание назад в то время как в ландшафте даже не вызовет методы ориентации, поэтому вы должны взломать его немного, показывая и отклоняя модальный вид.
И тогда просто помните, что если вы хотите, чтобы willShowViewController запускался, вам нужно установить self.delegate = self и добавить UINavigationControllerDelegate в свой пользовательский контроллер навигации вместе с приведенным ниже кодом.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
UIViewController *c = [[UIViewController alloc]init];
[c.view setBackgroundColor:[UIColor clearColor]];
[navigationController presentViewController:c animated:NO completion:^{
[self dismissViewControllerAnimated:YES completion:^{
}];
}];
}
}
Ответ 8
создайте подкласс UINavigationController следующим образом:
MyNavigationController.h
#import <UIKit/UIKit.h>
@interface MyNavigationController : UINavigationController
@end
MyNavigationController.m
#import "MyNavigationController.h"
#import "ServicesVC.h"
@implementation MyNavigationController
-(BOOL)shouldAutorotate{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
if ([[self.viewControllers lastObject] isKindOfClass:[ServicesVC class]]) {
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
return UIInterfaceOrientationMaskAll;
}
@end
Предполагая, что ваш диспетчер представлений назван: ServicesVC
Ответ 9
Вот ответ Александра (https://stackoverflow.com/posts/25507963/revisions) в Swift:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
var currentViewController: UIViewController? = self.topViewController()
if currentViewController != nil && currentViewController!.canAutoRotate() {
return Int(UIInterfaceOrientationMask.All.rawValue)
}
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
func topViewController() -> UIViewController? {
if UIApplication.sharedApplication().keyWindow != nil
{
return self.topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
}
return nil
}
func topViewControllerWithRootViewController(rootViewController: UIViewController?) -> UIViewController? {
if rootViewController == nil {
return nil
}
if rootViewController!.isKindOfClass(UITabBarController) {
var tabBarController: UITabBarController = (rootViewController as? UITabBarController)!
return self.topViewControllerWithRootViewController(tabBarController.selectedViewController)
}
else {
if rootViewController!.isKindOfClass(UINavigationController) {
var navigationController: UINavigationController = (rootViewController as? UINavigationController)!
return self.topViewControllerWithRootViewController(navigationController.visibleViewController)
}
else {
if (rootViewController!.presentedViewController != nil) {
var presentedViewController: UIViewController = rootViewController!.presentedViewController!
return self.topViewControllerWithRootViewController(presentedViewController)
}
else {
return rootViewController
}
}
}
}
Кроме того, вам нужно будет добавить следующий фрагмент в AppDelegate.swift:
extension UIViewController {
func canAutoRotate() -> Bool {
return false
}}
И для ViewControllers, для которых вы хотите разрешить все вращения, добавьте эту функцию:
override func canAutoRotate() -> Bool {
return true
}
Ответ 10
Я не уверен в истории этой проблемы (сейчас = iOS 10 таймфрейма), но было простое решение, поскольку я опубликовал это в октябре 2016 года.
Предполагая, что вы хотите:
- Поддержка iOS 7 и только новых (включая iOS 10)
- Некоторые контроллеры представлений должны поддерживать все ориентации, другие должны поддерживать поднабор ориентации. Пример того, что я имею в виду: один контроллер просмотра должен поддерживать только портрет, в то время как все остальные должны поддерживать все ориентации
- Все контроллеры представлений должны автоматически вращаться, если они поддерживают ротацию (это означает, что вы не хотите, чтобы этот код исправлял эту проблему в контроллерах представлений).
- Поддержка добавления
UINavigationController
в XIBs/NIBs/Storyboards без необходимости что-либо делать с ними
... тогда (IMO) самым простым решением является сделать UINavigationControllerDelegate, НЕ подкласс UINavigationController (который нарушает предположение 4 выше).
Когда я решил это, я решил сделать мой первый ViewController
a UINavigationControllerDelegate
. Этот контроллер представления устанавливает себя как делегат контроллера навигации и возвращает, какие ориентации разрешены. В моем случае значением по умолчанию является то, что все ориентации разрешены с предпочтительным портретом, но в одном конкретном случае разрешен только портрет. Код ниже - от Swift 3/XCode 8:
class iPhoneStartViewController: UIViewController {
var navInterfaceOrientationMask: UIInterfaceOrientationMask?
var navInterfaceOrientationPreferred: UIInterfaceOrientation! = .portrait
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.delegate = self
}
@IBAction func cameraButtonPressed(_ sender: AnyObject) {
if PermissionsHelper.singleton().photosPermissionGranted() == false {
self.navInterfaceOrientationMask = nil // default is: all orientations supported
self.performSegue(withIdentifier: "segueToPhotoAccess", sender: self)
} else {
self.navInterfaceOrientationMask = .portrait // this stops the next view controller from being to rotate away from portrait
self.performSegue(withIdentifier: "segueToCamera", sender: self)
}
}
}
// lock orientation to portrait in certain cases only. Default is: all orientations supported
extension iPhoneStartViewController : UINavigationControllerDelegate {
public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
if let mask = self.navInterfaceOrientationMask {
return mask
} else {
return .all
}
}
public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation {
return self.navInterfaceOrientationPreferred
}
}
Ответ 11
У меня была такая же ситуация. Поэтому я подклассифицировал UINavigationController в CustomNavigationController, и внутри этого CustomNavigationController я написал
#define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 )
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )
#pragma mark - Rotation
#ifdef IOS_OLDER_THAN_6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
#endif
#ifdef IOS_NEWER_OR_EQUAL_TO_6
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;;
}
#endif
Я использовал этот CustomNavigationController вместо существующего NavigationController.
Затем внутри контроллера представления, который вы должны отображать в ориентации LandScape, говорят LandScapeView, я написал
#pragma mark - Rotation
#ifdef IOS_OLDER_THAN_6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight | toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
#endif
#ifdef IOS_NEWER_OR_EQUAL_TO_6
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;
}
#endif
Внутри CustomNavigationController я представил этот контроллер представлений, а не вдвинулся в стек навигации. Итак, LandScapeView появился в ориентации LandScape.
LandScapeView *graph = [[LandScapeView alloc]init....];
[self presentViewController:graph animated:YES completion:nil];
Я ничего не изменил в Ориентация поддерживаемого интерфейса в настройках проекта.
Ответ 12
//вставьте этот метод в класс приложения deligate
- (UIInterfaceOrientationMask)application:(UIApplication )application supportedInterfaceOrientationsForWindow:(UIWindow )window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [_moviePlayerController class]])
{
if (self.window.rootViewController.presentedViewController)
return UIInterfaceOrientationMaskAll;
else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}
Ответ 13
Если приложение поддерживает от IOS7 до IOS9, используйте этот код для ориентации:
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll;
else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
Ответ 14
Я знаю, что этот вопрос очень старый, но ему нужен обновленный ответ. Самый простой и правильный путь для достижения этого результата - включить Portrait и Landscape в настройках вашего приложения. Затем добавьте этот код в свой делегат приложения:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
if let navigationController = self.window?.rootViewController as? UINavigationController {
if navigationController.visibleViewController is INSERTYOURVIEWCONTROLLERHERE {
return UIInterfaceOrientationMask.All
}
else {
return UIInterfaceOrientationMask.Portrait
}
}
return UIInterfaceOrientationMask.Portrait
}
Не забудьте заменить "INSERTYOURVIEWCONTROLLERHERE" на ваш контроллер просмотра.