Cách "đúng" để xử lý các thay đổi hướng trong iOS 8 là gì?


104

Ai đó có thể vui lòng cho tôi biết cách tiếp cận "đúng" hoặc "tốt nhất" để làm việc với các hướng giao diện dọc và ngang trong iOS 8 không? Có vẻ như tất cả các chức năng tôi muốn sử dụng cho mục đích đó đều không được chấp nhận trong iOS 8 và nghiên cứu của tôi không có giải pháp thay thế rõ ràng, thanh lịch nào. Tôi thực sự nên xem xét chiều rộng và chiều cao để tự xác định xem chúng ta đang ở chế độ dọc hay ngang?

Ví dụ: trong bộ điều khiển chế độ xem của tôi, tôi nên triển khai mã giả sau như thế nào?

if we are rotating from portrait to landscape then
  do portrait things
else if we are rotating from landscape to portrait then
  do landscape things

3
Đọc tài liệu cho UIViewController. Xem phần có tiêu đề "Xử lý các
lượt xem`

Đó là một manh mối. Bạn phải sử dụng cái gì khác .... mà cái gì khác nên AutoLayout và quy mô lớp :-)
Aaron

Câu trả lời:


262

Apple khuyên bạn nên sử dụng các lớp kích thước làm thước đo thô cho bao nhiêu không gian màn hình khả dụng, để giao diện người dùng của bạn có thể thay đổi đáng kể bố cục và giao diện của nó. Hãy xem xét rằng iPad ở chế độ dọc có các loại kích thước giống như ở chế độ ngang (Chiều rộng thông thường, Chiều cao thông thường). Điều này có nghĩa là giao diện người dùng của bạn ít nhiều phải giống nhau giữa hai hướng.

Tuy nhiên, sự thay đổi từ dọc sang ngang trong iPad là đủ đáng kể để bạn có thể cần thực hiện một số điều chỉnh nhỏ hơn đối với giao diện người dùng, mặc dù các lớp kích thước không thay đổi. Vì các phương pháp liên quan đến hướng giao diện trên UIViewControllerđã không còn được dùng nữa, Apple hiện khuyên bạn nên triển khai phương pháp mới sau UIViewControllerđể thay thế:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // Code here will execute before the rotation begins.
    // Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:]

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Place code here to perform animations during the rotation.
        // You can pass nil or leave this block empty if not necessary.

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Code here will execute after the rotation has finished.
        // Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:]

    }];
}

Tuyệt quá! Bây giờ bạn sẽ nhận được các cuộc gọi lại ngay trước khi vòng quay bắt đầu và sau khi quá trình này kết thúc. Nhưng thực sự biết liệu xoay là để dọc hay ngang?

Apple khuyên bạn nên nghĩ về việc xoay chỉ đơn giản là thay đổi kích thước của chế độ xem gốc. Nói cách khác, trong quá trình xoay iPad từ dọc sang ngang, bạn có thể coi đó là chế độ xem cấp cơ sở chỉ cần thay đổi bounds.sizetừ {768, 1024}sang {1024, 768}. Khi đó, khi biết điều này, bạn nên sử dụng giá trị sizeđược truyền vào viewWillTransitionToSize:withTransitionCoordinator:phương pháp ở trên để tìm hiểu xem bạn đang xoay theo chiều dọc hay ngang.

Nếu bạn muốn một cách liền mạch hơn để di chuyển mã kế thừa sang cách hoạt động mới của iOS 8, hãy xem xét sử dụng danh mục đơn giản này trên UIView, có thể được sử dụng để xác định xem chế độ xem là "dọc" hay "ngang" dựa trên kích thước.

Tóm lại:

  1. Bạn nên sử dụng các lớp kích thước để xác định thời điểm hiển thị các giao diện người dùng khác nhau về cơ bản (ví dụ: giao diện người dùng "giống iPhone" so với giao diện người dùng "giống iPad")
  2. Nếu bạn cần thực hiện các điều chỉnh nhỏ hơn đối với giao diện người dùng của mình khi các lớp kích thước không thay đổi nhưng kích thước vùng chứa (chế độ xem chính) của bạn thì có, chẳng hạn như khi iPad xoay, hãy sử dụng lệnh viewWillTransitionToSize:withTransitionCoordinator:gọi lại trong UIViewController.
  3. Mọi chế độ xem trong ứng dụng của bạn chỉ nên đưa ra các quyết định về bố cục dựa trên không gian mà nó đã được cấp cho bố cục. Hãy để thứ bậc tự nhiên của các chế độ xem chia nhỏ thông tin này.
  4. Tương tự, không sử dụng statusBarOrientation- về cơ bản là thuộc tính cấp thiết bị - để xác định xem nên bố trí chế độ xem cho "dọc" và "ngang". Hướng thanh trạng thái chỉ nên được sử dụng bởi mã xử lý những thứ như UIWindowthực sự tồn tại ở cấp cơ sở của ứng dụng.

5
Câu trả lời xuất sắc! BTW, video youtube của bạn trên AL cực kỳ nhiều thông tin. Thanx để chia sẻ. Kiểm tra nó ra! youtube.com/watch?v=taWaW2GzfCI
smileBot

2
Vấn đề duy nhất tôi tìm thấy là đôi khi bạn muốn biết hướng thiết bị và điều này sẽ không cho bạn biết. Trên iPad, nó được gọi trước khi giá trị thanh trạng thái hoặc hướng thiết bị thay đổi. Bạn không thể biết người dùng cầm thiết bị ở chế độ dọc hay dọc ngược. Nó cũng không thể kiểm tra, vì chế nhạo UIViewControllerTransitionCoordinatorlà một cơn ác mộng :-(
Darrarski

@Darrarski bạn đã tìm thấy một giải pháp thanh lịch để đối phó với những vấn đề đó chưa?
Xvolks

vậy thì ở đâu viewdidlayoutsubviews? Tôi nghĩ viewdidlayoutsubviewsđược sử dụng để nắm bắt các thay đổi bị ràng buộc do xoay. Bạn có thể nói rõ hơn về điều đó?
Honey

1
Làm cách nào để phân biệt giữa ngang trái và ngang phải nếu chúng ta không sử dụng phân bổ trạng thái? Tôi cần sự phân biệt đó. Bên cạnh đó, có những vấn đề khác như được mô tả ở đây - stackoverflow.com/questions/53364498/…
Deepak Sharma,

17

Dựa trên câu trả lời rất chi tiết (và được chấp nhận) của smileyborg, đây là một bản chuyển thể sử dụng swift 3:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: nil, completion: {
        _ in
        self.collectionView.collectionViewLayout.invalidateLayout()
    })        
}

Và trong quá trình UICollectionViewDelegateFlowLayoutthực hiện,

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    // retrieve the updated bounds
    let itemWidth = collectionView.bounds.width
    let itemHeight = collectionView.bounds.height
    // do whatever you need to do to adapt to the new size
}

11

Tôi chỉ sử dụng Trung tâm thông báo:

Thêm một biến định hướng (sẽ giải thích ở cuối)

//Above viewdidload
var orientations:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation

Thêm thông báo khi chế độ xem xuất hiện

override func viewDidAppear(animated: Bool) {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name: UIDeviceOrientationDidChangeNotification, object: nil)
}

Xóa thông báo khi chế độ xem biến mất

override func viewWillDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIDeviceOrientationDidChangeNotification, object: nil) 
}

Nhận hướng hiện tại khi thông báo được kích hoạt

func orientationChanged (notification: NSNotification) {
    adjustViewsForOrientation(UIApplication.sharedApplication().statusBarOrientation)
}

Kiểm tra hướng (dọc / ngang) và xử lý các sự kiện

func adjustViewsForOrientation(orientation: UIInterfaceOrientation) {
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown)
    {
        if(orientation != orientations) {
            println("Portrait")
            //Do Rotation stuff here
            orientations = orientation
        }
    }
    else if (orientation == UIInterfaceOrientation.LandscapeLeft || orientation == UIInterfaceOrientation.LandscapeRight)
    {
       if(orientation != orientations) {
            println("Landscape")
            //Do Rotation stuff here
            orientations = orientation
        }
    }
}

Lý do tôi thêm biến định hướng là vì khi thử nghiệm trên một thiết bị vật lý, thông báo định hướng được gọi ở mọi chuyển động nhỏ trong thiết bị, chứ không chỉ khi nó xoay. Việc thêm lệnh var và if chỉ gọi mã nếu nó chuyển sang hướng ngược lại.


11
Đây không phải là cách tiếp cận được khuyến nghị của Apple vì nó có nghĩa là mọi chế độ xem trong ứng dụng của bạn sẽ quyết định cách hiển thị dựa trên hướng của thiết bị, thay vì xem xét không gian mà nó được cung cấp.
smileyborg

2
Apple cũng không xem xét phần cứng với 8.0. Nói với lớp AVPreview rằng nó không cần phải lo lắng về hướng nếu nó được trình bày trên bộ điều khiển chế độ xem. Không hoạt động, nhưng nó đã được khắc phục trong 8.2
Nick Turner

supercủa viewDidAppearviewWillDisappearnên được gọi là
Andrew Bogaevskyi

Lưu ý: UIDeviceOrientation! = UIInterfaceOrientation. Trong các thử nghiệm của tôi, statusBarOrientation không đáng tin cậy.
nnrales

2

Từ góc độ giao diện người dùng, tôi tin rằng sử dụng Size Class là cách tiếp cận được Apple khuyến nghị để xử lý giao diện theo các hướng, kích thước và tỷ lệ khác nhau.

Xem phần: Đặc điểm Mô tả Loại Kích thước và Quy mô của Giao diện tại đây: https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html

"iOS 8 bổ sung các tính năng mới giúp xử lý kích thước và hướng màn hình linh hoạt hơn nhiều."

Đây cũng là một bài viết hay: https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/

EDIT Cập nhật liên kết: https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/ (Tín dụng: Koen)


Vâng, có vẻ như toàn bộ trang web của anh ấy đang ngừng hoạt động vào lúc này.
Aaron

Bài viết thực sự đáng đọc và đây là địa chỉ chính xác: carpeaqua.com/thinking-in-terms-of-ios-8-size-classes
uem

Nhưng điều gì sẽ xảy ra nếu chúng ta không nói về các lớp kích thước và giao diện người dùng, mà là về AVFoundation chẳng hạn. Khi quay video, trong một số trường hợp, bạn phải biết hướng viewControllers để đặt siêu dữ liệu chính xác. Điều này là đơn giản không thể. "đa năng".
Julian F. Weinert

Đó không phải là những gì OP đã hỏi / nói về.
Aaron

1
Liên kết cập nhật: carpeaqua.com/2014/06/14/…
koen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.