จะบังคับมุมมองการวางแนวของคอนโทรลเลอร์ใน iOS 8 ได้อย่างไร?


149

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

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];

แต่นี่คือความล้มเหลวใน iOS 8 นอกจากนี้ฉันได้เห็นคำตอบบางอย่างในกองล้นที่คนแนะนำว่าเราควรหลีกเลี่ยงวิธีนี้จาก iOS 8 เป็นต้นไป

เพื่อให้เฉพาะเจาะจงมากขึ้นแอปพลิเคชันของฉันเป็นแอปพลิเคชันที่เป็นสากล มีตัวควบคุมทั้งหมดสามตัว

  1. ตัวควบคุม First View - มันควรรองรับการหมุนใน iPad และแนวตั้งเท่านั้น (ปุ่มโฮมลง) ใน iPhone

  2. ตัวควบคุมมุมมองที่สอง - มันควรรองรับเฉพาะแนวนอนในทุกสภาวะ

  3. ตัวควบคุมมุมมองที่สาม - ควรสนับสนุนแนวนอนเท่านั้นในทุกสภาวะ

เรากำลังใช้ตัวควบคุมทิศทางสำหรับการนำทางหน้าเว็บ จากตัวควบคุมมุมมองแรกในการดำเนินการคลิกปุ่มเราจะผลักดันหนึ่งในกองซ้อน ดังนั้นเมื่อตัวควบคุมมุมมองที่สองมาถึงโดยไม่คำนึงถึงการวางแนวอุปกรณ์แอปควรล็อคในแนวนอนเท่านั้น

ด้านล่างเป็นของฉันshouldAutorotateและsupportedInterfaceOrientationsวิธีการในตัวควบคุมมุมมองที่สองและสาม

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

มีวิธีแก้ปัญหาสำหรับวิธีนี้หรือวิธีที่ดีกว่าในการล็อกตัวควบคุมมุมมองโดยเฉพาะใน iOS 8 โปรดช่วย !!


การใช้วิธีที่คุณกล่าวถึงในVC ที่นำเสนอควรใช้งานได้ (อย่างน้อยนั่นคือประสบการณ์ของฉันใน iOS 8) บางทีการตั้งค่าเฉพาะของคุณอาจทำให้เกิดปัญหา
Vladimir Gritsenko

อาจเป็นเพราะฉันสามารถทำให้คำถามชัดเจนขึ้นเล็กน้อย ฉันจะแก้ไขคำถามเล็กน้อย
Rashmi Ranjan mallick

@VladimirGritsenko: โปรดตรวจสอบตอนนี้ ฉันแก้ไขมันแล้ว
Rashmi Ranjan mallick

รหัสในคำถามไม่ได้ใช้สแต็คของตัวควบคุมการนำทาง แต่เป็นการนำเสนอ modal ดังนั้นจึงยังไม่ชัดเจนว่าคุณกำลังทำอะไรอยู่ ฉันจะบอกว่าในรหัสของเราคืน YES จาก shouldAutoRotate และกลับทิศทางที่ต้องการจากการสนับสนุน InInterfaceOrientations ในVC ที่นำเสนออย่างถูกต้อง orients ที่ VC
Vladimir Gritsenko

มันไม่ใช่ความล้มเหลวจริงๆมันเป็นเพียงการเปลี่ยนแปลงครั้งใหญ่ในแนวคิด ไม่ว่าจะเป็นการเปลี่ยนแปลงที่ดีเป็นอีกหัวข้อทั้งหมด
Kegluneq

คำตอบ:


315

สำหรับ iOS 7 - 10:

Objective-C:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];

สวิฟท์ 3:

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()

เพียงเรียกใช้ใน- viewDidAppear:ตัวควบคุมมุมมองที่นำเสนอ


61
นี่ไม่ใช่ API ส่วนตัว นี่คือไม่ปลอดภัยการใช้งานของ API คุณไม่ได้ใช้วิธีการส่วนตัว แต่ใช้ 'สิ่งภายใน' หาก Apple เปลี่ยนค่าสำหรับ "การวางแนว" มันจะล้มเหลว ที่แย่กว่านั้น: หาก Apple เปลี่ยนความหมายของค่า "การวางแนว" คุณไม่ทราบว่าคุณกำลังเปลี่ยนแปลงการตั้งค่าอย่างหนัก
sonxurxo

4
การเคลื่อนไหวปิดการใช้งานใส่ [UIView setAnimationsEnabled:NO];ในviewWillAppearและ[UIView setAnimationsEnabled:YES];ใน viewDidAppearที่เกี่ยวข้อง: stackoverflow.com/a/6292506/88597
ohho

3
แฮ็คที่ดี แต่ปัญหาที่เกิดขึ้นนั่นคือไม่ได้ทำการยิง ROTateFromInterfaceOrientation หลังจากตั้งค่าการวางแนวใหม่ (ถอนหายใจ)
loretoparisi

2
ใน iOS 9.2 นี่เป็นเพียงการเปลี่ยนทิศทาง แต่ไม่ล็อค
Mark13426

2
สำหรับทุกคนที่มีสิ่งนี้ทำงานได้ดี 90% ของเวลาและรถอีก 10% ของเวลาโทรนี้หลังจากตั้งค่าการวางแนว:[UINavigationController attemptRotationToDeviceOrientation];
อัลเบิร์ต Renshaw

93

หมุนปฐมนิเทศมีความซับซ้อนน้อยมากขึ้นถ้าคุณเป็นภายในหรือUINavigationController UITabBarControllerปัญหาคือว่าถ้าตัวควบคุมมุมมองถูกฝังอยู่ในหนึ่งในตัวควบคุมเหล่านี้การนำทางหรือตัวควบคุมแถบแท็บจะมีความสำคัญกว่าและทำการตัดสินใจเกี่ยวกับระบบอัตโนมัติและการวางแนวที่รองรับ

ฉันใช้ส่วนขยาย 2 ต่อไปนี้บน UINavigationController และ UITabBarController เพื่อดูตัวควบคุมที่ฝังอยู่ในตัวควบคุมเหล่านี้เพื่อทำการตัดสินใจ

ให้พลังควบคุมดู!

สวิฟท์ 2.3

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> Int {
        return visibleViewController.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

extension UITabBarController {
    public override func supportedInterfaceOrientations() -> Int {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

สวิฟท์ 3

extension UINavigationController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
    }
}

extension UITabBarController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

ตอนนี้คุณสามารถแทนที่supportedInterfaceOrientationsวิธีการหรือคุณสามารถแทนที่shouldAutoRotateในตัวควบคุมมุมมองที่คุณต้องการล็อคมิฉะนั้นคุณสามารถออกจากการแทนที่ในตัวควบคุมมุมมองอื่น ๆ ที่คุณต้องการที่จะสืบทอดพฤติกรรมการวางแนวเริ่มต้นที่ระบุไว้ใน Plist ของแอพ

ปิดใช้งานการหมุน

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

ล็อคการวางแนวเฉพาะ

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}

ในทางทฤษฎีสิ่งนี้ควรใช้ได้กับลำดับชั้นของตัวควบคุมมุมมองที่ซับซ้อนทั้งหมด แต่ฉันสังเกตเห็นปัญหากับ UITabBarController ด้วยเหตุผลบางอย่างมันต้องการใช้ค่าการวางแนวเริ่มต้น ดูโพสต์บล็อกต่อไปนี้หากคุณสนใจที่จะเรียนรู้เกี่ยวกับวิธีแก้ไขปัญหา:

ล็อคการหมุนหน้าจอ


1
ฉันรู้ว่านี่เป็นโพสต์เก่ามาก แต่คุณจะใส่รหัสส่วนขยายที่ไหน
dwinnbrown

7
การทำเครื่องหมายลงสำหรับ Swift จะตอบเฉพาะคำถาม Objective-C เท่านั้น
Charlie Scott-Skinner

17
นี่เป็นทางออกที่ดีสำหรับ Swift และ ObjC ไม่เข้าใจว่าทำไมคนถึงลงคะแนน คุณมีความคิดและการเขียนโค้ดนั้นง่ายมาก ทำไมบ่น
Zhao

2
@Krodak ในส่วนขยายลองเปลี่ยน "-> Int" เป็น "-> UIInterfaceOrientationMask" เคล็ดลับสำหรับฉัน
the_pantless_coder

2
ความคิดและรหัสนั้นสมบูรณ์แบบฉันชอบ แต่มีปัญหาเมื่อใช้ UINavigationController และย้อนกลับจาก UIViewController ในการแสดงในแนวนอนเป็นแนวที่ต้องแสดงในแนวตั้ง ความคิดใด ๆ
CrisGriega

24

นี่คือสิ่งที่ได้ผลสำหรับฉัน:

https://developer.apple.com/library//ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/clm/UIViewController/attemptRotationToDeviceOrientation

เรียกมันใน method viewDidAppear ของคุณ

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [UIViewController attemptRotationToDeviceOrientation];
}

3
มีประโยชน์มากถ้าอุปกรณ์หมุนไปแล้วและคุณต้องหมุนคอนโทรลเลอร์มุมมองของคุณ
avdyushin

2
คำตอบที่ดี เมื่อใช้ร่วมกับคำตอบที่ได้รับการยอมรับมันใช้ได้ดีสำหรับฉันทุกครั้งใน Swift และ iOS 9+
AndyDunn

1
แม้ว่าฉันคิดว่ามันไม่ใช่คำตอบสำหรับคำถามที่ถาม แต่มันช่วยฉันได้จริงๆ
Abdurrahman Mubeen Ali

21

ฉันพบว่าถ้ามันเป็นตัวควบคุมมุมมองที่นำเสนอคุณสามารถแทนที่ preferredInterfaceOrientationForPresentation

สวิฟท์:

override func supportedInterfaceOrientations() -> Int {
  return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
  return UIInterfaceOrientation.LandscapeLeft
}

override func shouldAutorotate() -> Bool {
  return false
}

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

1
@CliftonLabrum คุณทำอย่างอื่นเพื่อบังคับเฉพาะภูมิทัศน์หรือไม่? ใช้รหัสเดียวกันตัวควบคุมมุมมองยังคงสามารถหมุนไปยังทิศทางอื่นได้
Crashalot

ฉันรู้ในภายหลังว่า - คุณถูกต้อง ฉันยังไม่พบวิธีแก้ไข
Clifton Labrum

1
สิ่งนี้ใช้ได้สำหรับฉัน ฉันสามารถเก็บ View Controller เดียวไว้ในโหมด Portrait ได้โดยใช้รหัสนี้ (แทนที่ Landscape ด้วย Portrait) +1
Mark Barrasso

ใช่ สิ่งนี้ใช้ได้สำหรับฉันเช่นกันใน Xcode 7.3 และ Swift 2.2 แต่ยังคงต้องกำหนดแอปพลิเคชัน func สำหรับอินเทอร์เฟซการเชื่อมต่อระหว่าง Windows ใน AppDelegate
charles.cc.hsu

15

วิธีนี้ใช้ได้กับฉันในSwift 2 iOS 8.x:

PS (วิธีนี้ไม่จำเป็นต้องแทนที่ฟังก์ชั่นการวางแนวเช่นควรหมุนอัตโนมัติในทุก viewController เพียงหนึ่งวิธีใน AppDelegate)

ตรวจสอบ "ต้องการเต็มหน้าจอ" ในข้อมูลโครงการทั่วไปของคุณ ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นใน AppDelegate.swift ให้สร้างตัวแปร:

var enableAllOrientation = false

ดังนั้นใส่ func นี้ด้วย:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
        if (enableAllOrientation == true){
            return UIInterfaceOrientationMask.All
        }
        return UIInterfaceOrientationMask.Portrait
}

ดังนั้นในทุกชั้นในโครงการของคุณคุณสามารถตั้งค่า var นี้ใน viewWillAppear:

override func viewWillAppear(animated: Bool)
{
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.enableAllOrientation = true
}

หากคุณต้องการเลือกตามประเภทของอุปกรณ์คุณสามารถทำได้:

override func viewWillAppear(animated: Bool)
    {
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        switch UIDevice.currentDevice().userInterfaceIdiom {
        case .Phone:
        // It's an iPhone
           print(" - Only portrait mode to iPhone")
           appDelegate.enableAllOrientation = false
        case .Pad:
        // It's an iPad
           print(" - All orientation mode enabled on iPad")
           appDelegate.enableAllOrientation = true
        case .Unspecified:
        // Uh, oh! What could it be?
           appDelegate.enableAllOrientation = false
        }
    }

คำอธิบายที่ดีมาก
Mihir Oza

11

ก่อนอื่น - นี่เป็นความคิดที่ไม่ดีโดยทั่วไปมีบางอย่างผิดปกติเกิดขึ้นกับสถาปัตยกรรมแอปของคุณ แต่sh..t happensถ้าเป็นเช่นนั้นคุณสามารถลองทำสิ่งต่อไปนี้ได้:

final class OrientationController {

    static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]

    // MARK: - Public

    class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask) {
        OrientationController.allowedOrientation = [orientationIdiom]
    }

    class func forceLockOrientation(_ orientation: UIInterfaceOrientation) {
        var mask:UIInterfaceOrientationMask = []
        switch orientation {
            case .unknown:
                mask = [.all]
            case .portrait:
                mask = [.portrait]
            case .portraitUpsideDown:
                mask = [.portraitUpsideDown]
            case .landscapeLeft:
                mask = [.landscapeLeft]
            case .landscapeRight:
                mask = [.landscapeRight]
        }

        OrientationController.lockOrientation(mask)

        UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
    }
}

กว่าใน AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // do stuff
    OrientationController.lockOrientation(.portrait)
    return true
}

// MARK: - Orientation

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return OrientationController.allowedOrientation
}

และเมื่อใดก็ตามที่คุณต้องการเปลี่ยนการวางแนวทำเช่น:

OrientationController.forceLockOrientation(.landscapeRight)

หมายเหตุ: บางครั้งอุปกรณ์อาจไม่อัปเดตจากการโทรดังกล่าวดังนั้นคุณอาจต้องทำดังต่อไปนี้

OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)

นั่นคือทั้งหมดที่


9

สิ่งนี้ควรใช้งานได้ตั้งแต่ iOS 6 ขึ้นไป แต่ฉันได้ทำการทดสอบบน iOS 8 เท่านั้นคลาสย่อยUINavigationControllerและแทนที่วิธีต่อไปนี้:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeRight;
}

- (BOOL)shouldAutorotate {
    return NO;
}

หรือถามตัวควบคุมมุมมองที่มองเห็นได้

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return self.visibleViewController.preferredInterfaceOrientationForPresentation;
}

- (BOOL)shouldAutorotate {
    return self.visibleViewController.shouldAutorotate;
}

และใช้วิธีการที่นั่น


ฉันเพิ่งทดสอบสิ่งนี้บนแอพของฉันใน Xcode 8.2.1 ที่ใช้ iOS 10.0 และใช้งานได้ เมนูเกมของฉันเป็นหน้าจอแรกและไม่หมุน มุมมองอื่น ๆ ทั้งหมดหมุน ที่สมบูรณ์แบบ! ให้มันขึ้นหนึ่ง ฉันต้องการเฉพาะฟังก์ชัน 'PreferredInterfaceOrientationForPresentation' ที่ได้รับจาก Mojo66
Philip Borges

9

นี่คือผลตอบรับต่อความคิดเห็นในคำตอบของ Sid Shahเกี่ยวกับวิธีปิดการใช้งานภาพเคลื่อนไหวโดยใช้:

[UIView setAnimationsEnabled:enabled];

รหัส:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:NO];
    [UIView setAnimationsEnabled:NO];

    // Stackoverflow #26357162 to force orientation
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:NO];
    [UIView setAnimationsEnabled:YES];
}

ฉันจะใช้สิ่งนี้กับ Portrait ได้อย่างไร
Muju

6

หากคุณใช้ navigationViewController คุณควรสร้าง superclass ของคุณเองสำหรับสิ่งนี้และแทนที่:

- (BOOL)shouldAutorotate {
  id currentViewController = self.topViewController;

  if ([currentViewController isKindOfClass:[SecondViewController class]])
    return NO;

  return YES;
}

สิ่งนี้จะปิดการใช้งานการหมุนในSecondViewControllerแต่ถ้าคุณกดSecondViewControllerเมื่ออุปกรณ์ของคุณอยู่ในแนวตั้งแนวตั้งจากนั้นSecondViewControllerของคุณจะปรากฏในโหมดแนวตั้ง

สมมติว่าคุณกำลังใช้กระดานเรื่องราว คุณต้องสร้างการทำคู่มือ ( วิธีการ ) และวิธี "onClick" ของคุณ:

- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender {
  NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
  [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
  [self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
}

สิ่งนี้จะบังคับให้วางแนวนอนก่อนที่คุณจะปิดใช้งานคุณสมบัติ super-class อัตโนมัติ


6

ในXcode 8วิธีการจะถูกแปลงเป็นคุณสมบัติดังนั้นการทำงานต่อไปนี้ด้วยSwift:

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIInterfaceOrientation.portrait
}

override public var shouldAutorotate: Bool {
    return true
}

สิ่งนี้ล็อคการวางแนวหรือไม่?
bnussey

1
@bnussey ฉันต้องการป้องกันการหมุนอัตโนมัติและอยู่ในportraitโหมดเสมอไม่ว่าการวางแนวบน iPad shouldAutorotateจะเป็นอย่างไรฉันจึงกลับมาจริงได้
Ali Momen Sani

4

ฉันได้ลองใช้วิธีแก้ปัญหาหลายอย่างแล้ว แต่สิ่งที่ใช้งานได้มีดังนี้

ไม่จำเป็นต้องแก้ไขinfo.plistใน iOS 8 และ 9

- (BOOL) shouldAutorotate {
    return NO;
}   

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
}

ทิศทางที่เป็นไปได้จากเอกสารของ Apple :

UIInterfaceOrientationUnknown

ไม่สามารถกำหนดทิศทางของอุปกรณ์ได้

UIInterfaceOrientationPortrait

อุปกรณ์อยู่ในโหมดแนวตั้งโดยอุปกรณ์ตั้งตรงและปุ่มโฮมที่ด้านล่าง

UIInterfaceOrientationPortraitUpsideDown

อุปกรณ์อยู่ในโหมดแนวตั้ง แต่กลับหัวกลับหางโดยที่อุปกรณ์ตั้งตรงและปุ่มโฮมที่ด้านบน

UIInterfaceOrientationLandscapeLeft

อุปกรณ์อยู่ในโหมดแนวนอนโดยอุปกรณ์ตั้งตรงและปุ่มโฮมทางด้านซ้าย

UIInterfaceOrientationLandscapeRight

อุปกรณ์อยู่ในโหมดแนวนอนโดยอุปกรณ์ตั้งตรงและปุ่มโฮมทางด้านขวา


3

การรวมกันของคำตอบ Sids และ Koreys เหมาะกับฉัน

การขยายตัวควบคุมการนำทาง:

extension UINavigationController {
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

จากนั้นปิดการใช้งานการหมุนในมุมมองเดียว

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

และหมุนไปในทิศทางที่เหมาะสมก่อนที่จะทำต่อ

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "SomeSegue")
    {
        let value = UIInterfaceOrientation.Portrait.rawValue;
        UIDevice.currentDevice().setValue(value, forKey: "orientation")
    }
}

คุณรู้หรือไม่ว่าสิ่งนี้อาจช่วยให้ปัญหาของฉันที่ตัวควบคุมมุมมองที่แสดงอยู่ในแนวนอนเป็นวินาทีก่อนที่มันจะหมุนเป็นแนวตั้งเหมือนที่ควรจะเป็นเสมอ คำถามอยู่ที่นี่: stackoverflow.com/questions/30693964/…
dwinnbrown

3

ทางออกด้านบน:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

ไม่ทำงานสำหรับฉันเมื่อฉันเรียกมันใน viewDidAppear ของตัวควบคุมมุมมองที่นำเสนอ อย่างไรก็ตามมันใช้งานได้เมื่อฉันเรียกมันใน PreparForSegue ในตัวควบคุมมุมมองการนำเสนอ

(ขออภัยมีชื่อเสียงไม่เพียงพอที่จะแสดงความคิดเห็นเกี่ยวกับการแก้ปัญหานั้นดังนั้นฉันต้องเพิ่มแบบนี้)


ฉันได้ทำงานนี้ แต่เมื่อไปจากตัวควบคุมวิวทิวทัศน์ไปยังตัวควบคุมมุมมองแนวตั้งตัวควบคุมมุมมองที่ควรแสดงในแนวตั้งจะแสดงสั้น ๆ ในแนวนอนก่อนที่จะหมุนด้วยตัวเอง หากใครรู้วิธีที่จะช่วยคำถามของฉันได้ที่นี่: stackoverflow.com/questions/30693964/…
dwinnbrown

@dwinnbrown ที่ viewDidAppear ตัวควบคุมมุมมองมองเห็นได้แล้ว อาจลองจาก viewDidLoad แทน
Crashalot

@Crashalot ฉันได้แก้ไขสิ่งนี้แล้ว โปรดดูคำตอบที่ฉันทำเครื่องหมายว่าถูกต้อง
dwinnbrown

@dwinnbrown ลิงก์ไปยังคำถามของคุณตายแล้ว อัปเดต? ขอบคุณ!
Crashalot

@Crashalot ชุมชนถูกลบ แต่ฉันได้โหวตให้ยกเลิกการลบ ฉันจะแจ้งให้คุณทราบเร็ว ๆ นี้
dwinnbrown

3

[iOS9 +] หากใครลากลงมาที่นี่เพราะไม่มีวิธีแก้ไขปัญหาด้านบนทำงานและถ้าคุณแสดงมุมมองที่คุณต้องการเปลี่ยนการวางแนวโดยทำต่อคุณอาจต้องตรวจสอบเรื่องนี้

ตรวจสอบประเภทงานนำเสนอของ segue ของคุณ ฉันเป็น 'มากกว่าบริบทปัจจุบัน' เมื่อฉันเปลี่ยนเป็นหน้าจอเต็มจอจะทำงาน

ขอบคุณ @GabLeRoux ฉันพบโซลูชันนี้

  • การเปลี่ยนแปลงนี้จะทำงานเฉพาะเมื่อรวมกับโซลูชันด้านบน

2

ความต้องการของฉันคือ

  1. ล็อคมุมมองทั้งหมดในโหมดแนวตั้ง
  2. ใช้AVPlayerViewControllerสำหรับเล่นวิดีโอ

เมื่อวิดีโอกำลังเล่นหากเป็นแนวนอนแล้วให้หน้าจอหมุนแนวนอนไปทางขวาและแนวนอนด้านซ้าย หากเป็นแนวตั้งให้ล็อคมุมมองในโหมดแนวตั้งเท่านั้น

ก่อนกำหนดsupportedInterfaceOrientationsForWindowในAppDelegate.swift

var portrait = true
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if portrait {
        return .Portrait
    } else {
        return .Landscape
    }
}

ประการที่สองในตัวควบคุมมุมมองหลักของคุณกำหนดฟังก์ชั่นต่อไปนี้

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    print("\(#function)")
    return .Portrait
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return .Portrait
}

override func shouldAutorotate() -> Bool {
    return false
}

จากนั้นคุณจะต้องคลาสย่อย AVPlayerViewController

class MyPlayerViewController: AVPlayerViewController {

    var size: CGSize?

    var supportedOrientationMask: UIInterfaceOrientationMask?
    var preferredOrientation: UIInterfaceOrientation?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let size = size {
            if size.width > size.height {
                self.supportedOrientationMask =[.LandscapeLeft,.LandscapeRight]
                self.preferredOrientation =.LandscapeRight
            } else {
                self.supportedOrientationMask =.Portrait
                self.preferredOrientation =.Portrait
            }
        }
    }

แทนที่ฟังก์ชันทั้งสามนี้ใน MyPlayerViewController.swift

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return self.supportedOrientationMask!
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return self.preferredOrientation!
}

เนื่องจากผู้ใช้อาจหมุนแนวนอนอุปกรณ์ไปทางซ้ายหรือแนวนอนขวาเราต้องตั้งค่าการหมุนอัตโนมัติให้เป็นจริง

override func shouldAutorotate() -> Bool {
    return true
}

สุดท้ายสร้างMyPlayerViewControllerอินสแตนซ์ในตัวควบคุมมุมมองของคุณและตั้งค่าขนาดคุณสมบัติ

let playerViewController = MyPlayerViewController()

// Get the thumbnail  
let thumbnail = MyAlbumFileManager.sharedManager().getThumbnailFromMyVideoMedia(......)

let size = thumbnail?.size
playerViewController.size = size

เริ่มต้นการเล่นของคุณด้วยที่เหมาะสมแล้วกำหนดเครื่องเล่นของคุณไปvideoUrl playerViewControllerการเข้ารหัสมีความสุข!



1

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

- (void) viewWillAppear:(BOOL)animated
{
    [UIViewController attemptRotationToDeviceOrientation];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

-(BOOL)shouldAutorotate
{
    return NO;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft;
}

สำหรับตัวอย่างนี้คุณจะต้องตั้งค่าการจัดแนวอุปกรณ์ที่อนุญาตเป็น 'Landscape Left' ในการตั้งค่าโครงการของคุณ (หรือโดยตรงใน info.plist ) เพียงแค่เปลี่ยนการวางแนวเฉพาะที่คุณต้องการบังคับถ้าคุณต้องการสิ่งอื่นที่ไม่ใช่LandscapeLeft.

กุญแจสำคัญสำหรับฉันคือการattemptRotationToDeviceOrientationโทรเข้าviewWillAppear- หากไม่มีมุมมองจะหมุนไม่ถูกต้องหากไม่มีการหมุนอุปกรณ์


วิธีการเลิก
Saqib Omer

1

ตามคำตอบของ Korey Hinton

สวิฟท์ 2.2:

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return visibleViewController!.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController!.shouldAutorotate()
    }
}


extension UITabBarController {
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

ปิดใช้งานการหมุน

override func shouldAutorotate() -> Bool {
    return false
}

ล็อคการวางแนวเฉพาะ

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait
}

1

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

ฉันสร้างproject -c project-github.com/GabLeRoux/RotationLockInTabbedViewChildต่อไปนี้พร้อมตัวอย่างการทำงานของTabbedViewControllerมุมมองลูกหนึ่งที่อนุญาตให้หมุนและมุมมองลูกอื่น ๆ ถูกล็อคในแนวตั้ง

มันไม่สมบูรณ์ แต่การทำงานและความคิดเดียวกันควรจะทำงานสำหรับชนิดอื่น ๆ NavigationViewControllerของมุมมองรากเช่น :)

มุมมองลูกล็อคการวางแนวผู้ปกครอง


0

ตามวิธีแก้ปัญหาที่แสดงโดย @ sid-sha คุณต้องใส่ทุกอย่างในviewDidAppear:วิธีการมิฉะนั้นคุณจะไม่โดนdidRotateFromInterfaceOrientation:ไล่ออกดังนั้น:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
        interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
        NSNumber *value = [NSNumber numberWithInt:interfaceOrientation];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    }
}

0

ทางออกของฉัน

ในAppDelegate:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if let topController = UIViewController.topMostViewController() {
        if topController is XXViewController {
            return [.Portrait, .LandscapeLeft]
        }
    }
    return [.Portrait]
}

XXViewController เป็น ViewController ที่คุณต้องการรองรับโหมดแนวนอน

จากนั้นโซลูชันของ Sunny ShahจะทำงานXXViewControllerกับคุณบน iOS ทุกรุ่น:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

นี่คือฟังก์ชั่นยูทิลิตี้เพื่อค้นหา ViewController ที่ติดอันดับต้น ๆ

extension UIViewController {

    /// Returns the current application's top most view controller.
    public class func topMostViewController() -> UIViewController? {
        let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
        return self.topMostViewControllerOfViewController(rootViewController)
    }



    /// Returns the top most view controller from given view controller's stack.
    class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController? {
        // UITabBarController
        if let tabBarController = viewController as? UITabBarController,
           let selectedViewController = tabBarController.selectedViewController {
            return self.topMostViewControllerOfViewController(selectedViewController)
        }

        // UINavigationController
        if let navigationController = viewController as? UINavigationController,
           let visibleViewController = navigationController.visibleViewController {
            return self.topMostViewControllerOfViewController(visibleViewController)
        }

        // presented view controller
        if let presentedViewController = viewController?.presentedViewController {
            return self.topMostViewControllerOfViewController(presentedViewController)
        }

        // child view controller
        for subview in viewController?.view?.subviews ?? [] {
            if let childViewController = subview.nextResponder() as? UIViewController {
                return self.topMostViewControllerOfViewController(childViewController)
            }
        }

        return viewController
    }

}

0

ใช้สิ่งนี้เพื่อล็อคการวางแนวตัวควบคุมมุมมองทดสอบบน IOS 9:

// ล็อคการวางแนวแนวนอนให้ถูกต้อง

-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
    return UIInterfaceOrientationMaskLandscapeRight;
}

0

ฉันมีปัญหาเดียวกันและเสียเวลามากมายสำหรับมัน ดังนั้นตอนนี้ฉันมีทางออกของฉัน การตั้งค่าแอปของฉันเป็นเพียงการสนับสนุนแนว only.However หน้าจอบางอย่างใน app ของฉันจำเป็นต้องมีภูมิทัศน์ only.I แก้ไขได้โดยการมีตัวแปรisShouldRotateที่AppDelegate และฟังก์ชั่นที่AppDelegate :

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    if isShouldRotate == true {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

และในที่สุดเมื่อViewControllerAต้องการสถานะแนวนอน เพียงแค่ทำว่าก่อนที่จะผลักดัน / ปัจจุบันเพื่อViewControllerAกำหนดisShouldRotateไปจริง อย่าลืมเมื่อ pop / ยกเลิกการควบคุมกำหนดว่าisShouldRotateการเท็จที่viewWillDisappear


0

สำหรับฉันแล้ว VC ระดับสูงสุดจำเป็นต้องใช้การแทนที่การวางแนว การใช้ VC ลงไปในสแต็กจะไม่มีผลกระทบหาก VC ด้านบนไม่ได้ใช้งาน

VC-main
    |
    -> VC 2
        |
        -> VC 3

มีเพียง VC-Main เท่านั้นที่รับฟังเป็นหลักในการทดสอบของฉัน


0

ดูเหมือนว่าเจ้าที่นี่จะมีคำตอบมากมายเหลือเกินสำหรับฉัน ฉันต้องการบังคับให้วางแนวและจากนั้นย้อนกลับไปที่การวางแนวอุปกรณ์ แต่[UIViewController attemptRotationToDeviceOrientation];ก็ไม่ได้ผล สิ่งที่ซับซ้อนกว่านั้นก็คือฉันควรเพิ่มออโตโรโตเททให้เป็นเท็จโดยใช้คำตอบบางอย่างและไม่สามารถรับเอฟเฟกต์ที่ต้องการเพื่อหมุนกลับอย่างถูกต้องในทุกสถานการณ์

ดังนั้นนี่คือสิ่งที่ฉันทำ:

ก่อนที่จะกดคอนโทรลเลอร์ในการโทรในตัวสร้าง init ของเขาสิ่งนี้:

_userOrientation = UIDevice.currentDevice.orientation;
[UIDevice.currentDevice setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];
[self addNotificationCenterObserver:@selector(rotated:)
                               name:UIDeviceOrientationDidChangeNotification];

ดังนั้นฉันจึงบันทึกการวางแนวอุปกรณ์ล่าสุดและลงทะเบียนสำหรับเหตุการณ์การเปลี่ยนการวางแนว เหตุการณ์การเปลี่ยนทิศทางเป็นเรื่องง่าย:

- (void)rotated:(NSNotification*)notification {
    _userOrientation = UIDevice.currentDevice.orientation;
}

และในมุมมองการสลายตัวฉันเพิ่งบังคับกลับไปที่การวางแนวใด ๆ ที่ฉันมีในฐานะผู้ใช้การแจ้งเตือน:

- (void)onViewDismissing {
    super.onViewDismissing;
    [UIDevice.currentDevice setValue:@(_userOrientation) forKey:@"orientation"];
    [UIViewController attemptRotationToDeviceOrientation];
}

และสิ่งนี้จะต้องอยู่ที่นั่นด้วย:

- (BOOL)shouldAutorotate {
    return true;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

และยังมีตัวควบคุมการนำทางที่มีการมอบหมายให้ควรออโตโรทและสนับสนุนอินเทอร์เฟซการตรวจสอบ แต่ที่คนส่วนใหญ่มีอยู่แล้วฉันเชื่อ

ป.ล. : ขออภัยฉันใช้ส่วนขยายและคลาสพื้นฐาน แต่ชื่อมีความหมายมากดังนั้นแนวคิดจึงเป็นที่เข้าใจได้และจะสร้างส่วนขยายให้มากขึ้นเนื่องจากตอนนี้ยังไม่สวยมากนัก

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