วิธีบังคับ UIViewController ให้เป็นแนวตั้งใน iOS 6


85

เนื่องจากShouldAutorotateToInterfaceOrientationเลิกใช้งานแล้วใน iOS 6 และฉันใช้สิ่งนั้นเพื่อบังคับให้มุมมองเฉพาะเป็นแนวตั้งเท่านั้นวิธีที่ถูกต้องในการทำสิ่งนี้ใน iOS 6 คืออะไร? นี่เป็นเพียงพื้นที่เดียวในแอปของฉันมุมมองอื่น ๆ ทั้งหมดสามารถหมุนได้

คำตอบ:


117

หากคุณต้องการให้ตัวควบคุมการนำทางทั้งหมดของเราเคารพตัวควบคุมมุมมองด้านบนคุณสามารถใช้หมวดหมู่เพื่อที่คุณจะได้ไม่ต้องผ่านและเปลี่ยนชื่อคลาสมากมาย

@implementation UINavigationController (Rotation_IOS6)

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

เนื่องจากความคิดเห็นบางส่วนชี้ให้เห็นว่านี่เป็นการแก้ไขปัญหาอย่างรวดเร็ว ทางออกที่ดีกว่าคือ UINavigationController subclass และใส่วิธีการเหล่านี้ไว้ที่นั่น คลาสย่อยยังช่วยในการรองรับ 6 และ 7


3
ฉันสามารถยืนยันได้ว่ามันได้ผล คุณยังสามารถแทนที่ "[self.viewControllers lastObject]" ด้วย "self.topViewController" ได้หากต้องการ
Wayne Liu

3
หากคุณใช้ UITabBarController มากกว่าหมวดหมู่ UINavigationController นี้จะไม่มีความช่วยเหลือ คุณควรสร้างหมวดหมู่บน UITabBarController แทน ...
Borut Tomazin

46
ปัญหาในการแก้ปัญหานี้คือมันไม่ทำงานเมื่อคุณเปิดตัวควบคุมที่อยู่ในแนวนอนและตัวควบคุมด้านบนใหม่ของคุณรองรับเฉพาะแนวตั้ง (หรือในทางกลับกัน) การโทรกลับเหล่านั้นจะไม่ถูกเรียกในกรณีนี้และฉันยังไม่พบวิธีการ บังคับตัวควบคุมด้านบนใหม่ให้อยู่ในแนวที่ถูกต้อง ความคิดใด ๆ ?
Lope

4
ฉันซับคลาส UINavigationController และตั้งเป็น window.rootController ฉันใช้ทั้ง 3 วิธีมันใช้งานได้ดีเมื่อคุณเปลี่ยนการหมุนอุปกรณ์ปัญหาคือวิธีการเหล่านั้น (และไม่มีอะไรเกี่ยวข้องกับการหมุน) ถูกเรียกเมื่อคุณเปิดตัวควบคุมมุมมอง
Lope

4
ถ้าฉันกดหรือป๊อปจากตัวควบคุมมุมมองแนวนอนการบังคับ UIViewController จะเปลี่ยนเป็นแนวนอน อย่างไรก็ตามถ้าฉันหมุนเป็นแนวตั้งมันก็ใช้ได้ดีและจะไม่เปลี่ยนเป็นแนวนอน ปัญหาเดียวในขณะที่พุชหรือป๊อปจากแนวนอน โปรดช่วย
Tariq

63

วิธีที่ดีที่สุดสำหรับ iOS6 โดยเฉพาะมีการระบุไว้ใน "iOS6 By Tutorials" โดยทีม Ray Wenderlich - http://www.raywenderlich.com/และดีกว่าคลาสย่อยUINavigationControllerสำหรับกรณีส่วนใหญ่

ฉันใช้ iOS6 กับสตอรีบอร์ดที่มีUINavigationControllerชุดเป็นตัวควบคุมมุมมองเริ่มต้น

//AppDelegate.m - วิธีนี้ไม่สามารถใช้งานได้กับ iOS6 ล่วงหน้า

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;

if(self.window.rootViewController){
    UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
    orientations = [presentedViewController supportedInterfaceOrientations];
}

return orientations;
}

//MyViewController.m - ส่งคืนทิศทางที่คุณต้องการสนับสนุนสำหรับแต่ละทิศทาง UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

1
นี่เป็นทางออกที่ดีที่สุดสำหรับ iOS 6
Homam

2
@ ฟิลมันใช้งานได้ดีสำหรับ iOS 6 แต่ในบางกรณีเช่นถ้าคุณเปลี่ยนจากแนวนอนไปเป็นแนวตั้งมันจะไม่ทำงาน มีความคิดว่าทำไมมันถึงเกิดขึ้น?
Kirti Nikam

1
วิธีแก้ปัญหาที่มีประโยชน์มาก สำหรับฉันดีที่สุด
oscar castellon

1
การทำงานบน iOS 7 เบต้า 6 ใช้งานได้เมื่อเปลี่ยนจากแนวนอนเป็นแนวตั้งในกรณีของฉัน
Martin Berger

ฉันใช้ iOS 6 แต่ไม่ได้ผล มันแตกในบรรทัด "UIViewController * presentsViewController"
Marcel Marino

39

คำตอบนี้เกี่ยวข้องกับคำถามที่ถามในความคิดเห็นของโพสต์ของ OP:

ในการบังคับให้มุมมองปรากฏในแนวที่กำหนดให้ใส่สิ่งต่อไปนี้ใน viewWillAppear:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
    UIViewController *c = [[UIViewController alloc]init];
    [self presentModalViewController:c animated:NO];
    [self dismissModalViewControllerAnimated:NO];
}

มันเป็นการแฮ็กเล็กน้อย แต่สิ่งนี้บังคับUIViewControllerให้นำเสนอในแนวตั้งแม้ว่าตัวควบคุมก่อนหน้าจะเป็นแนวนอนก็ตาม

อัปเดตสำหรับ iOS7

วิธีการข้างต้นเลิกใช้แล้วดังนั้นสำหรับ iOS 7 ให้ใช้สิ่งต่อไปนี้:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
     UIViewController *c = [[UIViewController alloc]init];
     [c.view setBackgroundColor:[UIColor redColor]];
     [self.navigationController presentViewController:c animated:NO completion:^{
            [self.navigationController dismissViewControllerAnimated:YES completion:^{
            }];
     }];
}

ที่น่าสนใจในขณะที่เขียนไม่ว่าจะเป็นของขวัญหรือการเลิกจ้างต้องเป็นภาพเคลื่อนไหว หากไม่มีคุณจะได้หน้าจอสีขาว ไม่รู้ว่าทำไมสิ่งนี้ถึงใช้งานได้ แต่มันทำได้! เอฟเฟกต์ภาพจะแตกต่างกันไปขึ้นอยู่กับสิ่งที่เคลื่อนไหว


ขอบคุณฉันจะลองดูเมื่อฉันมีเวลาว่างไม่กี่นาที
Lope

@RohanAgarwal มันทำงานได้ตามที่โฆษณาฉันใช้ที่นี่ แต่คุณต้องติดตั้งโค้ดของคำตอบที่ยอมรับด้วยไม่เช่นนั้นจะใช้ไม่ได้
Dennis Munsie

2
มีใครคิดวิธีทำให้มันทำงานกับภาพเคลื่อนไหวการหมุนที่ถูกต้องในเวลาเดียวกัน? มันสั่นเล็กน้อยที่เห็นว่ามันเปลี่ยนจากแนวตั้งเป็นแนวนอนโดยไม่มีภาพเคลื่อนไหว มันได้ผลเพียงหวังว่าจะทำให้มันทำงานได้ดีขึ้นเล็กน้อย
Dennis Munsie

@ Craig Watkinson มันไม่ทำงานในสตอรี่บอร์ด และ presentModalViewController และเลิกใช้งาน ModalViewControllerAnimate จะเลิกใช้งานหาก iam ใช้ presentVirecontroller มันจะไม่ทำงานโปรดช่วยฉันด้วย
Kalpesh

1
สำหรับ ios8 dischargeViewController ฉันพบว่าการเรียก [NWSAppDelegate sharedInstance] .window.rootViewController = nil; [NWSAppDelegate sharedInstance] .window.rootViewController = previousRootController ทำงานได้ดี
Alexey

36

ดังนั้นฉันจึงพบปัญหาเดียวกันเมื่อแสดงมุมมองโมดอลในแนวตั้งเท่านั้น โดยปกติฉันจะสร้าง a UINavigationControllerตั้งค่าviewControllerเป็นrootViewControllerแล้วแสดงUINavigationControllerเป็นมุมมองโมดอล แต่ด้วย iOS 6 viewControllerตอนนี้จะถาม navigationController สำหรับการวางแนวอินเทอร์เฟซที่รองรับ (ซึ่งโดยค่าเริ่มต้นตอนนี้เป็นทั้งหมดสำหรับ iPad และทุกอย่างยกเว้นสำหรับ iPhone)

วิธีแก้ไข : ฉันต้อง subclass UINavigationControllerและแทนที่วิธีการ autorotation ชนิดของง่อย

- (BOOL)shouldAutorotate {
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
// pre-iOS 6 support 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}

1
ไม่ได้ผลกับฉัน ฉันมีรหัสนี้พร้อมกับการตั้งค่า global สำหรับการวางแนวทั้งหมด
phil88530

2
supportInterfaceOrientations ควรส่งคืน NSUInteger ไม่ใช่ BOOL ดูdeveloper.apple.com/library/ios/#featuredarticles/…
tomwhipple

มันใช้งานได้สำหรับฉันมันเป็น
tabbarcontroller

FWIW ฉันต้องไปเส้นทางนี้เช่นกัน ... ขอบคุณ.
Steve N

15

iOS 5

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

iOS 6

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations{

    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2

    //    return UIInterfaceOrientationMaskPortrait; 
    //    or
          return 2;
}

ยอดเยี่ยม! ต้องอยู่ด้านบนสุดของชุดข้อความนี้ เพราะเป็นวิธีที่ง่ายที่สุดในการแก้ปัญหา
Alex

@Roshan Jalgaonkar ใน ios 6 มันใช้ไม่ได้สำหรับฉันฉันต้องการเพียงภาพบุคคลโดยมีปุ่มโฮมลงฉันจะตั้งค่า UIOrientation นี้ได้อย่างไร ....
Karthik

@Karthik คุณต้องเปิดใช้งานการหมุนที่รองรับในเป้าหมายของแอปเพื่อให้สิ่งนี้ทำงานได้
Alejandro Iván

10

ฉันไม่เห็นด้วยกับคำตอบของ @aprato เนื่องจากวิธีการหมุน UIViewController ได้รับการประกาศเป็นหมวดหมู่เองจึงส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนดหากคุณแทนที่ในหมวดหมู่อื่น ปลอดภัยกว่าที่จะแทนที่พวกเขาในคลาสย่อย UINavigationController (หรือ UITabBarController)

นอกจากนี้สิ่งนี้ไม่ครอบคลุมสถานการณ์ที่คุณผลัก / นำเสนอ / ป๊อปจากมุมมองแนวนอนไปเป็นแนวตั้งเท่านั้นหรือในทางกลับกัน ในการแก้ไขปัญหาที่ยากลำบากนี้ (Apple ไม่เคยกล่าวถึง) คุณควร:

ใน iOS <= 4 และ iOS> = 6:

UIViewController *vc = [[UIViewController alloc]init];
[self presentModalViewController:vc animated:NO];
[self dismissModalViewControllerAnimated:NO];
[vc release];

ใน iOS 5:

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];

สิ่งเหล่านี้จะบังคับให้ UIKit ประเมิน shouldAutorotate, supportedInterfaceOrientations และอื่น ๆ อีกครั้ง


2
ข้อขัดข้องประการแรกสำหรับฉันโดยไม่คำนึงถึงเวอร์ชัน iOS บอกว่าไม่ควรเรียกเลิกก่อนที่ปัจจุบันจะเสร็จสิ้น
arsenius

@arsenius คุณสามารถโพสต์ตัวอย่างวิธีการใช้งานได้หรือไม่? ตราบใดที่มันไม่ใช่ภาพเคลื่อนไหวก็ไม่ควรมีปัญหาที่คุณพูดถึง
Rafael Nobre

ฉันยังใส่ตัวอย่างที่สองลงใน viewDidAppear และมันก็ไม่ช่วยอะไรสถานการณ์ของฉันบน iOS 6 คำถามอยู่ที่นี่: stackoverflow.com/questions/15654339/…
arsenius

ขออภัยความคิดเห็นสุดท้ายที่นี่ การย้ายโค้ด iOS 5 ไปที่ viewDidAppear จะสร้างการวนซ้ำแบบไม่สิ้นสุดโดยมีเอาต์พุตนี้: - [UIApplication beginIgnoringInteractionEvents] มากเกินไป ละเว้น
arsenius

3

ฉันมีแนวทางที่ดีมากในการผสมhttps://stackoverflow.com/a/13982508/2516436และhttps://stackoverflow.com/a/17578272/2516436

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
    NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;


    if(self.window.rootViewController){
        UIViewController *presentedViewController = [self topViewControllerWithRootViewController:self.window.rootViewController];
        orientations = [presentedViewController supportedInterfaceOrientations];
    }

    return orientations;
}

- (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;
    }
}

และส่งคืนทิศทางที่คุณต้องการสนับสนุนสำหรับ UIViewController แต่ละตัว

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

1

ฉันมีแอปสากลที่ค่อนข้างซับซ้อนโดยใช้ UISplitViewController และ UISegmentedController และมีมุมมองบางอย่างที่ต้องนำเสนอในแนวนอนโดยใช้ presentViewControllerไฟล์. ด้วยวิธีการที่แนะนำข้างต้นฉันสามารถทำให้ iPhone ios 5 & 6 ทำงานได้อย่างเป็นที่ยอมรับ แต่ด้วยเหตุผลบางประการ iPad ก็ปฏิเสธที่จะนำเสนอเป็นแนวนอน ในที่สุดฉันก็พบวิธีง่ายๆ (ใช้งานได้หลังจากอ่านและลองผิดลองถูกมาหลายชั่วโมง) ที่ใช้ได้กับทั้งอุปกรณ์และ ios 5 & 6

ขั้นตอนที่ 1) บนคอนโทรลเลอร์ระบุการวางแนวที่ต้องการ (มากหรือน้อยตามที่ระบุไว้ข้างต้น)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    NSInteger mask = UIInterfaceOrientationMaskLandscape;
    return mask;

}

ขั้นตอนที่ 2) สร้างคลาสย่อย UINavigationController อย่างง่ายและใช้วิธีการต่อไปนี้

-(BOOL)shouldAutorotate {
        return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
        return UIInterfaceOrientationMaskLandscape;
}

ขั้นตอนที่ 3) นำเสนอ viewController ของคุณ

vc = [[MyViewController alloc]init];
MyLandscapeNavigationController *myNavigationController = [[MyLandscapeNavigationController alloc] initWithRootViewController:vc];
[self myNavigationController animated:YES completion:nil];

หวังว่านี่จะเป็นประโยชน์กับใครบางคน


1

ไม่น่าเบื่อที่นี่ แต่คุณจะใจดีมากที่จะแบ่งปันคลาสย่อยของคุณหรือไม่? ขอขอบคุณ.

แก้ไข: ในที่สุดฉันก็ทำได้คลาสย่อยก็ตายง่ายที่จะทำ ฉันต้องประกาศnavigationControllerในAppDelegateas UINavigationControllerSubclassแทนค่าเริ่มต้นUINavigationControllerจากนั้นแก้ไขคลาสย่อยของคุณด้วย:

- (BOOL)shouldAutorotate {
    return _shouldRotate;
}

ฉันจึงสามารถตั้งค่ามุมมองที่ต้องการหมุนหรือไม่ก็ได้โดยโทรไปที่ viewDidLoad

_navController = (UINavigationController *)self.navigationController;
[_navController setShouldRotate : YES / NO]

หวังว่าการปรับแต่งนี้จะช่วยผู้อื่นได้เช่นกันขอบคุณสำหรับเคล็ดลับ!

เคล็ดลับ: ใช้ประโยชน์จากไฟล์

- (NSUInteger)supportedInterfaceOrientations

ในตัวควบคุมมุมมองของคุณดังนั้นคุณจะไม่ต้องมีมุมมองแนวตั้งที่ต้องการในแนวนอนหรือในทางกลับกัน


0

ฉันไม่ได้ทดสอบด้วยตัวเอง แต่เอกสารระบุว่าตอนนี้คุณสามารถแทนที่วิธีการเหล่านั้นได้: supportedInterfaceOrientationsและpreferredInterfaceOrientationForPresentation.

คุณสามารถบรรลุสิ่งที่คุณต้องการ y การตั้งค่าเฉพาะการวางแนวที่คุณต้องการในวิธีการเหล่านั้น


0

คำตอบโดยใช้คลาสย่อยหรือหมวดหมู่เพื่อให้ VCs ภายในคลาส UINavigationController และ UITabBarController ทำงานได้ดี การเรียกใช้โมดอลแนวตั้งเท่านั้นจากคอนโทรลเลอร์แถบแนวนอนล้มเหลว หากคุณจำเป็นต้องทำเช่นนี้แล้วใช้เคล็ดลับของการแสดงและซ่อนไม่เคลื่อนไหวมุมมองกิริยา แต่ทำมันในวิธี viewDidAppear มันไม่ได้ผลสำหรับฉันใน viewDidLoad หรือ viewWillAppear

นอกเหนือจากนั้นโซลูชันข้างต้นยังใช้ได้ดี


0

สำหรับ Monotouch คุณสามารถทำได้ด้วยวิธีนี้:

public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
    {
    return UIInterfaceOrientationMask.LandscapeRight;
}

public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation()
    {
    return UIInterfaceOrientation.LandscapeRight;
}

0

ฉันเห็นคำตอบมากมาย แต่ไม่ได้รับแนวคิดและคำตอบที่เฉพาะเจาะจงเกี่ยวกับการวางแนว แต่เห็นลิงก์เข้าใจการวางแนวและลบการหมุนอย่างแรงสำหรับ ios6

http://www.disalvotech.com/blog/app-development/iphone/ios-6-rotation-solution/

ฉันคิดว่ามันช่วยเต็มที่


-1

เพียงไปที่ project.plist จากนั้นเพิ่มการวางแนวอินเตอร์เฟซที่รองรับจากนั้นเพิ่มเฉพาะ Portrait (ปุ่มโฮมด้านล่าง) และ Portrait (ปุ่มโฮมด้านบน)

คุณสามารถเพิ่มหรือลบการวางแนวได้ตามความต้องการของโครงการ

ขอบคุณ


1
เกี่ยวกับตัวควบคุมมุมมองเฉพาะไม่ใช่สำหรับแอปพลิเคชันทั้งหมด
Muhammad Rizwan

-2

1) ตรวจสอบการตั้งค่าโครงการและ info.plist ของคุณและตรวจสอบให้แน่ใจว่าได้เลือกเฉพาะการวางแนวที่คุณต้องการเท่านั้น

2) เพิ่มวิธีการต่อไปนี้ในตัวควบคุมมุมมองด้านบนสุดของคุณ (ตัวควบคุมการนำทาง / ตัวควบคุมแถบแถบ)

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;

}

3) เพิ่มวิธีการต่อไปนี้ให้กับตัวแทนแอปของคุณ

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;

}

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    return UIInterfaceOrientationMaskPortrait;

}

-3

ใส่ไว้ในไฟล์. m ของแต่ละไฟล์ที่ViewControllerคุณไม่ต้องการหมุน:

- (NSUInteger)supportedInterfaceOrientations
{
    //return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
    return UIInterfaceOrientationMaskPortrait;
}

ดูที่นี่สำหรับข้อมูลเพิ่มเติม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.