วิธีการตรวจจับการเปลี่ยนแปลงการวางแนว?


148

ฉันกำลังใช้ Swift และฉันต้องการโหลด UIViewController เมื่อฉันหมุนไปสู่แนวนอนทุกคนสามารถชี้ให้ฉันไปในทิศทางที่ถูกต้องได้หรือไม่?

ฉันไม่พบสิ่งใดออนไลน์และสับสนเล็กน้อยจากเอกสารประกอบ


1
ฉันคิดว่า API ไม่เปลี่ยนแปลงดังนั้นควรเป็น "didRotateToOrientation" และ "willRotateToOrientation" อย่างนี้ลองดูในเอกสารประกอบของ Apple
David 'mArm' Ansermot

1
สวัสดี @ mArm.ch ขอบคุณสำหรับการตอบกลับอย่างรวดเร็ว! ดังนั้นฉันจะใช้สิ่งนี้ได้อย่างไร (นี่เป็นแอปแรกของฉัน ... ฉันใหม่สำหรับ IOS) :)
David

ฉันโพสต์ใหม่เป็นคำตอบสำหรับคนอื่น คุณสามารถยอมรับมันได้ไหมถ้ามันใช้ได้สำหรับคุณ
David 'mArm' Ansermot

คำตอบ:


194

นี่คือวิธีที่ฉันใช้งานได้:

ในAppDelegate.swiftภายในdidFinishLaunchingWithOptions ฟังก์ชั่นฉันใส่:

NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)

และจากนั้นภายใน AppDelegate class ฉันใส่ฟังก์ชั่นต่อไปนี้:

func rotated() {
    if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
        print("Landscape")
    }

    if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
        print("Portrait")
    }
}

หวังว่านี่ช่วยคนอื่นได้!

ขอบคุณ!


5
ฉันพยายามเพิ่ม addObserver ใน AppDelegate แต่ยังคงได้รับ SIGABRT ใน CoreFoundation ด้วยตัวเลือกที่ไม่รู้จัก อย่างไรก็ตามเมื่อฉันย้าย addObserver ไปยัง viewDidLoad ในมุมมองแรกของฉันมันทำงานได้อย่างสมบูรณ์ สำหรับข้อมูลถ้าใครเจอปัญหาเดียวกัน
FractalDoctor

1
ฉันใหม่ในการเขียนโค้ด แต่ไม่ควรselectorมีรูปแบบสตริงเป็น"rotated:"?
Chameleon

4
ฉันค่อนข้างแน่ใจว่าเฉพาะในกรณีที่คุณยอมรับข้อโต้แย้ง (ซึ่งrotated()ไม่ใช่)
เดวิด

26
ระวังเพราะUIDeviceOrientationมันเป็นสิ่งที่แตกต่างจากUIInterfaceOrientation.. นี่ก็เป็นเพราะUIDeviceOrientationตรวจจับคว่ำหน้าและเงยหน้าขึ้นมองซึ่งหมายความว่ารหัสของคุณสามารถข้ามระหว่างแนวตั้งและแนวนอนแบบสุ่มหากอุปกรณ์ของคุณวางอยู่บนพื้นผิวเกือบเรียบ แต่ไม่สม่ำเสมอเล็กน้อย กล้องของ 6 / 6s)
liamnichols

4
วิธีนี้จะไม่ทำงานหากโทรศัพท์ปิดการใช้งานการหมุนอัตโนมัติ
chengsam

178
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.orientation.isLandscape {
        print("Landscape")
    }
    if UIDevice.current.orientation.isFlat {
        print("Flat")
    } else {
        print("Portrait")
    }
}

71
สิ่งนี้จะถูกเรียกก่อนการหมุน หากคุณต้องการเช่นขนาดเฟรมหลังจากการหมุนการแก้ปัญหานี้จะไม่ทำงาน
โหวต

ไม่ทำงานในส่วนขยาย แนวนอนหรือแนวตั้งยังคงพิมพ์ "portraight"
TomSawyer

4
วิธีนี้จะไม่ทำงานหากโทรศัพท์ปิดการใช้งานการหมุนอัตโนมัติ
chengsam

5
บน iPad เนื่องจากคลาสมีขนาดเท่ากันทั้งในแนวนอนและแนวตั้งวิธีนี้ไม่เคยถูกเรียก
Jacky

สิ่งนี้จะล้มเหลวหากอุปกรณ์ส่งคืน isFlat developer.apple.com/documentation/uikit/uideviceorientation/…
CodeBender

57

ต้องการตรวจจับการหมุนในขณะที่ใช้กล้องด้วยAVFoundationและพบว่า & didRotate( เลิกใช้แล้ว ) & willTransitionวิธีการนี้ไม่น่าเชื่อถือสำหรับความต้องการของฉัน การใช้การแจ้งเตือนที่โพสต์โดย David ทำได้ แต่ไม่เป็นปัจจุบันสำหรับ Swift 3.x / 4.x

สวิฟต์ 4.2 เปลี่ยนชื่อการแจ้งเตือนแล้ว

มูลค่าการปิดยังคงเหมือนเดิมกับ Swift 4.0:

var didRotate: (Notification) -> Void = { notification in
        switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("Portrait")
        default:
            print("other")
        }
    }

วิธีตั้งค่าการแจ้งเตือนสำหรับ Swift 4.2 :

NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification,
                                       object: nil,
                                       queue: .main,
                                       using: didRotate)

หากต้องการยกเลิกการแจ้งเตือนสำหรับ Swift 4.2 :

NotificationCenter.default.removeObserver(self,
                                          name: UIDevice.orientationDidChangeNotification,
                                          object: nil)

เกี่ยวกับคำสั่งการคัดค้านความคิดเห็นเริ่มต้นของฉันทำให้เข้าใจผิดดังนั้นฉันจึงต้องการอัปเดต เท่าที่สังเกตการใช้งานของการอนุมานได้เลิกใช้ซึ่งจะเป็นสิ่งที่จำเป็นที่จะใช้@objc #selectorโดยใช้การปิดแทนสิ่งนี้สามารถหลีกเลี่ยงได้และตอนนี้คุณมีวิธีแก้ปัญหาที่ควรหลีกเลี่ยงความล้มเหลวเนื่องจากการเรียกตัวเลือกที่ไม่ถูกต้อง

ทุกอย่างด้านล่างที่นี่ล้าสมัยตั้งแต่ XCode 10 และ iOS 4.2

Swift 4.0 ด้วย Swift 4.0 Apple ได้สนับสนุนให้เราหลีกเลี่ยงการใช้#selectorวิธีการนี้จึงใช้บล็อกการทำให้เสร็จสมบูรณ์ในขณะนี้ วิธีนี้ยังใช้งานร่วมกับ Swift 3.x ได้และจะเป็นแนวทางที่แนะนำต่อไป

นี่คือคำเตือนของคอมไพเลอร์ที่คุณจะได้รับในโครงการ Swift 4.x หากคุณใช้#selectorฟังก์ชั่นอันเนื่องมาจากการไม่ใช้การ@objcอนุมาน:

ป้อนคำอธิบายรูปภาพที่นี่

รายการในวิวัฒนาการที่รวดเร็วในการเปลี่ยนแปลงนี้

ตั้งค่าการติดต่อกลับ:

// If you do not use the notification var in your callback, 
// you can safely replace it with _
    var didRotate: (Notification) -> Void = { notification in
        switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("Portrait")
        default:
            print("other")
        }
    }

ตั้งค่าการแจ้งเตือน:

NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange,
                                       object: nil,
                                       queue: .main,
                                       using: didRotate)

ฉีกมันลง:

NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)

4
คุณมีการอ้างอิงถึงที่ Apple พูดถึงการใช้ #selector ใน Swift 4 หรือไม่ ฉันต้องการอ่านว่าทำไมพวกเขาถึงพูดแบบนี้
jeffjv

@jeffjv แน่นอนฉันไม่มีลิงก์โดยตรงไปยังเอกสาร Apple แต่ฉันได้รวมภาพหน้าจอของคำเตือนคอมไพเลอร์ที่ XCode ให้หากคุณใช้วิธีการก่อนหน้านี้
CodeBender

1
ฉันได้เพิ่มลิงก์ไปยังวิวัฒนาการอย่างรวดเร็วที่กล่าวถึงการเปลี่ยนแปลง
CodeBender

1
@CodeBender: คำเตือนของคอมไพเลอร์ไม่ได้หมายถึงสิ่งที่คุณแนะนำ #selector ไม่ได้ถูกคิดค่าเสื่อมราคามีการอนุมาน "@objc" เท่านั้น ซึ่งหมายความว่าเมื่อใช้ฟังก์ชันเป็น #selector คุณต้องทำเครื่องหมายอย่างชัดเจนเพื่อให้คอมไพเลอร์จะสร้างรหัสที่ถูกต้องเพิ่มเติมเนื่องจากคอมไพเลอร์จะไม่ลองอนุมานจากการใช้งานของคุณอีกต่อไป ดังนั้นหากคุณเพิ่ม "@obj" ในการหมุน () func ในโซลูชัน Swift 3.0 ของคุณรหัสจะรวบรวมโดยไม่มีคำเตือน
Mythlandia

ขอบคุณ @Mythlandia ฉันได้อัปเดตคำตอบเพื่อแก้ไขความสับสนในข้อความเริ่มต้นของฉัน
CodeBender

19

การใช้-orientationคุณสมบัติของUIDeviceไม่ถูกต้อง (แม้ว่ามันจะสามารถทำงานได้ในกรณีส่วนใหญ่) และอาจนำไปสู่ข้อผิดพลาดบางอย่างเช่นUIDeviceOrientationพิจารณาการวางแนวของอุปกรณ์หากมันคว่ำหน้าหรือลงไม่มีคู่โดยตรงในUIInterfaceOrientationenum สำหรับสิ่งเหล่านั้น ค่า
นอกจากนี้หากคุณล็อกแอพของคุณในทิศทางเฉพาะ UIDevice จะให้การวางแนวอุปกรณ์โดยไม่คำนึงถึงสิ่งนั้น
ในอีกด้านหนึ่ง iOS8 ได้เลิกใช้interfaceOrientationทรัพย์สินในUIViewControllerชั้นเรียน
มี 2 ​​ตัวเลือกสำหรับตรวจจับทิศทางของอินเทอร์เฟซ:

  • ใช้การวางแนวแถบสถานะ
  • ใช้คลาสขนาดบน iPhone หากพวกเขาไม่ได้ถูกแทนที่พวกเขาสามารถให้คุณเข้าใจทิศทางของอินเทอร์เฟซปัจจุบัน

สิ่งที่ยังขาดหายไปคือวิธีที่จะเข้าใจทิศทางของการเปลี่ยนทิศทางของอินเทอร์เฟซซึ่งเป็นสิ่งสำคัญมากในระหว่างการเคลื่อนไหว
ในเซสชั่นของ WWDC 2014 "ดูความก้าวหน้าในการควบคุม iOS8" -will/DidRotateToInterfaceOrientationลำโพงให้วิธีการแก้ปัญหาที่มากเกินไปโดยใช้วิธีการที่จะแทนที่

นี่เป็นวิธีการแก้ปัญหาที่นำเสนอดำเนินการบางส่วนข้อมูลเพิ่มเติมได้ที่นี่ :

func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        let orientation = orientationFromTransform(coordinator.targetTransform())
        let oldOrientation = UIApplication.sharedApplication().statusBarOrientation
        myWillRotateToInterfaceOrientation(orientation,duration: duration)
        coordinator.animateAlongsideTransition({ (ctx) in
            self.myWillAnimateRotationToInterfaceOrientation(orientation,
            duration:duration)
            }) { (ctx) in
                self.myDidAnimateFromInterfaceOrientation(oldOrientation)
        }
    }

11

ฉันรู้ว่าคำถามนี้มีไว้เพื่อSwiftแต่เนื่องจากเป็นหนึ่งในลิงค์ด้านบนสำหรับการค้นหาของ Google และหากคุณกำลังมองหารหัสเดียวกันในObjective-C:

// add the observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rotated:) name:UIDeviceOrientationDidChangeNotification object:nil];

// remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];

// method signature
- (void)rotated:(NSNotification *)notification {
    // do stuff here
}

11

ใช้งานได้ง่ายใน iOS8 และ 9 / Swift 2 / Xcode7 เพียงแค่ใส่รหัสนี้ไว้ใน viewcontroller.swift ของคุณ มันจะพิมพ์ขนาดหน้าจอที่มีการเปลี่ยนแปลงการวางแนวทุกครั้งคุณสามารถใส่รหัสของคุณเองแทน:

override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
        getScreenSize()
    }
    var screenWidth:CGFloat=0
    var screenHeight:CGFloat=0
    func getScreenSize(){
        screenWidth=UIScreen.mainScreen().bounds.width
        screenHeight=UIScreen.mainScreen().bounds.height
        print("SCREEN RESOLUTION: "+screenWidth.description+" x "+screenHeight.description)
    }

5
ฟังก์ชันนี้เลิกใช้แล้วให้ใช้ "viewWillTransitionToSize: withTransitionCoordinator:" แทน
Masa S-AiYa

นอกเหนือจากการถูกปฏิเสธdidRotateFromInterfaceOrientation()ไม่ทำงานอย่างน่าเชื่อถือ มันขาดการหมุนบ้าง iewWillTransitionToSize:withTransitionCoordinator:ทำงานได้ดี
Andrej

@Andrej หลายสิ่งหลายอย่างเลิกใช้แล้วขอบคุณ Swift 3
Josh


9

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

สวิฟท์ 5:

    //ask the system to start notifying when interface change
    UIDevice.current.beginGeneratingDeviceOrientationNotifications()
    //add the observer
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(orientationChanged(notification:)),
        name: UIDevice.orientationDidChangeNotification,
        object: nil)

กว่าการแคชการแจ้งเตือน

    @objc func orientationChanged(notification : NSNotification) {
        //your code there
    }

8

ในวัตถุประสงค์ C

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator

อย่างรวดเร็ว

func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

แทนที่วิธีนี้เพื่อตรวจจับการเปลี่ยนแปลงการวางแนว


8

สวิฟท์ 3 | UIDeviceOrientationDidChange การแจ้งเตือนที่สังเกตบ่อยเกินไป

รหัสต่อไปนี้จะพิมพ์ "deviceDidRotate" ทุกครั้งที่อุปกรณ์ของคุณเปลี่ยนการวางแนวในพื้นที่ 3 มิติโดยไม่คำนึงถึงการเปลี่ยนจากแนวตั้งเป็นแนวนอน ตัวอย่างเช่นหากคุณถือโทรศัพท์ในแนวตั้งและเอียงไปข้างหน้าและข้างหลัง - DeviceDidRotate () ถูกเรียกซ้ำ ๆ

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIDeviceOrientationDidChange, 
        object: nil
    )
}

func deviceDidRotate() {
    print("deviceDidRotate")
}

เพื่อหลีกเลี่ยงปัญหานี้คุณสามารถระงับการวางแนวอุปกรณ์ก่อนหน้านี้และตรวจสอบการเปลี่ยนแปลงใน deviceDidRotate ()

var previousDeviceOrientation: UIDeviceOrientation = UIDevice.current.orientation

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIDeviceOrientationDidChange, 
        object: nil
    )
}

func deviceDidRotate() {
    if UIDevice.current.orientation == previousDeviceOrientation { return }
    previousDeviceOrientation = UIDevice.current.orientation
    print("deviceDidRotate")
}

หรือคุณสามารถใช้การแจ้งเตือนที่แตกต่างกันซึ่งจะถูกเรียกเมื่ออุปกรณ์เปลี่ยนจากแนวนอนเป็นแนวตั้งเท่านั้น ในกรณีนี้คุณต้องการใช้การUIApplicationDidChangeStatusBarOrientationแจ้งเตือน

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self, 
        selector:  #selector(deviceDidRotate), 
        name: .UIApplicationDidChangeStatusBarOrientation, 
        object: nil
    )
}

func deviceDidRotate() {
    print("deviceDidRotate")
}

6

การใช้งานอย่างเต็มรูปแบบของวิธีตรวจจับการเปลี่ยนแปลงการวางแนวใน Swift 3.0

ฉันเลือกที่จะใช้การใช้งานนี้เพราะทิศทางของโทรศัพท์face upและface downมีความสำคัญต่อฉันและฉันต้องการให้มุมมองการเปลี่ยนแปลงเพียงครั้งเดียวที่ฉันรู้ว่าการวางแนวอยู่ในตำแหน่งที่ระบุ

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //1
        NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

    }

    deinit {
        //3
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
    }

    func deviceOrientationDidChange() {
        //2
        switch UIDevice.current.orientation {
        case .faceDown:
            print("Face down")
        case .faceUp:
            print("Face up")
        case .unknown:
            print("Unknown")
        case .landscapeLeft:
            print("Landscape left")
        case .landscapeRight:
            print("Landscape right")
        case .portrait:
            print("Portrait")
        case .portraitUpsideDown:
            print("Portrait upside down")
        }
    }

}

สิ่งสำคัญที่ควรทราบคือ:

  1. คุณฟังสตรีมการแจ้งเตือน DeviceOrientationDidChange และผูกเข้ากับฟังก์ชันอุปกรณ์ DeviceOrientationDidChange
  2. จากนั้นคุณเปิดการวางแนวอุปกรณ์ตรวจสอบให้แน่ใจว่ามีการunknownวางแนวในบางครั้ง
  3. เช่นเดียวกับการแจ้งเตือนใด ๆ ก่อนที่ viewController จะถูกปิดการใช้งานให้แน่ใจว่าได้หยุดการสังเกตกระแสการแจ้งเตือน

หวังว่าบางคนพบว่ามีประโยชน์


ขอบคุณมาก
Mohammad Razipour

ดังนั้นฉันสับสนตอนนี้มุมมองทั้งหมดของฉันปรับตามแนวตั้งเป็นแนวนอน แต่มันไม่เปลี่ยนหากอุปกรณ์หงายหน้า? ฉันจะใช้โค้ดด้านบนของคุณเพื่อให้ได้ผลเหมือนกันเมื่อหงายหน้า!?
Famic Tech

คุณให้บริบทเพิ่มอีกหน่อยได้ไหม? ฉันไม่แน่ใจว่าคุณอ้างถึงเอฟเฟกต์ใด รหัสนี้ใช้เพื่อตรวจจับทิศทาง หากคุณใช้หลายวิธีในการตรวจจับการวางแนวคุณอาจประสบปัญหา
Rob Norback

6
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
    //swift 3
    getScreenSize()
}


func getScreenSize(){
   let screenWidth = UIScreen.main.bounds.width
   let  screenHeight = UIScreen.main.bounds.height
    print("SCREEN RESOLUTION: \(screenWidth.description) x \(screenHeight.description)")
}

คำตอบที่สะอาดที่สุด ทำงานให้ฉัน
Dorad

ตอนนี้เลิกใช้แล้ว
Aziz Javed

5

หากคุณต้องการทำบางสิ่งบางอย่างหลังจากการหมุนเสร็จสมบูรณ์คุณสามารถใช้UIViewControllerTransitionCoordinatorตัวจัดการความสมบูรณ์เช่นนี้

public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    // Hook in to the rotation animation completion handler
    coordinator.animate(alongsideTransition: nil) { (_) in
        // Updates to your UI...
        self.tableView.reloadData()
    }
}

5

ตั้งแต่ iOS 8 นี่เป็นวิธีที่ถูกต้องที่จะทำ

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate(alongsideTransition: { context in
        // This is called during the animation
    }, completion: { context in
        // This is called after the rotation is finished. Equal to deprecated `didRotate`
    })
}

4

ตรวจสอบว่าการหมุนมีการเปลี่ยนแปลงด้วย: viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

กับ coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext)คุณสามารถตรวจสอบว่าการเปลี่ยนแปลงเสร็จสิ้น

ดูรหัสด้านล่าง:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition(nil) { (UIViewControllerTransitionCoordinatorContext) in
        // if you want to execute code after transition finished
        print("Transition finished")
    }

    if size.height < size.width {
        // Landscape
        print("Landscape")
    } else {
        // Portrait
        print("Portrait")
    }

}

4

นี่เป็นวิธีที่ง่ายในการตรวจจับการวางแนวอุปกรณ์: ( Swift 3 )

override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
            handleViewRotaion(orientation: toInterfaceOrientation)
        }

    //MARK: - Rotation controls
    func handleViewRotaion(orientation:UIInterfaceOrientation) -> Void {
        switch orientation {
        case .portrait :
            print("portrait view")
            break
        case .portraitUpsideDown :
            print("portraitUpsideDown view")
            break
        case .landscapeLeft :
            print("landscapeLeft view")
            break
        case .landscapeRight :
            print("landscapeRight view")
            break
        case .unknown :
            break
        }
    }

2
willRotateviewWillTransitionจะเลิกตอนนี้ใช้ดีกว่า
ก่อน

4

สวิฟท์ 4:

override func viewWillAppear(_ animated: Bool) {
    NotificationCenter.default.addObserver(self, selector: #selector(deviceRotated), name: UIDevice.orientationDidChangeNotification, object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}

@objc func deviceRotated(){
    if UIDevice.current.orientation.isLandscape {
        //Code here
    } else {
        //Code here
    }
}

คำตอบจำนวนมากช่วยไม่ได้เมื่อต้องการตรวจสอบตัวควบคุมมุมมองที่หลากหลาย อันนี้ทำอุบาย


คุณต้องตรวจสอบว่าอุปกรณ์หมุนในขณะที่ตัวควบคุมมุมมองหายไปหรือไม่ (ในกรณีที่ตัวควบคุมมุมมองอื่น ๆ เปิดเหนือกระแสปัจจุบัน) ในความเป็นจริงคุณสามารถข้ามviewWillDisappearและเพิ่มในaddObserver viewDidLoadiOS ยกเลิกการเป็นสมาชิกตัวควบคุมการดูโดยอัตโนมัติ
Alexander Volkov

คุณลืมUIDevice.current.orientation.isFlat
user924

3

วิธีการของฉันคล้ายกับสิ่งที่bpeditแสดงด้านบน แต่ด้วยการมุ่งเน้น iOS 9+ ฉันต้องการเปลี่ยนขอบเขตของFSCalendarเมื่อมุมมองหมุน

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    coordinator.animateAlongsideTransition({ (context) in
        if size.height < size.width {
            self.calendar.setScope(.Week, animated: true)
            self.calendar.appearance.cellShape = .Rectangle
        }
        else {
            self.calendar.appearance.cellShape = .Circle
            self.calendar.setScope(.Month, animated: true)

        }

        }, completion: nil)
}

ด้านล่างนี้ใช้งานได้ แต่ฉันรู้สึกอายมาก :)

coordinator.animateAlongsideTransition({ (context) in
        if size.height < size.width {
            self.calendar.scope = .Week
            self.calendar.appearance.cellShape = .Rectangle
        }
        }) { (context) in
            if size.height > size.width {
                self.calendar.scope = .Month
                self.calendar.appearance.cellShape = .Circle
            }
    }

2

ฉันใช้UIUserInterfaceSizeClassเพื่อตรวจจับทิศทางที่เปลี่ยนไปในUIViewControllerชั้นเรียนเช่นเดียวกับที่:

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {

    let isiPadLandscapePortrait = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .regular
    let isiPhonePlustLandscape = newCollection.horizontalSizeClass == .regular && newCollection.verticalSizeClass == .compact
    let isiPhonePortrait = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .regular
    let isiPhoneLandscape = newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .compact

     if isiPhonePortrait {
         // do something...
     }
}

1

สำหรับ Swift 3

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.orientation.isLandscape {
        //Landscape
    }
    else if UIDevice.current.orientation.isFlat {
        //isFlat
    }
    else {
        //Portrait
    }
}

คุณลืมUIDevice.current.orientation.isFlat
user924

1

สวิฟท์ 5

ตั้งค่าคลาสเพื่อรับการแจ้งเตือนการเปลี่ยนทิศทางของอุปกรณ์:

class MyClass {

    ...

    init (...) {

        ...

        super.init(...)

        // subscribe to device orientation change notifications
        UIDevice.current.beginGeneratingDeviceOrientationNotifications()
        NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged), name: UIDevice.orientationDidChangeNotification, object: nil)

        ...

    }

    ...

}

ตั้งค่ารหัสตัวจัดการ:

@objc extension MyClass {
    func orientationChanged(_ notification: NSNotification) {
        let device = notification.object as! UIDevice
        let deviceOrientation = device.orientation

        switch deviceOrientation {
        case .landscapeLeft:   //do something for landscape left
        case .landscapeRight:  //do something for landscape right
        case .portrait:        //do something for portrait
        case .portraitUpsideDown: //do something for portrait upside-down 
        case .faceDown:        //do something for face down
        case .faceUp:          //do something for face up
        case .unknown:         //handle unknown
        @unknown default:      //handle unknown default
        }
    }
}

0
- (void)viewDidLoad {
  [super viewDidLoad];
  [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(OrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
}

-(void)OrientationDidChange:(NSNotification*)notification {
  UIDeviceOrientation Orientation=[[UIDevice currentDevice]orientation];

  if(Orientation==UIDeviceOrientationLandscapeLeft || Orientation==UIDeviceOrientationLandscapeRight) {
    NSLog(@"Landscape");
  } else if(Orientation==UIDeviceOrientationPortrait) {
    NSLog(@"Potrait Mode");
  }
}

หมายเหตุ: เพียงใช้รหัสนี้เพื่อระบุ UIViewController ว่าอยู่ในทิศทางใด


รหัสของคุณไม่ทำงานในโครงการ ฉันต้องทำอะไรอย่างอื่นด้วยเหรอ?
Syed Ali Salman

0
override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(MyController.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
//...
}

@objc
private func rotated() {
    if UIDevice.current.orientation.isLandscape {

    } else if UIDevice.current.orientation.isPortrait {

    }

    //or you can check orientation separately UIDevice.current.orientation
    //portrait, portraitUpsideDown, landscapeLeft, landscapeRight... 

}

0

ด้วย iOS 13.1.2 การวางแนวจะส่งคืน 0 เสมอจนกว่าอุปกรณ์จะหมุน ฉันต้องโทรหา UIDevice.current.beginGeneratingDeviceOrientationNotifications () เพื่อรับการหมุนจริงก่อนที่เหตุการณ์การหมุนจะเกิดขึ้น

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