스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
UIKit의 새로운 기능
UIKit의 최신 업데이트 및 향상된 기능을 확인하고 더 우수한 iPadOS, iOS 및 Mac Catalyst 앱을 빌드하는 방법을 배울 수 있습니다. UI 개선 사항, 생산성 업데이트, API의 향상된 기능 등을 안내합니다. 또한 향상된 성능, 보안 및 개인 정보 보호에 대해 알아볼 수 있습니다.
리소스
- Building a desktop-class iPad app
- centerItemGroups
- UICalendarView
- UINavigationItem.ItemStyle
- UIPageControl
관련 비디오
WWDC22
- 데스크탑급 편집 상호 작용 도입
- 데스크탑급 iPad 소개
- 데스크탑급 iPad 앱 빌드
- SF Symbols에 가변 색상 도입
- Swift 동시성 시각화 및 최적화
- Swift Concurrency를 사용하여 데이터 경합 제거
- TextKit 및 텍스트 보기의 새로운 기능
- UIKit과 SwiftUI 사용
- What's new in SF Symbols 4
WWDC21
-
다운로드
iOS 16의 'UIKit 변경 사항' 안내 영상입니다 저는 Dima이고 UIKit 팀의 엔지니어링 매니저죠 UIKit는 앱을 관통하는 강력한 프레임워크입니다 iOS 16의 새로운 기능을 지원하기 위해 업데이트했죠
이 영상에서는 생산성을 위한 UI 개선과 컨트롤 개선 사항 API 개선 사항을 다루며 UIKit와 SwiftUI를 함께 사용할 수 있는 멋진 방법에 관해 이야기하겠습니다
또한 UIKit으로 깔끔하고 눈에 띄는 사용자 인터페이스를 선보였는데 개선된 내비게이션 바에는 새로 적용된 타이틀 메뉴와 찾아 바꾸기가 적용됐으며 자르기, 복사하기, 붙이기 등의 편집 인터랙션을 개선하여 문서 기반의 애플리케이션을 개선할 수 있습니다 먼저 내비게이션 바를 살펴볼 건데 데스크톱 수준의 도구모음 기능을 지원하기 위해 업데이트했죠
iOS 16의 UIKit은 2개의 내비게이션 방식을 추가하여 문서 기반의 앱을 지원하는데요 브라우저와 편집기입니다
브라우저 스타일은 웹과 문서 브라우저처럼 이력이나 폴더 구조를 이용하여 탐색하기에 적합합니다
편집기는 문서 편집을 고려하여 만든 인터페이스죠
iOS 16에서는 앱에 바 버튼을 추가할 수 있는데 하위 그룹에 속한 버튼은 내비게이션 바 중앙에 배치되죠
메뉴에서 '도구모음 커스텀 편집'을 탭 하면 팝업창에서 항목을 드래그하여 재배치할 수 있습니다
새롭게 구성한 설정은 계속 유지되죠
예를 들어 다른 앱을 함께 실행하여 크기를 맞춰야 하는 상황이 발생하면 시스템에서 자동으로 오버플로 메뉴를 제공하여 공간이 부족해 밀려난 항목에 접근할 수 있습니다
새로운 내비게이션 스타일에 맞는 타이틀 메뉴를 추가하여 기본적인 기능을 지원하죠 복제, 이동, 이름 바꾸기 내보내기, 인쇄 등입니다 이런 항목은 delegate 메서드를 적용했을 때 자동으로 메뉴에 나타나죠 타이틀 메뉴에 커스텀 항목을 추가할 수도 있습니다
또한 Mac Catalyst로 빌드한 앱은 개선된 내비게이션 바를 이용할 수 있는데 NSToolbar와 매끄럽게 통합되며 추가 코딩도 필요하지 않습니다
iOS 16은 여러 앱에 걸쳐 텍스트를 편집하는 방법을 도입했죠 첫 번째는 새롭게 바뀐 찾아 바꾸기입니다 개념적으로는 데이터 모델 객체로 운영되는 사진이나 달력의 행사 같은 높은 수준의 인 앱 검색과 다르죠 찾아 바꾸기는 텍스트에 맞게 설계됐습니다 UITextView나 WKWebView와 같은 내장된 UIKit 뷰에서 플래그를 설정하면 이 기능을 활성화할 수 있죠
또한 이 시스템을 적용한 여러 뷰와 문서에 걸쳐 매끄럽게 작동합니다
다음으로 편집 메뉴도 대규모로 업데이트됐죠 입력 방식에 따라 다르게 보입니다 터치 인터랙션의 경우 상호작용성을 강화한 메뉴로 다시 설계했죠
포인터를 사용할 때는 모든 기능이 들어 있는 컨텍스트 메뉴가 나타납니다
이러한 경험을 매끄럽게 제공하기 위해 UIEditMenuInteraction을 도입하여 이제 사라진 UIMenuController를 대체하죠
또한 텍스트 뷰 메뉴에 액션을 삽입하는 API도 생겼습니다
'데스크톱 수준의 편집 인터랙션 적용' 동영상에서 새로운 편집 메뉴의 자세한 사항과 커스텀 뷰에서 검색 인터렉션을 적용하는 법을 알아보십시오
시각적인 UI 업데이트 사항도 다루겠습니다 iOS 16에서 Slide Over 모드의 사이드바는 추가 코드가 없어도 활성화되죠 이를 위해 UIKit에서 몇 가지 개인 뷰를 관리합니다
다음은 UIKit의 새로운 생산성 향상 기능이죠 커스텀 설정이 가능한 내비게이션 바 찾아 바꾸기 편집 인터랙션 그리고 유용한 타이틀 메뉴입니다 이 세션은 기본적인 내용만 다루는데요 '데스크톱 수준의 iPad 만나기' 세션에도 추가 정보가 있고 '데스크톱 수준의 iPad 앱 만들기' 세션에서도 자세하게 다루는데 iOS 16의 개선된 UIKit 기능을 적용하여 샘플 앱을 개선하는 작업을 자세히 볼 수 있습니다
이제 우리가 추가한 2개의 새로운 컨트롤을 소개하고 UIPageControl의 개선 사항을 논의하죠
UIDatePicker의 캘린더 스타일을 사용할 수 있는데 UICalendarView의 형태로 모든 기능이 있는 독립 요소입니다 UICalendarView는 다양한 선택 동작을 지원하는데 선택적인 단일 날짜나 여러 날짜의 선택이 가능하죠 가능한 날짜 범위 설정은 물론 선택 범위에서 일부 날짜를 제외하는 기능도 있습니다
또한 각 날짜를 장식할 수도 있죠
UICalendarView와 UIDatePicker의 차이점은 UICalendarView가 날짜를 표현할 때 NSDate가 아닌 NSDateComponents로 나타내는 거죠 NSDate와 달리 날짜 요소는 특정 날짜를 더 정확하게 대표하지만 NSDate는 시간의 한 지점을 나타냅니다
NSDateComponents의 개념이 매우 유연하므로 어떤 NSCaledar를 사용하는지 명확하게 지정해야 하죠
현재 달력 유형에 관해 가정하면 안 됩니다 달력을 그레고리력으로 설정해야 한다면 그레고리력이라고 명확하게 지정해야 하죠
이전에 봤던 캘린더 뷰처럼 설정하려면 먼저 캘린더 뷰를 만들어 대리자를 설정하십시오 그레고리력 NSCalendar가 캘린더를 지원하도록 calendarView의 캘린더 속성을 그레고리력 NSCalendar로 설정하세요
다음은 여러 날짜 선택을 설정하기 위해 UICalendarSelectionMultiDate 객체를 만들고 선택 객체의 선택 날짜 속성을 여러분의 데이터 모델에 있는 기존 날짜에 설정하여 캘린더 뷰에 나타나게 하십시오
그리고 선택 객체를 캘린더 뷰의 selectionBehavior에 설정하세요
캘린더의 개별 날짜 선택을 방지하기 위해 캘린더 선택 대리자에서 multiDateSelection:canSelectDate 메서드를 적용하여 선택할 수 있는 날짜를 제어하십시오
선택할 수 없는 날짜는 캘린더 뷰에서 회색으로 표시되죠
개별 날짜에 장식을 달고 싶다면 캘린더 대리자의 매서드인 calendarView:decorationForDate Components:를 적용하세요
장식이 없으면 nil을 반환하세요
기본값인 회색 원은 기본 장식을 반환하십시오
색상을 커스텀 설정할 수 있는 이미지 장식도 만들 수 있죠 더 필요하면 customView 장식을 사용하여 뷰 제공자에서 여러분의 뷰를 반환하세요
커스텀 뷰 장식은 인터랙션을 허용하지 않으며 공간에 고정되어 있다는 점을 유의하십시오
페이지 컨트롤도 개선됐습니다 현재 페이지에 커스텀 표시 이미지를 추가하여 페이지의 선택 여부에 따라 다른 이미지를 선택할 수 있습니다
이제 페이지 컨트롤의 지향이나 방향을 커스텀으로 설정할 수 있죠
세로형 페이지 컨트롤을 설정하는 예입니다 현재와 현재가 아닌 페이지 사이에서 인디케이터가 바뀌죠
저는 페이지 컨트롤의 방향을 위에서 아래로 설정했고 선호하는 인디케이터와 현재 인디케이터의 이미지를 설정하면 끝입니다
Apple은 사용자 개인 정보와 보안을 지키려고 노력합니다 iOS 15에서는 애플리케이션이 프로그램적으로 시스템의 붙여넣기 인터페이스를 통하지 않고 클립보드에 접근하면 클립보드에 접근했다는 배너가 나타났죠
iOS 16에서 시스템의 원리가 바뀌었습니다 이제는 배너 대신 클립보드의 사용 허가를 묻는 알림창이 나타나죠
사용자가 시스템의 붙여넣기 인터페이스를 사용하면 클립보드에 대한 암묵적인 접근을 제공하여 알림을 피할 수 있습니다
만약 커스텀 붙여넣기 컨트롤이 있다면 새로 개발된 UIPasteControl로 대체할 수 있으며 채워진 UIButton과 모습과 동작이 비슷하죠
컨트롤의 붙여넣기 대상과 호환되는 콘텐츠가 클립보드에 들어가면 활성화됩니다
지금까지 성능이 좋은 UICalendarView와 개선된 UIPageControl 보안 중심의 UIPasteControl을 알아봤죠 직접 사용해 보십시오 이제 API 개선 사항을 짚어드리겠습니다
iOS 15에서는 시트에 디텐트를 추가하여 유연하고 역동적인 UI를 구축할 수 있었죠 iOS 16에서는 커스텀 디텐트를 지원하여 시트의 크기를 마음대로 조정할 수 있습니다
이 기능을 활용하려면 .custom 디텐트를 사용하여 관련된 블록의 포인트로 시트의 높이를 지정하십시오 일정한 값을 반환해도 되고 디텐트 최대 높이의 비율을 반환해도 됩니다
다른 API에서 참조해야 한다면 커스텀 디텐트에 식별자를 줄 수도 있죠 예를 들어 커스텀 디텐트에서 투명도 조절을 끌 수도 있습니다
커스텀 블록에서 반환하는 값은 아래의 안전 공간 인셋을 고려하지 않아도 되죠 플로팅이나 모서리에 고정된 시트에도 같은 계산이 적용됩니다
시스템 디텐트와 다른 옵션을 통한 시트의 커스텀 설정에 관해서는 'UIKit에서 시트 커스텀 설정과 크기 바꾸기'를 시청하십시오 해당 영상의 샘플 코드를 업데이트하여 커스텀 디텐트 API 내용을 반영했습니다
UIKit의 SF Symbols에도 새로운 기능이 있죠 Symbols는 4개의 렌더링 모드를 지원합니다 모노크롬, 멀티컬러 계층형, 팔레트가 있죠 심벌이 다른 렌더링 모드를 사용하지 않는 이상 UIKit는 기본값으로 모노크롬을 설정합니다 iOS 16에서 UIKit는 개별 심벌을 렌더링할 때 렌더링 모드가 지정되지 않은 경우 모노크롬이 아닌 모드를 사용할 수 있죠
기기 심벌을 예로 들겠습니다 iOS 15와 그 이전에는 다른 렌더링 모드를 지정하지 않았을 때 모노크롬 렌더링을 사용했죠
iOS 16에서는 이 심벌의 기본값은 계층형 렌더링입니다
일반적으로 심벌의 기본 렌더링 모드는 심벌을 표시하는 선호 방식이죠 따라서 이 경우에는 기본값인 계층형 렌더링을 허용해야 합니다 모노크롬 렌더링을 명시적으로 요청하고 싶을 때 쓸 수 있는 건 UIImage.SymbolConfiguration. preferringMonochrome() API입니다
UIKit는 변수 심벌도 지원하여 0과 1 사이의 값에 따라 심벌의 변화를 나타낼 수 있죠 현재 볼륨 수준을 심벌로 나타낸다고 합시다 앱에서 speaker.3.wave.fill 심벌을 사용할 수 있는데 변수 렌더링을 지원하도록 업데이트했죠 값이 0일 때는 스피커의 음파를 흐리게 하여 가장 낮은 볼륨 수준을 표현합니다 값이 1로 증가할수록 스피커의 음파가 점점 채워지면서 더 높은 볼륨 수준을 표현하죠
만약 심벌이 변수 렌더링을 지원한다면 0과 1 사이의 값을 반영한 심벌을 앱에서 요청할 수 있습니다
변수 심벌을 사용하면 직관적이죠 변수가 제거된 형태의 일반 심벌과 표준 SF Symbols API는 UIImage에 있습니다
변수의 값이 포함된 버전의 심벌을 원하신다면 variableValue 매개 변수를 추가하십시오
변수 렌더링과 다른 렌더링 모드를 혼합할 수도 있죠 예를 들어 팔레트 모드로 심벌을 꾸밀 수 있습니다
많은 시스템 심벌이 변수 렌더링을 지원하며 커스텀 심벌을 업데이트하여 다양성을 지원할 수도 있죠
커스텀 변수 심벌을 만드는 법이 궁금하시면 'SF Symbols에 변수 색상 적용하기' 세션과 'SF Symbols 4 변경 사항'을 확인하십시오
Swift Concurrency 기능에 맞춰 UIKit를 개선했는데 불변의 유형인 UIImage와 UIColor를 Sendable에 맞추는 작업을 통해 MainActor와 커스텀 액터 사이에서 컴파일러 경고문 없이 보낼 수 있죠
예를 들어 Processor라는 커스텀 액터와 ImageViewer라는 뷰 컨트롤러가 있는데 이는 MainActor에 바인딩 되어 있죠 sendImageForProcessing 메서드에서 ImageViewer가 Processor 액터에 처리를 위해 이미지를 보내서 반짝이나 무지개 등을 추가할 수 있게 됩니다 UIImage가 불변이므로 안전하며 Processor가 새로운 복사본을 만들어 무지개나 반짝이를 추가할 수 있죠
원본 이미지를 참조하는 모든 코드는 이러한 수정 사항을 나타내지 않으며 공유 상태는 불안전하게 변환되지 않습니다
반면 UIBezierPath는 불변이 아니어서 전송할 수 없죠
이전에는 문서로만 표현할 수 있었던 것을 컴파일러로 확인할 수 있으면 얼마나 멋질까요?
Sendable과 Swift Concurrency에 관해 더 알고 싶다면 'Swift Concurrency로 데이터 레이스 없애기'와 'Swift Concurrency 시각화 및 최적화' 영상을 확인하십시오
iOS 16은 외부 디스플레이를 위해 강력한 성능을 지원합니다 또한 이 기능을 활용하기 위해 앱을 업데이트하지 않아도 되죠 UIScreen API를 사용하는 경우는 제외합니다
이제 앱이 메인 화면에 있다고 가정하지 않아도 되죠 대신 더 구체적인 API를 따를 수 있습니다 특성 수집 및 UIScene API를 통해 원하는 정보를 얻을 수 있죠 여러분의 앱이 아직도 UIScene을 사용하지 않는다면 업그레이드하셔서 다중 창도 지원하십시오
UICollectionView의 알아서 크기를 맞추는 셀과 UITableView가 크게 업데이트됐죠 이제 셀이 알아서 크기를 바꿉니다 iOS 16에서는 보이는 셀의 콘텐츠가 바뀌었을 때 새로운 콘텐츠에 맞춰 자동으로 셀 크기를 조정하죠
이 동작은 기본적으로 활성화되어 있으며 UICollectionView와 UITableView는 selfSizingInvalidation 속성이 추가되어 이 기능을 제어할 수 있게 됐습니다
원리를 알려 드리죠
selfSizingInvalidation이 활성화되어 있으면 셀은 크기 조정을 요청하는데 소속된 집단이나 테이블 뷰를 통합니다
UIListContentConfiguration으로 셀을 설정한다면 셀의 설정이 바뀔 때마다 자동으로 무효 처리가 되죠
다른 경우에는 셀이나 셀의 contentView의 invalidateIntrinsicContentSize 메서드를 호출하여 조정하세요
기본값은 크기를 바꿀 때 애니메이션이 나타나는데 invalidateIntrinsicContentSize를 호출하는 걸 performWithoutAnimation 안에 래핑하면 애니메이션이 안 나오죠 UICollectionView와 UITableView는 스마트하게 셀의 크기 무효 처리를 최적의 시기에 하나의 업데이트로 수행하도록 통합합니다
만약 셀에서 자동 레이아웃을 사용한다면 enabledIncludingConstraints를 선택하여 더 포괄적인 동작으로 옵트인 할 수 있습니다 만약 셀이 contentView 내에서 자동 레이아웃 변경을 감지하면 invalidateIntrinsicContentSize를 자동으로 호출하여 소속된 컬렉션이나 테이블 뷰의 크기를 조정하죠 이를 통해 아주 쉽게 콘텐츠나 레이아웃이 변경될 때마다 자동으로 셀의 크기를 조정할 수 있습니다
UIKit는 성능이 좋고 유연하죠 SwiftUI를 사용하면 UI를 적용할 때 더 풍성하게 표현할 수 있습니다 같은 앱에 두 프레임워크를 쉽게 적용할 수 있도록 했죠
iOS 16에서는 SwiftUI를 이용하여 완전히 새로운 방식으로 컬렉션과 테이블 뷰를 위한 셀을 만들 수 있습니다
UIHostingConfiguration이라는 새로운 콘텐츠 설정 유형으로 이런 작업을 할 수 있게 됐죠 코드 한 줄이면 SwiftUI를 셀 안에서 바로 작성할 수 있습니다 추가 뷰나 뷰 컨트롤러가 필요 없죠
UIHostingConfiguration을 사용하여 SwiftUI로 작성한 간단한 커스텀 셀입니다 이 셀을 만드는 것이 정말 간단하죠
여러분의 앱에 SwiftUI를 통합하는 정말 좋은 방식이고 SwiftUI의 풍부한 표현성을 통해 UIKit에서 커스텀 셀을 만드는 게 그 어느 때보다도 효과적으로 되었습니다 이와 관련한 주제가 더 많죠 더 알아보고 싶다면 'UIKit로 SwiftUI 사용하기'를 시청하십시오
여러분이 알아 두어야 할 작지만 중요한 변경 사항이 있죠 사용자가 추적되는 것을 방지하기 위해 UIDevice.name은 사용자의 커스텀 기기 이름이 아닌 모델 이름을 반환합니다 커스텀 설정한 이름을 이용하려면 권한을 받아야 하죠
UIDevice.orientation 설정은 이제 지원하지 않습니다 UIViewController API인 preferredInterfaceOrientation을 사용하여 인터페이스의 의도된 방향을 지정하십시오
다음 단계는 뭘까요? iOS 16 SDK를 이용하여 앱을 컴파일하십시오 텍스트 편집 메뉴나 찾아 바꾸기 같은 새로운 기능을 테스트하세요 새로운 UIKit API를 적용하여 개선된 컨트롤과 생산성 향상 기능을 적용하십시오 또한 UIKit 앱에 SwiftUI를 통합하는 새로운 방식을 시도해 보세요 감사합니다
-
-
7:51 - Configuring a UICalendarView with multi-date selection
// Configuring a calendar view with multi-date selection let calendarView = UICalendarView() calendarView.delegate = self calendarView.calendar = Calendar(identifier: .gregorian) view.addSubview(calendarView) let multiDateSelection = UICalendarSelectionMultiDate(delegate: self) multiDateSelection.selectedDates = myDatabase.selectedDates() calendarView.selectionBehavior = multiDateSelection func multiDateSelection( _ selection: UICalendarSelectionMultiDate, canSelectDate dateComponents: DateComponents ) -> Bool { return myDatabase.hasAvailabilities(for: dateComponents) }
-
9:07 - Configure UICalendarView decorations.
// Configuring Decorations func calendarView( _ calendarView: UICalendarView, decorationFor dateComponents: DateComponents ) -> UICalendarView.Decoration? { switch myDatabase.eventType(on: dateComponents) { case .none: return nil case .busy: return .default() case .travel: return .image(airplaneImage, color: .systemOrange) case .party: return .customView { MyPartyEmojiLabel() } } }
-
10:16 - Setting up a vertical UIPageControl with custom indicators
// Vertical page control with custom indicators pageControl.direction = .topToBottom pageControl.preferredIndicatorImage = UIImage(systemNamed: "square") pageControl.preferredCurrentIndicatorImage = UIImage(systemNamed: "square.fill")
-
12:21 - Creating a custom sheet detent
// Create a custom detent sheet.detents = [ .large(), .custom { _ in 200.0 } ]
-
12:38 - Creating a custom sheet detent using a percentage of maximum detent height
// Create a custom detent sheet.detents = [ .large(), .custom { context in 0.3 * context.maximumDetentValue } ]
-
12:42 - Assigning identifiers to custom sheet detents
// Define a custom identifier extension UISheetPresentationController.Detent.Identifier { static let small = UISheetPresentationController.Detent.Identifier("small") } // Assign identifier to custom detent sheet.detents = [ .large(), .custom (identifier: .small) { context in 0.3 * context.maximumDetentValue } ] // Disable dimming above the custom detent sheet.largestUndimmedDetentIdentifier = .small
-
22:16 - UIHostingConfiguration example
cell.contentConfiguration = UIHostingConfiguration { VStack { Image(systemName: "wand.and.stars") .font(.title) Text("Like magic!") .font(.title2).bold() } .foregroundStyle(Color.purple) }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.