iOS 11 safeArea 상세 설명 및 아이 폰 X 적합

11585 단어 iOS11safeArea
최근 에 아이 폰 X 에 어 울 리 는 글 을 많이 봤 는데,safeArea 를 소개 하 는 사람 이 별로 없어 서 마음대로 쓰 는 것 을 발견 하 였 다.
현재 아이 폰 X 의 적합 에 대해 흔히 볼 수 있 는 방법 은 네 비게 이 션 표시 줄 이나 tabbar 에 고정된 거 리 를 추가 하 는 것 이다.예 를 들 어 상단 에 44pt 를 증가 하고 바닥 에 34pt 를 증가 하 는 것 이다.이런 사거 리 를 쓰 는 방법 은 언뜻 보기 에는 매우 간단 하지만,사실은 결코 좋 지 않다.이 유 는 다음 과 같다.
  • 다 중 기종 에 적합 하지 않 습 니 다.나중에 앞머리 가 있 는 아이 패드 가 나 오 면 미리 남 겨 두 어야 할 거리 가 지금 죽은 거 리 는
  • 이 아 닙 니 다.
  • 은 가로 세로 화면 을 지원 해 야 하 는 app 에 적합 하지 않 습 니 다.가로 화면 상단 은 거 리 를 늘 릴 필요 가 없고 오히려 좌우 에 각각 44pt 이 있 으 며 바닥 의 거리 도 세로 화면 과 다 릅 니 다
  • 은 동태 적 이지 않다.아니면 예 를 들 어 전화 가 들 어 오 면 네 비게 이 션 표시 줄 이 내 려 갈 것 입 니 다.이때 view 는
  • 을 가 릴 수 있 습 니 다.
    여기 서 저 는 safearea LayoutGuide 와 safearea Insets 를 어떻게 사용 하 는 지 동태 적 인 방식 으로 아이 폰 X 심지어 후속 적 인 모든 기종 의 적합 문 제 를 영원히 해결 하 는 지 연구 하고 싶 습 니 다.
    safeAreaLayoutGuide
    우선 safearea LayoutGuide 가 뭔 지 봅 시다.

    복잡 해 보이 지만 사실은 간단 합 니 다.몇 가 지 를 요약 하 겠 습 니 다.
  • 은 UIView 의 읽 기 전용 속성 으로 모든 UIView 대상 이 있 고 시스템 이 만들어 준
  • 을 의미 합 니 다.
  • 은 UILayoutGuide 를 계승 합 니 다.layoutFrame 은 한 지역 을 대표 할 수 있다 는 것 을 의미 합 니 다
  • 이 대표 하 는 구역 은 네 비게 이 션 표시 줄,tabbar 또는 이 UIView 대상 이 표시 하 는 모든 부모 view 를 피 했 습 니 다.이 는 view 대상 이 다른 view 의 safeLayoutGuide 에 비해 구 조 를 하면 이상 한 것 에 가 려 질 까 봐 걱정 하지 않 아 도 된다 는 것 을 의미 합 니 다.
  • 컨트롤 러 의 view 에 대한 safearea LayoutGuide,그의 구역 역시 status bar 또는 view 가 표시 할 수 있 는 다른 것 을 피 했 습 니 다.우 리 는 컨트롤 러 의 addition al Safearea Insets 속성 으로 inset
  • 을 추가 로 지정 할 수 있 습 니 다.
  • view 가 부모 view 의 안전 구역 에 있 거나 view 가 보기 등급 이나 화면 에 없 으 면 view 의 safearea LayoutGuide 구역 은 view 자체 와 똑 같이 큰
  • 입 니 다.
    safearea LayoutGuide 는 상대 적 으로 추상 적 인 개념 입 니 다.이해 하기 쉽 도록 safearea LayoutGuide 를'view'로 볼 수 있 습 니 다.이'view'시스템 은 자동 으로 bounds 를 조정 하여 아이 폰 X 의 앞머리 구역 과 아래쪽 의 철봉 구역 을 포함 하여 각종 기괴 한 것 에 가 려 지지 않도록 합 니 다.이"view"에 서 는 모든 내용 을 완전 하 게 표시 할 수 있다 고 볼 수 있 습 니 다.
    아래 녹색 부분 은 현재 컨트롤 러 view 의 safearea LayoutGuide 영역 입 니 다.

    아이 폰 X 세로 화면 safearea LayoutGuide 의 bounds.png

    iPhone X 가로 화면 safearea LayoutGuide 의 bounds.png
    캡 처
    그러나 명심 해 야 할 것 은 이'view'가 우리 의 보기 단계 에 나타 나 지 않 는 다 는 것 이다.
    UILayoutGuides will not show up in the view hierarchy, but may be used as items in an NSLayoutConstraint and represent a rectangle in the layout engine.
    내 가 보기에 그의 가장 큰 역할 은 참조물 로 서 view 가 특정한 view 의 safearea LayoutGuide 에 비해 구 조 를 하여 view 가 정상 적 이 고 안전하게 표 시 될 수 있 도록 하 는 것 이다(상대 적 으로 그 view 가 반드시 부모 view 가 되 는 것 은 아니다).
    흔히 볼 수 있 는 사용 장면 에서 예전 에 제 view 는 컨트롤 러 view 에 비해 구 조 를 했 는데 지금 은 컨트롤 러 view 의 safearea LayoutGuide 에 비해 구 조 를 했 습 니 다.
    예전 에는 이렇게 썼어 요.
    [NSLayoutConstraint constraintWithItem:someView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.vc.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
    지금 은 그렇습니다.
    [NSLayoutConstraint constraintWithItem:someView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.vc.view.safeAreaLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
    전후의 효과 에 적합 하 다

    적합 전.png

    view 에 대비 한 safearea LayoutGuide 로 바 꾼 후-세로.png

    view 에 대비 한 safearea LayoutGuide 로 변경 한 후-가로 화면.png
    이 를 통 해 알 수 있 듯 이 같은 레이아웃 에서 가로 화면 은 status bar 가 없 을 때 상단 에서 0,왼쪽 은 44 이 고 status bar 가 있 으 면 상단 에서 20 이다.어쨌든 우리 가 상대 적 으로 safearea LayoutGuide 를 배치 하면 우리 의 view 는 안전 하고 완전 하 게 표 시 될 수 있다.
    그럼 iOS 11 아니면 어 떡 해?
    iOS 11 이 아니면 view 에 만 레이아웃 을 할 수 있 습 니 다.레이아웃 코드 두 세트 를 써 야 합 니 다.잠시 후에 소개 하 겠 습 니 다.
    이 정도 면 모든 상황 에 대처 하기에 충분 하지 않 을까요?
    결코
    사용자 정의 view 는 화면 가장자리 에 바짝 붙 어야 합 니 다.예 를 들 어 제 프로젝트 는 사용자 정의 네 비게 이 션 표시 줄 입 니 다.상단 은 화면 상단 에 붙 어 있 습 니 다.그러면 네 비게 이 션 표시 줄 은 view 의 safearea LayoutGuide 레이아웃 과 비교 할 수 없습니다.그렇지 않 으 면 상단 이 비어 있 습 니 다.
    프레임 레이아웃
    이제 safearea Insets 가 역할 을 할 차례 입 니 다.
    safeAreaInsets
    safearea Insets 의 공식 설명 을 살 펴 보 겠 습 니 다.

    혹시 safearea Layout Guide 랑 비슷 하지 않 아 요?safearea LayoutGuide 는 safearea Insets 에 따라 자신의 bounds 를 조정 할 수 있 습 니 다.
    아이 폰 X 세로 화면 에서 전체 화면 을 차지 하 는 컨트롤 러 view 의 safearea Insets 는(44,0,34,0),가로 화면 은(0,44,21,44),inset 뒤의 영역 은 safearea LayoutGuide 영역 입 니 다.
    그렇다면 사용자 정의 상단 네 비게 이 션 바 에 있어 서 네 비게 이 션 바 의 높이 에 vc.view.safearea Insets.top 을 추가 하여 그 를 좀 높 게 만 들 면 된다.이렇게 X 에서 세로 화면 시 top=44,가로 화면 시 top=0,네 비게 이 션 바 의 높이 는 변화 에 응 할 수 있다.
    주의해 야 할 것 은 safearea LayoutGuide 든 safearea Insets 든 모두 iOS 11 에서 만 사용 할 수 있다 는 것 이다.
    safearea Insets 에 대해 서 는 버 전 판단 을 함수 에 쓸 수 있 습 니 다.
    우 리 는 이렇게 쓸 수 있다.
    
    static inline UIEdgeInsets sgm_safeAreaInset(UIView *view) {
     if (@available(iOS 11.0, *)) {
      return view.safeAreaInsets;
     }
     return UIEdgeInsetsZero;
    }
    
    
    UIEdgeInsets safeAreaInsets = sgm_safeAreaInset(self.view);
    CGFloat height = kDefaultTopViewHeight; //         ,   44.0
    height += safeAreaInsets.top > 0 ? safeAreaInsets.top : 20.0; // 20.0 statusbar   
    
    문제 가 또 생 겼 습 니 다.이 코드 는 어디 에 두 면 적당 합 니까?앞에서 공식 문서 에서 언급 했 듯 이 view 가 화면 에 없 거나 레이 어 링 을 표시 하지 않 으 면 view 의 safearea Insets=UIEdgeInsets Zero 이기 때문에 safearea Insets 가 바 뀌 는 시 기 를 명 확 히 알 아야 합 니 다.
    실제 시스템 은 이미 리 셋 을 제공 했다.
    UIViewController 에 대해

    -(void)viewSafeAreaInsetsDidChange NS_REQUIRES_SUPER API_AVAILABLE(ios(11.0), tvos(11.0));
    UIView
    
    -(void)safeAreaInsetsDidChange API_AVAILABLE(ios(11.0),tvos(11.0));
    여기 서 주로 controller 의 리 셋 을 검토 하 는데 view 의 리 셋 은 유사 하 다.controller 의 view 의 safearea Insets 가 바 뀌 면 시스템 은 view Safearea Insets Did Change 를 호출 합 니 다.자 연 스 럽 게 우 리 는 상기 코드 를 여기에 두 고 싶 을 것 이다.그러나 여기 큰 구덩이 가 있다.이 컨트롤 러 가 애니메이션 방식 으로 push 로 들 어 올 때 네 비게 이 션 바 의 높이 도 애니메이션 으로 높 아 지고 불필요 한 애니메이션 이 생 긴 다 는 것 을 알 게 될 것 이다.이런 체험 은 매우 나쁘다.
    그렇다면 어디 에 두 어야 할 까?우 리 는 새로운 view Controller 호출 시 서 를 볼 필요 가 있다.
    다음은"rootVC"push 에서"pushVC"콘 솔 로 출력 하 는 호출 순서 및 컨트롤 러 에 대응 하 는 view 의 safeareaInsets 입 니 다.
    
    2017-10-04 16:59:59.594811+0800 XXX[15662:803767] Begin pushViewController to [<_TtCC8XXXTests27ContainerViewControllerTest20MockUIViewController: 0x7f9c07b643b0>]
    viewDidLoad()---Optional("pushVC")---UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
    willMove(toParentViewController:)---Optional("pushVC")---UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
    viewWillDisappear---Optional("rootVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    viewWillAppear---Optional("pushVC")---UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
    viewSafeAreaInsetsDidChange()---Optional("pushVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    viewWillLayoutSubviews()---Optional("pushVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    viewDidLayoutSubviews()---Optional("pushVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    viewWillLayoutSubviews()---Optional("pushVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    viewDidLayoutSubviews()---Optional("pushVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    viewDidAppear---Optional("pushVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    viewDidDisappear---Optional("rootVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    didMove(toParentViewController:)---Optional("pushVC")---UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
    2017-10-04 16:59:59.604563+0800 XXX[15662:803767] Did PushViewController [<_TtCC8XXXTests27ContainerViewControllerTest20MockUIViewController: 0x7f9c0790d170>]->[<_TtCC8XXXTests27ContainerViewControllerTest20MockUIViewController: 0x7f9c07b643b0>] time = [0.009772]
    view Safearea Insets DidChange 호출 시기 가 이 르 고 view WillAppear 이후 불필요 한 애니메이션 이 생 긴 이 유 를 알 수 있 습 니 다.또한"pushvc"의 safeareaInsets 는 view SafeareaInsets DidChange 호출 전 까지 UIEdgeInsets Zero 이 고 그 다음 에 야 정확 한 UIEdgeInsets(top:44.0,left:0.0,bottom:34.0,right:0.0)입 니 다.
    또한 view Safearea Insets Did Change 뒤에 view Did Layout Subviews 를 두 번 호출 하기 때문에 높이 나 레이아웃 을 바 꾸 는 코드 를 모두 view Did Layout Subviews 에 써 야 합 니 다.그러면 불필요 한 애니메이션 효과 가 없 을 것 입 니 다.view Did Layout Subviews 는 다른 작업 에 의 해 자주 실 행 될 수 있 으 므 로 safeArea 레이아웃 을 조정 하 는 코드 가 오래 걸 리 면 상태 표 시 를 추가 하여 didChange 후 한 번 만 레이아웃 조정 을 수행 하 는 것 을 고려 할 수 있 습 니 다.
    마지막 코드 는 이렇게 생 겨 야 돼 요.
    
    - (void)viewDidLayoutSubviews {
     [super viewDidLayoutSubviews];
     UIEdgeInsets safeAreaInsets = sgm_safeAreaInset(self.view);
     CGFloat height = 44.0; //         ,   44.0
     height += safeAreaInsets.top > 0 ? safeAreaInsets.top : 20.0; // 20.0 statusbar   ,    statusbar   
     if (_navigationbar && _navigationbar.height != height) {
      _navigationbar.height = height;
     }
    
    전후의 효과 에 적합 하 다

    어울리다.

    배합 후
    이렇게 하면 frame 레이아웃 과 autolayot 레이아웃 의 여러 가지 상황 에 대해 동태 적 인 적합 방안 이 생 겼 습 니 다.바로 safearea LayoutGuide 와 safearea Insets 를 사용 하여 구 조 를 유연 하 게 처리 하 는 것 입 니 다.고정 거 리 를 쓰 는 것 보다 현재 와 미래의 각종 기종 이 코드 를 조합 할 수 있 고 확장 성 이 좋 습 니 다.우리 프로젝트 도 현재 이런 방법 을 사용 하고 있 습 니 다.만약 당신 의 프로젝트 가 가로 세로 화면 이나 UI 컨트롤 의 배치 가 상대 적 으로 복잡 하 다 면 safeArea 를 사용 하 는 것 을 고려 해 야 합 니 다.
    참고 로 VFL 은 이미 폐 기 된 것 같 습 니 다.왜냐하면|부모 view 의 가장자리 만 표시 할 수 있 고 부모 view 의 safearea LayoutGuide 의 가장 자 리 를 표시 하 는 기호 가 하나 도 없 기 때 문 입 니 다.예전 에 우리 가 쓴 VFL 코드 는 많이 고 쳐 야 하고 고 쳐 도 매우 번 거 로 웠 습 니 다.더 이상 VFL 을 사용 하지 말 것 을 권장 합 니 다.
    마지막 버 전 판단 의 문제 입 니 다.safearea Insets 와 safearea LayoutGuide 는 모두 iOS 11 의 API 입 니 다.패 키 징 을 하지 않 고 코드 에 직접 쓰 면 대량의@available 라 는 버 전 판단 문 이 나타 날 것 입 니 다.코드 에@available 가 곳곳에 있 고 붕괴 되 어 코드 의 가 독성 을 파괴 할 것 입 니 다.
    제 가 예전 에 자동 레이아웃 프레임 워 크 를 썼 기 때문에 이번 에는 safearea LayoutGuide 와 버 전 판단 을 모두 안에 포 장 했 습 니 다.개인 적 으로 이 프레임 워 크 가 NSLayoutAnchor 보다 좋다 고 생각 합 니 다.주요 역할 은 레이아웃 코드 를 간소화 하 는 것 입 니 다.다음은 NSLayout Constraint 의 대 비 를 생 성 하 는 것 입 니 다.
    
    //    topLeftView top  self.view safeAreaLayoutGuide top
    //     API
    if (@available(iOS 11.0, *)) {
      [NSLayoutConstraint constraintWithItem:self.topLeftView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view.safeAreaLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
     } else {
      [NSLayoutConstraint constraintWithItem:self.topLeftView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
     }
    
    //   NSLayoutConstraint-SSLayout
    self.topLeftView.top_attr = self.view.top_attr_safe
    
    
    비 즈 니스 코드 에 서 는 버 전 판단 이 나 오지 않 습 니 다.관심 이 있 으 시 면 해 보 세 요.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기