스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
데스크탑급 편집 상호 작용 도입
앱에서 사용자의 생산성 속도를 높일 수 있는 고급 데스크탑급 편집 기능을 확인하세요. UI에 최적화된 더 많은 상호 작용을 제공하여 사용자가 편집 기능에 빠르게 액세스하도록 지원하고, Mac Catalyst를 통해 macOS에 맞게 iPadOS 앱을 최적화하는 방법을 알아보세요. 또한 고도로 맞춤화 가능한 찾기 상호 작용에 대해 알아보고, 시스템 UI를 통해 사용자가 앱에서 콘텐츠를 일관성 있게 찾을 수 있도록 지원하는 방법을 알아봅니다..
리소스
- Building a desktop-class iPad app
- Supporting desktop-class features in your iPad app
- UIEditMenuInteraction
- UIFindInteraction
관련 비디오
WWDC22
WWDC19
-
다운로드
안녕하세요 '데스크톱급 편집 상호 작용 도입’ 영상입니다 제 이름은 Andy고 UIKit 프레임워크 엔지니어죠 잠시 후 동료인 James도 함께할 겁니다 iPad는 계속 발전하고 있고 인터랙션을 통해 간단하고 쉽게 사용할 수 있죠 이 영상에서는 새로운 편집 인터랙션을 통해 여러분의 앱을 데스크톱 수준으로 바꿔 줄 겁니다 먼저 iOS 16에서 크게 바뀐 새로운 편집 메뉴부터 살펴보죠
나중에 James가 새로운 시스템인 찾아 바꾸기를 소개할 겁니다 iOS 16의 편집 메뉴에 새로운 기능이 추가됐는데 외관은 유지하면서 상호작용성을 높였고 동작은 더 찾기 쉬워졌죠 편집 메뉴는 입력 방식에 따라 다르게 나타납니다 터치 입력을 할 때는 편집 메뉴가 이전처럼 간결한 모습을 유지하지만 개선된 페이지 동작을 통해 이전보다 쉽게 동작을 찾을 수 있죠
Magic Keyboard나 트랙 패드를 사용하면 오른쪽 클릭을 통해 컨텍스트 메뉴를 호출하여 데스크톱 수준의 경험을 할 수 있습니다 iPhone에서도 터치 입력 시 새로운 편집 메뉴가 나타나죠
Mac Catalyst 앱의 경우 Mac 사용자에게 익숙한 컨텍스트 메뉴가 나타납니다 iOS 16에서 텍스트 편집 메뉴가 훨씬 개선되어 데이터 감지 기능이 추가됐죠 인라인 단위나 환율 변환 스마트 검색 등 선택한 텍스트에 맞는 동작이 나타납니다 예를 들어 Safari에서 주소를 선택하면 지도와 관련된 동작이 나타나죠 '길 찾기'나 '지도에서 열기' 등의 기능이 기존 편집 메뉴 동작 위에 나타납니다 가장 좋은 소식은 적용이 필요 없다는 거죠 이 기능은 모든 텍스트 편집 메뉴에 있어서 텍스트 상호작용 뷰와 WebKit, Safari, PDFKit에도 있죠
텍스트 뷰 메뉴에 동작을 넣으려면 TextViewDelegate를 적용하여 주어진 범위 내 텍스트의 표시 메뉴를 시스템 제공 동작과 함께 커스텀 설정하십시오 커스텀 설정이 필요 없다면 nil을 반환하면 표준 시스템 메뉴가 나옵니다 UITextFieldDelegate와 UITextInput 등 비슷한 메서드에서 메뉴를 커스텀 설정할 수 있죠 UIMenuController를 이용하여 메뉴 항목을 추가하는 건 iOS 16부터 지원하지 않습니다 이제는 다른 메서드를 사용하여 텍스트 편집 메뉴에 메뉴 항목을 추가할 수 있죠 앞으로는 메뉴 컨트롤러가 필요 없으니까요 커스텀 동작이 있는 텍스트 뷰의 예시입니다 텍스트 선택 영역에 메뉴를 표시할 때 커스텀 '강조' 및 '사진 삽입' 동작이 시스템 추천 동작 뒤에 나오죠 강조 동작을 선택하면 예상한 대로 텍스트가 강조됩니다 텍스트를 선택하지 않아 강조할 게 없을 때 메뉴를 선택하면 '사진 삽입' 동작만이 시스템 추천 동작 뒤에 나타납니다 새로운 API로 이 동작을 추가하는 법을 보여 드리죠 메뉴가 나타날 때 동적으로 동작을 넣으려면 UITextViewDelegate 메서드의 textView:editMenuForTextInRange: suggestedActions:를 적용하세요 이 예시에서 저는 텍스트를 선택했을 때만 '강조하기' 동작을 추가하여 이 메서드를 통해 동적으로 동작을 추가하고 싶습니다
'사진 삽입' 동작은 언제나 유효하므로 메뉴에 언제나 나타나도록 배열에 추가할게요 마지막으로 시스템 추천 동작에 저의 동작을 추가할 건데 잘라내기, 복사하기, 붙여넣기를 포함하며 메뉴를 반환하죠 그러면 끝입니다 UIEditMenuInteraction은 새 편집 메뉴의 API입니다
인터랙션을 통해 프로그래밍적으로 텍스트 뷰 밖에 있는 가벼운 편집 메뉴를 제스처에 따라 보여 줄 수 있죠 세컨더리 클릭을 통해 컨텍스트 메뉴도 나타납니다 iOS 16에서 UIMenuController와 관련된 모든 API는 새로운 editMenuInteraction으로 대체됐죠
편집 메뉴를 처음부터 만들려면 먼저 인터랙션을 만들어 뷰에 추가하세요 다음은 메뉴를 표시할 제스처 인식기를 설정하십시오 직접 터치했을 때만 메뉴가 나타나고 간접적인 포인터 클릭에 반응하지 않도록 제스처 인식기의 allowedTouchTypes 속성을 직접 터치로 설정하세요 이제 제스처 인식기를 뷰에 추가합니다 마지막으로 제스처 인식기가 신호를 보냈을 때 제스처 위치에 콘텐츠가 있는지를 판단하여 메뉴를 보여 주세요 제스처 위치의 소스 포인트에 편집 메뉴 설정을 만드십시오 소스 포인트는 인터랙션 뷰의 실행할 수 있는 동작을 결정하여 메뉴를 보여 줍니다
presentEditMenuWithConfiguration 메서드를 설정 후에 호출하여 메뉴를 보여 주세요
선택한 '젤로 안녕!' 뷰 영역 내 아무 곳이나 오른쪽 클릭하면 앱의 콘텐츠에 실행할 수 있는 시스템 동작이 있는 컨텍스트 메뉴가 나타납니다 또한, 선택한 뷰를 탭 하면 제가 터치한 곳에 편집 메뉴가 나타나서 컨텍스트 메뉴처럼 일부 동작을 보여 주죠 지금도 좋지만 더 좋게 할 수 있습니다 터치가 일어난 곳에서 메뉴가 나타나는 건 좋지만 선택 뷰의 콘텐츠를 가리는 문제가 있죠 또한 메뉴에 '복사하기' 동작을 추가하고 싶은데 시스템 기본 동작이 아닙니다 다시 가서 이걸 수정하죠 메뉴를 선택 뷰 주변에 나타내기 위하여 다음의 대리자 메서드를 적용하십시오 editMenuInteraction: targetRectForConfiguration:이죠 이 메서드가 반환하는 CGRect는 어디에 메뉴를 나타낼지 결정하며 인터랙션 뷰의 좌표 공간 안에 있습니다 메서드를 적용하지 않거나 CGRect 값이 null이면 메뉴가 설정의 소스 포인트에서 나타나죠 이 경우, 메뉴가 선택 뷰를 가리는 걸 방지하기 위해 프레임을 반환합니다 복사하기 동작을 추가하려면 다음을 적용하세요 editMenuInteraction: menuFor Configuration: suggestedActions: 그리고 시스템 추천 동작 뒤에 커스텀 동작을 추가하십시오 텍스트 뷰 메뉴에 동작을 추가했던 것과 비슷하죠
이제 선택 뷰를 한 번 더 탭 하면 '젤로 안녕!'을 가리지 않고 그 주변에 메뉴가 나타납니다 메뉴가 나타날 때 복사하기가 포함됐는데 코드 몇 줄로 가능했죠 멋집니다
Mac Catalyst 앱의 경우 편집 메뉴가 익숙한 컨텍스트 메뉴로 이어져서 Mac의 사용자들이 인터랙션 뷰를 오른쪽 클릭했을 때 예상하는 메뉴와 같게 나타나죠 iPad 관용어의 Mac Catalyst 앱은 프로그램적인 편집 메뉴가 컨텍스트 메뉴로도 이어집니다 프로그램적인 편집 메뉴가 Mac 관용어의 앱에는 지원되지 않는다는 것을 유의하십시오 서로 다른 프레젠테이션 스타일을 매끄럽게 연결하기 위해 UIMenuElement 종류의 API에 UIEditMenuInteraction을 구축했죠 이를 통해 유연성과 커스텀 활용도가 높아졌으며 하위 메뉴와 이미지도 지원합니다 UIMenu 사용이 처음이라면 'Modernizing Your UI for iOS 13'에서 메뉴와 동작에 관해 배워 보세요 UIMenuElement 위에 구축한다는 건 편집 메뉴가 다양한 API에 접근할 수 있다는 의미이며 이미 메뉴를 지원하는 UIMenuSystem도 사용할 수 있죠 편집 메뉴는 기존의 UIMenuSystem.context를 사용하여 메뉴를 구축합니다 메뉴 구축에 관해 더 알고 싶거나 리스폰더 체인 순회와 커맨드 유효성 검사가 궁금하시면 'Taking your iPad apps to the next level'를 시청하십시오
메뉴 얘기가 나왔으니 말인데 iOS 16에 UIMenu가 많이 개선됐죠 UIMenu의 요소 크기 속성이 추가되어 컨텍스트 메뉴의 레이아웃 중 하나를 고를 수 있습니다 소형은 메뉴 안에 각 요소를 병렬로 배치하여 한 줄에 더 많은 동작을 배치하죠 중형도 동작을 병렬로 배치하지만 정보가 조금 더 많습니다 표준 편집 메뉴를 나타내기 위해 텍스트 편집 메뉴를 사용했죠 마지막으로 대형은 기본 메뉴를 전체 폭으로 보여 줍니다 추가로 .keepsMenuPresented 속성이 UIMenuElement에 생겼는데 동작을 수행한 뒤에도 메뉴가 계속 나타나죠 이 속성을 사용하면 동작을 여러 번 수행하면서도 메뉴를 유지할 수 있습니다 새로운 편집 메뉴는 더 많은 사항이 개선됐죠 텍스트 편집 메뉴 커스텀화로 텍스트 편집 기능을 확장하고 동작에 제목과 이미지가 나타나도록 하여 어떤 형태의 메뉴도 완전한 모습으로 보입니다 가장 중요한 것은 UIEditMenuInteraction을 적용하여 다양한 플랫폼과 입력 방식에도 일관성을 유지하고 커스텀 활용도를 높였죠 새로운 편집 메뉴를 적용하는 건 훌륭한 출발점입니다 데스크톱 수준의 편집 경험을 완성하기 위해 James에게 넘겨 찾아 바꾸기 경험에 관해 알아보죠
아, 여기 있었네요 저는 James Magahern이며 UIKit 엔지니어입니다 찾아 바꾸기에 관해 말씀드리려고 이 자리에 나왔죠 iOS 16부터 앱의 텍스트를 찾아 바꾸는 새로운 UI 요소를 추가했습니다 시스템 전반에 적용됐으며 내장 앱에 포함되어 있어 사용자가 몸으로 기억하는 편집 단축키를 더 많이 추가했습니다 이건 iPad의 새로운 찾기 패널인데요 하드웨어 키보드를 장착했을 때는 플로팅 단축키 바를 사용하다가 하드웨어 키보드를 사용하지 않을 때는 자동으로 소프트웨어 키보드 위에 패널이 나타나도록 전환하죠 iPhone의 경우 더 작은 화면 크기에 맞춰 더 축소된 레이아웃을 사용합니다 자동 기각, 최소화 키보드 회피는 전부 시스템에서 관리하죠 Mac에서 여러분의 앱을 실행하면 콘텐츠 안에 찾기 패널이 나타나도록 하며 AppKit 찾기 바와 똑같이 동작하고 Mac 사용자에게 익숙한 레이아웃을 사용합니다
UITextView, WKWebView PDFViews를 이용하여 앱의 텍스트 콘텐츠를 표시한다면 isFindInteractionEnabled를 true로 설정하면 됩니다 내장된 찾기 인터랙션에서요 그 정도로 쉽죠 또한 텍스트 콘텐츠를 QuickLook으로 표시한다면 추가 작업 없이 바로 사용할 수 있습니다
하드웨어 키보드를 사용하면 기본적인 단축 키인 찾기의 커맨드 F와 다음 찾기인 커맨드 G 이전 찾기인 커맨드 시프트 G를 예상대로 사용할 수 있죠 Mac을 실행할 때 메뉴 바에 단축키가 있습니다 콘텐츠를 표시하는 뷰가 첫 리스폰더가 될 수 있다는 걸 확실히 하면 되죠 하드웨어 키보드를 사용하지 않는 사용자는 findInteraction 속성의 presentFindNavigator로 프로그램적으로 찾기 인터랙션을 인보크 할 수 있습니다 예를 들어 내비게이션 바 아이템을 통해 이 기능을 활용하는 것이 좋을 겁니다
Mac에서 실행할 때는 유념해야 할 상황이 있죠 예를 들어 iOS에서는 찾기 패널이 소프트웨어 키보드나 단축키 바의 일부로 표시됩니다 맥에서는 콘텐츠 안에 찾기 패널을 표시하죠 스크롤 뷰에 찾기 인터랙션을 설치한다면 찾기 패널을 넣기 위해 콘텐츠 인셋을 자동으로 조정하고 자동으로 속성 수집 변화에 적응할 겁니다 그렇지 않은 경우 macOS의 UI에 찾기 패널을 넣을 공간이 있는지 확인해야 하죠
또한 돋보기 아이콘을 클릭하면 표준의 찾기 옵션이 있는 메뉴를 보여 드립니다 이 메뉴의 콘텐츠는 커스텀 설정할 수 있으며 optionsMenuProvider가 있는 UIFindInteraction을 사용하세요 커스텀 설정 적용에는 이게 더 중요할 겁니다 제가 언급했던 내장 뷰 중 하나를 사용한다면 그 작업만 하면 되죠 만약 여러분의 앱이 다른 방법으로 텍스트 콘텐츠를 표시하여 완전한 커스텀 뷰나 이런 형태의 리스트 뷰를 사용해도 찾기 인터랙션을 앱에 추가할 수 있습니다 방법을 보여 드리죠
찾기 인터랙션의 좋은 점은 모든 임의의 뷰에도 설치할 수 있다는 겁니다 앱에 찾아 바꾸기 기능을 이미 적용했다면 UIFindInteraction으로 넘어와서 시스템의 UI를 활용하는 것도 쉽습니다 커스텀 뷰에 찾기 기능을 적용하지 않았더라도 시작하는 건 어렵지 않죠 UITextInput 프로토콜을 적용했다면 시스템 키보드를 활용하는 것이 쉽습니다 UIFindInteraction이 커스텀 뷰에서 작동하는 방식이죠 커스텀 뷰에 UIFindInteraction을 설치한 뒤 UIFindInteractiondelegate를 설정하십시오 UIFindInteractiondelegate는 찾기 세션의 시작과 종료를 알게 되는 것 이외에도 UIFindSessions을 분배하는 역할을 합니다 UIFindSession은 추상 기반 클래스로 주어진 세션의 모든 상태를 포괄하는데 현재 강조 중인 결과도 포함하죠 또한 UI에서 요청한 모든 동작을 수행하는데 '다음 결과로 가기'나 '이 스트링에서 찾기'가 있습니다 이 모든 상태를 직접 관리하고 싶다면 찾기 인터랙션 대리자의 UIFindSession의 하위 클래스를 사용하는 방법도 있죠
여러분의 앱에 찾아 바꾸기 기능이 있는데 시스템 UI로 연결하고 싶다면 그것도 좋은 방법입니다 시스템이 상태를 대신 관리하는 것은 훨씬 더 좋은 방법이죠 현재 문서의 콘텐츠를 포괄하고 있는 클래스에 UITextSearching 프로토콜을 적용하는 것입니다 이를 위해 반환해야 하는 건 UITextSearchingFindSession이며 문서 클래스와 연결하십시오 여러분의 커스텀 뷰에 찾기 기능이 없을 때 가장 좋은 방법입니다 코드로 보여 드리죠
이 예시는 커스텀 문서 클래스가 있으며 이 문서를 보여 주는 커스텀 뷰가 있습니다 UIFindInteraction은 이 뷰에 설치되며 UITextSearchingFindSession은 '검색할 수 있는 객체'로 이 문서와 함께 제공되죠 여러분의 뷰 컨트롤러나 커스텀 뷰를 첫 번째 리스폰더로 설정해야 키보드 단축 키가 잘 작동합니다
찾기 인터랙션을 만들고 세션 대리자를 제공하여 찾기 세션을 분배하세요 여기서는 뷰 컨트롤러가 세션 대리자입니다 인터랙션이 찾기 세션을 요청하면 UITextSearchingFindSession을 반환하여 여러분의 문서를 찾을 수 있는 객체로 제공하세요 물론 여러분의 문서 클래스가 UITextSearching 프로토콜에 맞아야 합니다
UITextSearching 프로토콜을 적용하는 클래스는 여러분의 문서에서 텍스트를 찾는 역할을 하죠 시스템은 performTextSearch를 호출하며 집합자 객체에 넘겨 결과를 제공할 수 있습니다 집합자는 UITextRange와 함께 문서의 결과를 나타내죠 이건 여러분이 사용할 수 있는 또 다른 추상 클래스로 텍스트를 저장하는 데이터를 포괄할 수 있습니다 예를 들어 WebKit로 텍스트를 렌더하는 고객에게는 이것이 DOM 범위를 나타낼 수 있죠 이 통합자는 스레드 안전이 보장되어 백그라운드 스레드에도 결과를 제공할 수 있습니다 마지막으로 찾기 인터랙션은 여러분의 커스텀 뷰로 결과를 나타내는 방법을 모르므로 decorate()를 호출했을 때 주어진 양식으로 데코레이션하세요 UITextSearching 찾기 세션과 프로토콜은 다중의 문서에 걸쳐 같은 인터랙션을 이용하여 멀티플렉싱을 지원합니다 그 말은 여러분의 앱이 콘텐츠를 표시할 때 Mail의 대화 뷰와 비슷한 방식으로 표시되어 각 문서가 우편함의 메시지인 경우라면 루트 레벨 컬렉션 뷰에 단일 찾기 인터랙션을 설치하고 모든 문서에 걸쳐 동시에 찾기를 수행하여 사용자가 다양한 문서의 결과를 쉽게 탐색할 수 있게 하십시오 iOS 16의 새로운 찾기 인터랙션은 이렇게 쉽게 시작할 수 있습니다 텍스트 콘텐츠를 많이 보여 주는 시스템 뷰라면 isFindInteractionEnabled을 활성화하십시오 기존의 찾기 적용 내용을 UIFindInteraction으로 옮기세요 앱에 텍스트 검색이 없다면 UITextSearching을 적용하고 UITextSearchingFindSession을 사용하십시오 마지막으로 키보드 단축키가 겹치지 않는지 확인하세요 iOS 16을 위해 편집 인터랙션을 최신으로 유지하고 데스크톱 수준으로 만드는 방법이었습니다 여러분의 앱에도 텍스트 편집 메뉴를 사용해 보고 커스텀 UI에 편집 메뉴 인터랙션을 적용하십시오 텍스트 검색 기능을 넣어 앱의 생산성도 높이세요 여러분의 앱에서 최신 기능을 만나게 되기를 기대합니다 시청해 주셔서 감사하고 좋아요, 댓글, 구독 부탁드려요
-
-
2:42 - Adding items into text edit menus
func textView( _ textView: UITextView, editMenuForTextIn range: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu?
-
4:03 - Adding actions into a text view's menu
func textView( _ textView: UITextView, editMenuForTextIn range: NSRange, suggestedActions: [UIMenuElement] ) -> UIMenu? { var additionalActions: [UIMenuElement] = [] if range.length > 0 { let highlightAction = UIAction(title: "Highlight", ...) additionalActions.append(highlightAction) } let insertPhotoAction = UIAction(title: "Insert Photo", ...) additionalActions.append(insertPhotoAction) return UIMenu(children: suggestedActions + additionalActions) }
-
5:24 - Presenting an edit menu with a custom gesture
let editMenuInteraction = UIEditMenuInteraction(delegate: self) view.addInteraction(editMenuInteraction) let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTap(_:))) tapRecognizer.allowedTouchTypes = [UITouch.TouchType.direct.rawValue as NSNumber] view.addGestureRecognizer(tapRecognizer) @objc func didTap(_ recognizer: UITapGestureRecognizer) { let location = recognizer.location(in: self.view) if self.hasSelectedObjectView(at: location) { let configuration = UIEditMenuConfiguration(identifier: nil, sourcePoint: location) editMenuInteraction.presentEditMenu(with: configuration) } }
-
7:13 - Implementing UIEditMenuInteractionDelegate
func editMenuInteraction( _ interaction: UIEditMenuInteraction, targetRectFor configuration: UIEditMenuConfiguration ) -> CGRect { guard let selectedView = objectView(at: configuration.sourcePoint) else { return .null } return selectedView.frame } func editMenuInteraction( _ interaction: UIEditMenuInteraction, menuFor configuration: UIEditMenuConfiguration, suggestedActions: [UIMenuElement] ) -> UIMenu? { let duplicateAction = UIAction(title: "Duplicate") { ... } return UIMenu(children: suggestedActions + [duplicateAction]) }
-
10:34 - Using the "keeps menu presented" attribute
UIAction(title: "Increase", image: UIImage(systemName: "increase.indent"), attributes: .keepsMenuPresented) { ... } UIAction(title: "Decrease", image: UIImage(systemName: "decrease.indent"), attributes: .keepsMenuPresented) { ... }
-
12:46 - Find with system views
open var findInteraction: UIFindInteraction? { get } textView.isFindInteractionEnabled = true
-
17:22 - Installing a UIFindInteraction on a custom view
let customDocument = MyDocument(string: "") lazy var customView = MyTextView(document: customDocument) lazy var findInteraction = UIFindInteraction(sessionDelegate: self) override var canBecomeFirstResponder: Bool { true } override func viewDidLoad() { customView.addInteraction(findInteraction) } func findInteraction(_ interaction: UIFindInteraction, sessionFor view: UIView) -> UIFindSession? { return UITextSearchingFindSession(searchableObject: customDocument) }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.