스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
키보드 따라잡기
키보드는 매년 더욱 다양한 언어, 크기, 기능을 지원할 수 있도록 발전합니다. 기기에 키보드가 어떻게 표시되는지에 관계없이 계속 발전하는 키보드를 따라잡을 수 있도록 앱을 디자인하는 방법을 알아 보세요. 원활한 텍스트 입력 항목을 만드는 방법과 키보드가 시스템 내에서 작동하는 방식을 이해할 수 있도록 주요 아키텍처 변화들을 공유합니다.
챕터
- 0:00 - Introduction
- 1:29 - Out of process keyboard
- 3:47 - Design for the keyboard
- 14:06 - New text entry APIs
- 15:06 - Key takeaways
리소스
- Adding a search interface to your app
- Adjusting your layout with keyboard layout guide
- FocusState
- Human Interface Guidelines: Keyboards
- SafeAreaRegions
관련 비디오
WWDC23
WWDC21
-
다운로드
♪ ♪
안녕하세요, 여러분 저는 Spencer Lewson입니다 오늘 저는 지난 몇 년간 키보드가 어떻게 변했는지와 함께 그리고 '키보드에 맞춘' 앱 디자인법을 알려드릴 겁니다
아시다시피 iPhone의 키보드는 2007년에 도입되어 이후 상당히 발전했습니다 이제는 다양한 언어를 지원하고 각각 레이아웃에 맞게 다양한 크기를 가지죠 물론 다른 기기들에도 키보드가 생겼습니다 하지만 키보드가 발전한 것처럼 시스템도 발전했고 멀티태스킹과 플로팅 키보드처럼 멋진 기능들도 추가됐죠 키보드는 이제 앱의 경계를 초월할 수 있게 되었습니다
작년에 우리는 Stage Manager를 도입했는데요 iPad에서의 생산성을 새로운 수준으로 끌어올렸죠 이제 다양한 디스플레이에서 보는 다양한 씬 덕분에 하드웨어 키보드와 마우스 사용이 더욱 매력적이게 다가옵니다 그래서 오늘은 키보드의 재건축으로 얼마나 다양한 키보드 시나리오가 만들어질 수 있는지 그리고 그게 앱에 얼마나 영향을 주는지 알아볼게요 그리고 여러분의 앱이 최소한의 노력으로 키보드와 매끄럽게 작동하는 팁과 비법도 공유하겠습니다 마지막으로 텍스트 입력의 아주 재밌는 새 기능을 소개하도록 하겠습니다 먼저 아웃 오브 프로세스 키보드를 살펴봅시다
앱 프로세스에서 키보드를 가져오면 보안이 개선되고 사용자가 입력하는 내용의 프라이버시도 보장됩니다 앱은 물론 시스템 전체의 공간도 널널하게 해주죠 하나의 키보드만 있으니까요 다양한 앱에서 여러 인스턴스가 실행되지 않고 말이죠 이 새로운 아키텍처를 통해 미래를 위한 디자인이 가능하고 새로운 기능을 구현할 수 있습니다 그 작동 원리를 더 살펴볼게요 iOS 17 이전에는 키보드의 뷰와 로직이 앱 프로세스 내에서 실행됐죠 하지만 이제 iOS 17이 설치된 iPhone에서는 키보드가 자체 프로세스로 이동하여 앱의 거의 외부에서 실행된다고 보면 됩니다 작동 원리를 보여드리려니 너무 신이 나는데요 먼저 키보드 실행 과정을 보며 차이를 알아보죠
키보드 실행 시 앱이 먼저 키보드를 요청합니다 터치에 응답하여 becomeFirstResponder를 유발하는 것과 같이요 그리고 동기성 작업들을 시작해 모든 뷰를 초기화할 거고요 이게 완료되면 시스템은 애니메이션을 수행해 키보드를 가져옵니다 앱은 터치 이벤트가 생기거나 텍스트 삽입이 생성되기 전까지 가만히 있거나
앱 사이드 작업을 할 겁니다 앱은 키보드를 요청합니다 becomeFirstResponder를 호출하는 식으로 말이죠 그럼 앱은 초기 계산을 수행하고 키보드 프로세스는 UI를 비동기적으로 초기화하죠 그렇게 되면 앱은 가만히 있거나 앱 사이드 작업을 합니다 일단 준비되면 키보드를 불러오고 프로세스간 애니메이션을 조정하죠 키보드 UI가 나타나면 키보드 경계 내에서 일어나는 터치 이벤트를 기다리고 이벤트를 앱에 대한 텍스트 삽입으로 전환할 겁니다 대다수의 앱에서는 이 변화가 완전히 투명하게 이루어지고 여러분의 채택을 필요로 하지 않죠 그렇지만 이 비동기성 접근법의 일부는 키보드 전체에 걸쳐 존재하여 타이밍에 약간의 차이를 도입할 수 있습니다 앱이 텍스트 입력 타이밍이나 선택 변경 혹은 다른 텍스트 관련 운영에 대해 특히 민감한 경우에는 이 새 아키텍처를 고려해 주셔야 합니다 iOS 내 타이핑의 다양성을 좀 이야기해 보았으니 이제 앱 디자인 시 상대적으로 고려해 주어야 할 새로운 시나리오들을 살펴볼게요 당연히 우리에게 가장 친숙한 사용 사례는 이겁니다 키보드가 있는 풀 스크린 앱이요 이건 상대적으로 간단한 사용 사례죠 앱과 키보드 모두 풀 스크린이고 키보드 조정을 키보드 높이가 되는 값에 따라 뷰를 올리는 것 만큼이나 아주 단순하게 만들거든요 그러나 Stage Manager가 있으면 시스템은 그 모델에서 벗어날 겁니다 고급 멀티태스킹이 가능해 풀 스크린이 꼭 필요하지 않죠 그 말인 즉슨 키보드가 나타나면 앱의 뷰를 정확히 조정하고자 특별한 관심이 필요하단 겁니다 키보드의 씬과 앱의 씬이 더 이상 일치하지 않거든요 앱을 콘텍스트에 적절하게 맞추기 위해서는 추가 변형이 필요합니다 이 시나리오의 경우 앱의 조정은 실제 Y 길이 즉, 키보드의 높이가 아니죠 이건 키보드와 앱의 교차점을 통해 조정해야 합니다 Y'에 나타나는 것처럼요 계산할 조정값이 하나가 아닐지도 모릅니다 스크린에 다양한 씬이 있을 수도 있으니까요 이 경우에는 각각 다른 계산과 조정이 필요하죠 최근 하드웨어 키보드에 새로 도입된 시나리오인데 하드웨어 키보드를 연결하면 시스템이 스크린 중앙에 지원 툴바를 제시하는 겁니다 이 풀 사이즈 툴바가 나타나면 키보드의 일환으로 작동하고 뷰가 번거롭게 조정되어야 하죠 그런데 플릭 제스처를 사용해 툴바 최소화가 가능합니다 Stage Manager 밖에서는 기존 동작을 보존합니다 미니 툴바가 키보드의 일부로 작동하지 않아 뷰와 겹치게 될 거고요 사용자는 툴바를 스크린 다른 쪽에 드래그해 아래에 있는 콘텐츠에 접근할 수 있습니다 하지만 Stage Manager에서는 미니 툴바가 키보드의 일부로 작용하기 때문에 사용 사례에 따라 스크롤 오프셋을 업데이트하고 입력 액세서리 뷰를 밀어올릴 수 있죠 그럼 다른 레이아웃 조정도 가능해집니다 이렇게 다양한 시나리오와 차이가 존재하는데요 좋은 소식은 올바른 API가 있다면 시스템이 여러분의 작업 대부분을 한다는 겁니다 이제 키보드 레이아웃 가이드에 대해 이야기해 보죠 아마 iOS 15에 도입된 키보드 레이아웃 가이드에 친숙하실 겁니다 여기서는 키보드에 맞게 자동 조정하는 간편한 자동 레이아웃 가이드를 제공했습니다 지난 해 우리는 여기에 내용을 추가했습니다 실제로 일부 복잡한 Apple 앱에서 사용되는데요 스포트라이트나 메시지 같은 곳에서요 뷰와 가이드 사이에 제약을 추가하려면 필요한 게 이 한 줄인 만큼 간편한 방법으로 추천합니다 이제 이게 정확히 어떻게 도움이 되는지 살펴보죠 기존 기본 동작은 다음과 같은데요 키보드 레이아웃 가이드는 온스크린 고정 상태에서 키보드를 따라갑니다 키보드가 스크린 하단을 터치하고 있다는 거죠 키보드가 고정되지 않아 iPad에서 플로팅 상태라면 가이드의 높이는 뷰의 하단 안전 영역에 맞춰집니다 가이드는 터치 포인트가 가이드와 교차하면 키보드 디스미스 제스처를 추적할 거고요 iOS 17에서 사용자화 옵션이 확장되었다는 겁니다 이제 이런 변경을 통해 정확히 원하는 동작을 얻을 수가 있죠 이제 UIKeyboardLayoutGuide에는 프로퍼티가 3개입니다 먼저 followsUndockedKeyboard 인데요 기본적으로 가이드는 오프스크린 키보드처럼 플로팅 키보드나 미니 툴바를 따라갑니다 하지만 이게 참으로 설정될 경우 플로팅 상태에서도 키보드를 계속 따라가죠 앱의 창 위에 있는 한 말이죠 다음은 usesBottomSafeArea입니다 키보드 레이아웃 가이드는 키보드가 사라지게 되면 기본적으로 안전 영역의 높이를 추적할 겁니다 하지만 이게 거짓으로 설정되면 usesBottomSafeArea는 대신 뷰의 하단을 추적하죠 이 경우 스크린의 하단이 되겠네요 이건 언제 유용할까요? 일단 키보드가 사라지면 배경이 확장되어 스크린 하단도 커버하게 되고 키보드가 나타나면 그에 맞게 조정되죠 InputAccessoryView와 비슷하게 동작합니다 실제로 이 프로퍼티에는 흥미로운 사용 사레가 있는데요 그 작동 원리를 살펴봅시다 이건 키보드가 사라졌을 때 텍스트 필드가 하단 안전 영역 위에 있고 백드롭이 하단 안전 영역까지 쭉 확장되게 하는 단순 입력 액세서리와 같은 뷰를 얻을 수 있는 코드입니다 여기에서는 수직 제약 조건만 다룰 건데요 이 사례에서 흥미로운 부분이기 때문이죠 먼저 usesBottomSafeArea를 거짓으로 설정합니다 다음으로 텍스트 필드의 상단을 백드롭 상단과 묶습니다 두 시스템 공간 차이를 사용해 약간의 패딩을 주는 거죠 텍스트 필드를 항상 키브도 위에 있도록 할 겁니다 가이드 상단을 최소의 시스템 간격으로 텍스트 필드 하단에 제약함으로써 말이죠 더 중요한 부분은 지금부터입니다 키보드가 오프스크린 상태이면 텍스트 필드에는 충분한 유연성이 필요해 하단 안전 영역 인셋 위에 머물러야 할 겁니다 가이드의 상단 앵커를 백드롭 하단에 고정시켜 보죠 이는 가이드가 오프스크린일 경우 백드롭이 하단까지 뻗게 해줄 겁니다 usesBottomSafeArea를 설정했다는 이유로요 마지막으로 안전 영역 하단을 텍스트 필드 하단으로 제한하죠 시스템 간격도 더해서요 여기서는 키보드가 나타났을 때 따라갈 만큼 유연하게 하려는 제약 조건 이상을 사용 중이죠 이를 통해 백드롭이 뷰 하단까지 뻗는 적응형 뷰를 갖추게 되거든요 하지만 텍스트 필드 시스템 간격은 키보드 상단에 백드롭은 키보드 상단에 유지되도록 조정하죠 입력 액세서리 뷰처럼요
세 번째로 keyboardDismissPadding입니다 이건 스크롤 매개변수를 디스미스 제스처로 조정하죠 '키보드 레이아웃 뷰'를 통해 과거 InputAccessory와 같은 뷰를 만들어 보셨다면 터치가 키보드를 교차할 때까지 키보드 디스미스 제스처가 시작되지 않음을 아실 겁니다 이 프로퍼티로 그걸 고정해 보도록 하죠
keyboardDismissPadding 프로퍼티는 해당 제스처에 응답해야 하는 패딩을 키보드 위에 유지시킵니다 상대적으로 간단한데요 얼마를 원하던 뷰의 높이를 골라 프로퍼티를 설정하면 됩니다 끝입니다 이제 이 제스처는 터치가 뷰왁 교차할 때 시작되죠 물론 UIKit이 유일한 앱 구축 프레임워크는 아니죠 SwiftUI도 있습니다 SwiftUI는 자동으로 흔한 사례를 처리하고요 SwiftUI에서는 키보드가 안전 영역 일부로 포함되어 키보드가 사라지면 스크린 하단에 있는 홈 어포던스를 추적합니다 키보드가 나타나면 시스템은 안전 영역에 생기를 불어넣고 조정하여 뷰 크기를 자동 조절하죠 그래서 키보드 코드를 쓸 필요가 전혀 없습니다 하지만 레이아웃에 대해 작업이 좀 필요합니다 뷰의 크기와 위치가 원하는 대로 조정되려면 말이죠 SwiftUI에 대한 자원은 훨씬 더 많습니다 제가 간단한 목록으로 제시할 수 없으니 더 알아보고 싶으시다면 아래 연결된 개발자 문서를 확인해 보시길 바랍니다 이제 키보드를 통합의 더 수동적인 방식인 '키보드 알림'에 대해 알아보도록 하죠 SwiftUI와 키보드 레이아웃 가이드가 나오기 전에는 키보드를 앱에 통합할 수 있는 유일한 방식이 키보드 알림들을 듣는 것이었습니다 willShow, didShow, willHide, didHide 같은 걸요 그리고 알림의 프레임과 애니메이션 정보를 기반으로 레이아웃을 손수 조정해야 했죠 여전히 가능하기는 하지만 더 세심한 처리가 필요합니다 시스템이 그걸 해주지는 않거든요 그리고 Stage Manager의 도입 덕분에 우리는 흔히 사용하는 처리 패턴이 더 이상 100% 항상 작동하지 않는다는 것을 알았습니다 이 패턴은 대개 키보드 알림을 수신하고 키보드 높이의 원값을 직접 사용하는 것에 집중하죠
키보드 높이와 스크린에서의 앱 높이 상호작용 방식의 차이를 논의했던 것 기억하시죠? 이제 알림과 작동하는 방식을 논의해 보겠습니다 각 알림은 스크린 좌표와 연관된 키보드 예상 프레임을 지정하는데요 앱이 풀스크린일 때처럼 스크린 좌표 공간과 앱의 좌표 공간이 일치하면 알림에 포함되는 원 높이값은 우연히 예측한대로 뷰 조정을 할 겁니다 하지만 스크린의 좌표 공간과 앱 좌표 공간이 다를 경우 이 원 높이값은 더 이상 올바른 값으로 조정되지 않죠 그럼 뷰가 너무 높이 가있거나 잘못된 곳에 위치할 겁니다 다행히 이 모든 걸 매끄럽게 할 수 있도록 알림 처리에 적용 가능한 변경 사항들이 있는데요 iOS 6.1에서부터 키보드 알림은 일치하는 UIScreen을 알림의 객체로 포함했습니다 먼저 키보드가 앱의 동일한 스크린에 나타나는지 확인하기 위해 사용해 보죠 제대로 나타나면 조정은 필요없습니다 이제 뷰와 연관된 키보드 배치를 표현하기 위해 rect를 계산하겠습니다 키보드의 예상 엔드 프레임과 알림과 뷰가 제공하는 좌표 공간을 불러오고 이들을 사용해 keyboardFrameEnd를 좌표 공간으로 전환할 수 있습니다 이를 통해 뷰에 대한 필수 오프셋 결정이 가능하죠 뷰와 convertedKeyboardFrameEnd의 교차점을 계산해서 말이죠 뷰와 키보드가 겹치는 경우 필수 오프셋은 뷰와 키보드 간 교차점의 높이가 될 겁니다 원하는 대로 제약 조건이나 레이아웃 조절이 가능하죠 새로운 아웃 오브 프로세스 아키텍처에 있어 알림에 대한 동작에서 몇 가지 작은 변경 사항을 알아두셔야 하는데요 이에 대해 잠시 이야기해 보죠 키보드 프로세스의 생애 주기 그림 기억나시죠? 여기 '애니메이션 불러오기' 단계를 좀 더 살펴보겠습니다 인 프로세스 아키텍처에서 앱이 키보드를 요청했을 떈 시스템은 동기적으로 키보드 UI를 쵝화하고 알림을 게시한 후 애니메이션을 수행합니다 하지만 이 아웃 오브 프로세스 아키엑처에서는 앱이 키보드를 요청하면 시스템이 비동기적으로 키보드 UI를 초기화하고 비동기적으로 알림을 게시하며 애니메이션을 수행하죠 이는 타이밍에서 약간의 차이가 나게 합니다 그래서 앱이 becomeFirstResponder 호출 콜백으로 알림의 타이밍에 의존하는 경우 아니면 알림 처리가 지연되게 할 수 있는 메인 스레드에서 상당한 작업을 수행하는 경우 앱에 영향을 줄 수 있으니 이 새 모델을 기억하세요 사용자가 여러분의 앱에서 쉽게 입력할 수 있는 모든 팁과 비법을 소개해 드렸는데요 이제 텍스트 입력이 훨씬 빨라지는 새 기능과 API를 소개해 드리겠습니다 다음은 인라인 예측입니다 iOS 17에서 영어 키보드는 텍스트 필드 인라인에 맞는 다음 단어 몇 개에 대한 예측을 제공하는데요 이 예측은 기기에서 안전하게 생성되고 집중 텍스트 필드에 제공된 맥락 정보만 사용합니다 이 예측 채택도 상당히 쉽습니다 여기서는 UITextInputTraits 프로토콜을 사용합니다 보시다시피 inlinePredictionType 프로퍼티가 추가되었고 여기에는 몇 가지 옵션이 있죠 인라인 예측은 대부분의 입력 필드에서 기본 활성화되죠 하지만 예측이 적합하지 않은 필드에서는 자동으로 비활성화됩니다 검색 필드나 비밀번호 필드에선 말이죠 물론 앱에서 동작 사용자화도 가능합니다 프로퍼티를 yes나 no로 명확하게 설정만 하면 되죠 이제 주요 학습 내용 몇 가지를 복습하겠습니다 꼭 기억해 주세요 키보드와 매끄럽게 작동하도록 앱을 디자인하세요 어떤 모습인지는 상관 없습니다 시간에 민감한 코드 작성 시 아웃 오브 프로세스 모델을 유념해 주세요 텍스트 입력을 빠르게 하는 API로 경험은 개선됩니다 키보드에 신경써 주셔서 감사합니다 ♪ ♪
-
-
6:21 - Keyboard layout guide
view.keyboardLayoutGuide.topAnchor.constraint(equalTo: textView.bottomAnchor).isActive = true
-
7:56 - usesBottomSafeArea
// Example of using usesBottomSafeArea to create keyboard and text view aligned with safe area view.keyboardLayoutGuide.usesBottomSafeArea = false textField.topAnchor.constraint(equalToSystemSpacingBelow: backdrop.topAnchor, multiplier: 1.0).isActive = true view.keyboardLayoutGuide.topAnchor.constraint(greaterThanOrEqualToSystemSpacingBelow: textField.bottomAnchor, multiplier: 1.0).isActive = true view.keyboardLayoutGuide.topAnchor.constraint(equalTo: backdrop.bottomAnchor).isActive = true view.safeAreaLayoutGuide.bottomAnchor.constraint(greaterThanOrEqualTo: textField.bottomAnchor).isActive = true
-
9:40 - Keyboard dismiss padding
var dismissPadding = aboveKeyboardView.bounds.size.height view.keyboardLayoutGuide.keyboardDismissPadding = dismissPadding
-
12:11 - Handle willShow or hideKeyboard notifications
func handleWillShowOrHideKeyboardNotification(notification: NSNotification) { // Retrieve the UIScreen object from the notification (Added iOS 16.1) guard let screen = notification.object as? UIScreen else { return } // Determine if the notification’s screen corresponds to your view’s screen guard(screen.isEqual(view.window?.screen)) else { return } // Calculate intersection with keyboard let endFrameKey = UIResponder.keyboardFrameEndUserInfoKey // Get the ending screen position of the keyboard guard let keyboardFrameEnd = userInfo[endFrameKey] as? CGRect else { return } let fromCoordinateSpace: UICoordinateSpace = screen.coordinateSpace let toCoordinateSpace: UICoordinateSpace = view // Convert from the screen coordinate space to your local coordinate space let convertedKeyboardFrameEnd = fromCoordinateSpace.convert(keyboardFrameEnd, to: toCoordinateSpace) // Calculate offset for view adjustment var bottomOffset = view.safeAreaInsets.bottom // Get the intersection between the keyboard's frame and the view's bounds let viewIntersection = view.bounds.intersection(convertedKeyboardFrameEnd) // Check whether the keyboard intersects your view before adjusting your offset. if !viewIntersection.isEmpty { // Set the offset to the height of the intersection bottomOffset = viewIntersection.size.height } // Use the new offset to adjust your UI movingBottomConstraint.constant = bottomOffset // Adjust view layouts and animate using information in notification ... }
-
14:38 - Inline predictions
@MainActor public protocol UITextInputTraits : NSObjectProtocol { // Controls whether inline text prediction is enabled or disabled during typing @available(iOS, introduced: 17.0) optional var inlinePredictionType: UITextInlinePredictionType { get set } } public enum UITextInlinePredictionType : Int, @unchecked Sendable { case `default` = 0 case no = 1 case yes = 2 } let textView = UITextView(frame: frame) textView.inlinePredictionType = .yes
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.