iOS 8에서 방향 변경을 처리하는 "올바른"방법은 무엇입니까?


104

누군가 iOS 8에서 세로 및 가로 인터페이스 방향으로 작업하는 데 "올바른"또는 "가장 좋은"접근 방식을 알려주시겠습니까? 그 목적으로 사용하려는 모든 기능이 iOS 8에서 더 이상 사용되지 않는 것 같습니다. 그리고 내 연구에 따르면 명확하고 우아한 대안이 없습니다. 가로 모드인지 세로 모드인지 스스로 결정하기 위해 너비와 높이를 확인해야합니까?

예를 들어, 뷰 컨트롤러에서 다음 의사 코드를 어떻게 구현해야합니까?

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
에 대한 문서를 읽어보십시오 UIViewController. "View Rotations 처리"섹션을 참조하십시오. 수행해야 할 작업에 대해 설명합니다.
rmaddy

더 이상 사용되지 않는다는 것이 단서입니다. 당신은 뭔가 다른 자동 레이아웃 및 크기 클래스 :-)해야한다고 .... 다른 것을 사용 해
아론

답변:


262

Apple은 UI가 레이아웃과 모양을 크게 변경할 수 있도록 크기 클래스를 사용 가능한 화면 공간의 대략적인 척도로 사용할 것을 권장합니다. 세로 모드의 iPad는 가로 모드 (일반 너비, 일반 높이)와 동일한 크기 등급을 가지고 있다고 가정합니다. 이는 UI가 두 방향간에 다소 유사해야 함을 의미합니다.

그러나 iPad에서 세로에서 가로로의 변경은 크기 클래스가 변경되지 않았더라도 UI를 약간 조정해야 할만큼 충분히 중요합니다. 의 인터페이스 방향 관련 메서드 UIViewController가 더 이상 사용되지 않으므로 Apple은 이제 다음과 같은 새로운 메서드를 UIViewController대체로 구현할 것을 권장합니다 .

- (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:]

    }];
}

큰! 이제 순환이 시작되기 직전과 완료된 후에 콜백을받습니다. 그러나 회전이 세로인지 가로인지 실제로 아는 것은 어떨까요?

Apple은 회전을 단순히 상위 뷰의 크기 변경으로 생각할 것을 권장합니다. 즉, 세로에서 가로로 아이 패드 회전하는 동안, 당신은 루트 레벨보기는 단순히 변화로 생각할 수 bounds.size에서 {768, 1024}까지 {1024, 768}. 이를 알면 위 sizeviewWillTransitionToSize:withTransitionCoordinator:메서드에 전달 된를 사용하여 세로 또는 가로로 회전하는지 파악 해야합니다 .

레거시 코드를 새로운 iOS 8 방식으로 마이그레이션하는보다 원활한 방법을 원한다면 UIView 에서이 간단한 범주 를 사용하는 것이 좋습니다. 이 범주 를 사용하여 뷰가 "세로"인지 또는 "가로"인지 여부를 결정하는 데 사용할 수 있습니다. 크기.

요약하자면:

  1. 크기 클래스를 사용하여 근본적으로 다른 UI를 표시 할시기를 결정해야합니다 (예 : "iPhone과 유사한"UI 대 "iPad와 유사한"UI).
  2. iPad가 회전 할 때와 같이 크기 클래스 변경 되지 않고 컨테이너 (부모보기) 크기가 변경 될 때 UI를 더 작게 조정해야하는 경우 viewWillTransitionToSize:withTransitionCoordinator:UIViewController 에서 콜백을 사용하십시오 .
  3. 앱의 모든 뷰는 레이아웃에 주어진 공간에 따라 레이아웃을 결정해야합니다. 뷰의 자연스러운 계층 구조가이 정보를 계단식으로 배열하도록합니다.
  4. 마찬가지로 statusBarOrientation기본적으로 장치 수준 속성 인를 사용하여 "세로"와 "가로"보기를 레이아웃할지 여부를 결정 하지 마십시오 . 상태 표시 줄 방향은 UIWindow실제로 앱의 가장 루트 수준에있는 것과 같은 것을 처리하는 코드에서만 사용해야 합니다.

5
훌륭한 대답입니다! BTW, AL에 대한 YouTube 비디오는 매우 유익했습니다. 공유해 주셔서 감사합니다. 확인 해봐! youtube.com/watch?v=taWaW2GzfCI
smileBot 2015-04-06

2
내가 찾은 유일한 문제는 때때로 장치 방향을 알고 싶어하지만 이것이 알려지지 않는다는 것입니다. iPad에서는 상태 표시 줄 또는 기기 방향 값이 변경되기 전에 호출됩니다. 사용자가 기기를 세로로 들고 있는지 아니면 거꾸로 들고 있는지 알 수 없습니다. 조롱과 같이 그것은 또한 테스트하는 것은 불가능 UIViewControllerTransitionCoordinator악몽이 :-(
Darrarski

@Darrarski는 이러한 문제에 대처할 수있는 우아한 해결책을 찾았습니까?
Xvolks

그럼 어디야 viewdidlayoutsubviews? viewdidlayoutsubviews회전으로 인한 바운드 변화를 포착하는 데 사용 된다고 생각했습니다 . 그것에 대해 자세히 설명해 주시겠습니까?
Honey

1
상태 표시 줄 방향을 사용하지 않는 경우 가로 가로와 세로 가로를 구분하는 방법은 무엇입니까? 나는 그 구별이 필요합니다. - 게다가, 여기에 설명 된 다른 문제가있는 stackoverflow.com/questions/53364498/...은
디팍 샤르마

17

smileyborg의 매우 상세한 (및 수용된) 답변을 기반으로하여 다음은 신속한 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()
    })        
}

그리고 UICollectionViewDelegateFlowLayout구현에서

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

알림 센터를 사용합니다.

방향 변수 추가 (마지막에 설명)

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

보기가 나타날 때 알림 추가

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

보기가 사라질 때 알림 제거

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

알림이 트리거 될 때 현재 방향을 가져옵니다.

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

방향 (세로 / 가로) 확인 및 이벤트 처리

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

방향 변수를 추가하는 이유는 물리적 장치에서 테스트 할 때 방향 알림이 회전 할 때뿐만 아니라 장치의 모든 사소한 움직임에서 호출되기 때문입니다. var 및 if 문을 추가하면 반대 방향으로 전환 된 경우에만 코드가 호출됩니다.


11
이는 앱의 모든보기가 주어진 공간을 고려하는 대신 장치의 방향에 따라 표시하는 방법을 결정하기 때문에 Apple에서 권장하는 접근 방식이 아닙니다.
smileyborg 2014

2
Apple은 또한 8.0에서 하드웨어를 고려하지 않습니다. 뷰 컨트롤러를 통해 표시되는 경우 방향에 대해 걱정할 필요가없는 AVPreview 레이어에 알립니다. 작동하지 않지만 8.2에서 수정 됨
Nick Turner

superviewDidAppearviewWillDisappear호출해야
앤드류 Bogaevskyi

참고 : UIDeviceOrientation! = UIInterfaceOrientation. 내 실험에서 statusBarOrientation은 신뢰할 수 없습니다.
nnrales

2

UI 관점에서 저는 크기 클래스를 사용하는 것이 다양한 방향, 크기 및 스케일의 인터페이스를 처리하기 위해 Apple에서 권장하는 접근 방식이라고 생각합니다.

https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html 에서 인터페이스의 크기 클래스 및 규모 설명 섹션을 참조 하십시오.

"iOS 8은 화면 크기와 방향을 훨씬 더 다양하게 다루는 새로운 기능을 추가합니다."

이것도 좋은 기사입니다 : https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/

업데이트 된 링크 편집 : https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/ (크레딧 : Koen)


예, 현재 사이트 전체가 다운 된 것 같습니다.
Aaron

이 기사는 실제로 읽을 가치가 있으며 여기에 올바른 주소가 있습니다. carpeaqua.com/thinking-in-terms-of-ios-8-size-classes
uem

하지만 예를 들어 크기 클래스와 UI가 아니라 AVFoundation에 대해 이야기한다면 어떨까요? 비디오를 녹화 할 때 경우에 따라 올바른 메타 데이터를 설정하려면 viewController의 방향을 알아야합니다. 이것은 간단합니다. "변하기 쉬운".
Julian F. Weinert

그것은 OP가 묻거나 말한 것이 아닙니다.
아론

1
업데이트 된 링크 : carpeaqua.com/2014/06/14/…
koen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.