스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
AppKit의 새로운 기능
Mac 앱을 개발하는 데 있어 최근 도입된 개선 사항을 살펴보세요. macOS Sequoia의 새로운 기능과 이러한 기능을 앱에 적용하는 방법을 알아보세요. 기존 코드를 SwiftUI에 통합하는 새로운 방법을 살펴보고, 도구 막대, 메뉴, 텍스트 입력 등 다양한 AppKit 컨트롤의 개선 사항에 대해서도 알아보세요.
챕터
- 0:00 - Introduction
- 0:49 - New macOS features
- 0:52 - Writing Tools, Genmoji, and Image Playground
- 3:31 - Window Tiling
- 6:21 - More SwiftUI integrations
- 6:41 - Build menus with SwiftUI
- 7:39 - Get animated with SwiftUI
- 8:20 - API refinements
- 8:44 - Context menu refinements
- 9:42 - Text highlighting
- 11:00 - SF Symbols
- 11:59 - Save Panel refinements
- 13:04 - Cursors refinements!
- 15:21 - Toolbar refinements
- 17:22 - Text entry suggestions
리소스
관련 비디오
WWDC24
WWDC23
-
다운로드
안녕하세요, 저는 Matt Zanchelli이고 AppKit 팀의 엔지니어입니다 이번 주제는 AppKit의 새로운 기능입니다 저만큼 AppKit과 Mac을 좋아하신다면 이 시간이 도움이 될 겁니다 여기서는 macOS Sequoia의 여러 가지 개선 사항을 보여 드리고 AppKit 앱을 더 잘 사용하는 방법도 알아보겠습니다 이 동영상에서는 다양한 주제를 다룰 예정이며 시스템 전반의 몇 가지 새로운 기능과 앱에 이러한 기능을 적용하는 방법부터 살펴보겠습니다 그런 다음 AppKit에 적용된 SwiftUI 사용 시의 유용한 일부 변경 사항을 보여드립니다 마지막으로 프레임워크의 탁월하고 새로운 여러 가지 API 개선 사항을 공유할 예정입니다
새로운 macOS 기능부터 만나 보시겠습니다 이제 macOS에서 글쓰기 도구를 사용하면 맞춤법과 문법에 대한 도움을 받을 뿐 아니라 문장 구조, 명확성, 어조 등의 더 정교한 쓰기 개념을 제공받을 수 있습니다 이러한 글쓰기 도구를 시스템 전반에 적용시키고자 저희가 많은 노력을 기울인 결과 앱에서 이러한 지능형 기능을 자동으로 가져올 수 있게 되었습니다 앱에서 만족도 높은 쓰기 경험을 하려면 불러오는 상호작용 동작을 고려하시기 바랍니다 앱에서 많은 텍스트 입력값을 처리하거나 텍스트 보기로 고급 작업을 수행한다면 ‘글쓰기 도구 시작하기’를 시청해 보세요 저는 늘 꿈꾸던 이모티콘을 만드는 데 많은 재미를 느끼고 있습니다 이제 감정과 사물, 장면을 한층 구체적으로 표현한 다음 메시지 및 메모 같은 앱에서 이모티콘을 친구들과 공유할 수 있습니다 여러분의 앱에서도 이러한 새로운 이모티콘을 만들고 사용할 수 있게 되어 기쁩니다 이렇게 만드는 새 이모티콘은 Unicode 문자가 아닌 이미지입니다 따라서 앱에서 이러한 이미지를 텍스트와 인라인으로 표시하고 저장하는 데 약간의 구현 작업이 필요할 수 있습니다
‘Genmoji로 앱에서 더욱 풍부한 표현 선보이기’를 시청하여 앱에서의 맞춤형 이모티콘 구현 방법을 알아보세요
이제 맞춤형 이모티콘 외에도 전체 이미지를 새 Image Playground 앱에서 만들 수 있습니다 여러분의 앱에서도 이러한 매력적인 이미지를 생성할 수 있으며 새 Image Playground 경험을 통해 구현할 수 있습니다 앱에 Image Playground 경험을 추가하는 방법을 알아볼 차례입니다 먼저 Image Playground 보기 컨트롤러의 인스턴스를 초기화하고 대리자를 할당합니다 대리자는 중요한 라이프 사이클 이벤트 소식을 전달받게 되는데 이미지 생성이 완료되거나 취소된 경우를 예로 들 수 있습니다 앱에 Image Playground 경험으로 이어지는 일부 특정 컨텍스트가 있으면 필요에 따라 앱에서 몇 가지 초기 개념과 소스 이미지를 사용해 보기 컨트롤러를 설정할 수 있습니다 개념은 출력 이미지에 예상되는 콘텐츠를 나타내며 소스 이미지는 만든 이미지에 대한 그래픽 참조 역할을 합니다 이 두 속성을 통해 시트를 보고 있는 사용자가 이미지 생성을 빠르게 시작할 수 있습니다 여전히 이미지 생성 시트 내에서 다양한 이미지와 개념을 선택할 수 있습니다 그런 다음 보기 컨트롤러를 시트로 표시하여 생성할 수 있습니다
이미지가 생성되면 보기 컨트롤러의 대리자에게 이미지 파일 URL에 대한 참조와 함께 콜백이 전송됩니다 이 파일 URL은 앱의 샌드박스된 임시 디렉토리에서 찾을 수 있습니다 해당 파일 URL을 사용하여 사용자 인터페이스에 이미지를 삽입한 다음 플레이그라운드 시트를 닫습니다 앱이 사진 보관함이나 Finder, 연속성 카메라에서의 이미지 삽입을 허용하면 또 다른 이미지 소스로 Image Playground를 추가해 보시기 바랍니다 Image Playground 경험을 앱에 통합하는 것이 얼마나 수월한지 설명드렸습니다 제가 macOS Sequoia에서 가장 좋아하는 새로운 기능 중 하나는 바로 윈도우 타일 정렬입니다 바로 보여드리겠습니다
윈도우 타일 정렬을 사용하면 일반적인 배열로 윈도우를 빠르게 이동할 수 있습니다 이 윈도우를 움직여 볼게요, 마우스 커서를 화면 오른쪽 가장자리에 두고
윈도우를 여기에 드롭하면 화면 절반 크기로 윈도우가 배치됩니다
이 윈도우를 정렬된 영역 밖으로 드래그하면 타일 정렬 전의 크기로 돌아갑니다
이 기능은 잠시 동안 윈도우를 눈에 잘 띄게 표시한 다음 작업이 끝난 후 다시 기본 크기로 되돌릴 때 유용합니다 타일을 정렬하려고 화면 가장자리까지 마우스 커서를 이동할 필요도 없습니다 Option 키를 누른 상태에서 바로 드래그하면 가장 가까운 타일의 미리보기가 제공되고 해당 위치에 드롭하면 됩니다 윈도우 > 이동 및 크기 조절 메뉴에서 ‘윈도우 타일 정렬’ 옵션에 액세스할 수도 있습니다
여기에서 모든 키보드 관련 단축키 확인도 가능합니다 이 단축키로 매우 신속하게 윈도우를 이동시킬 수 있습니다
붕 붕 붕
윈도우 두 개를 나란히 배열하고 싶은 경우 이를 해결할 수 있는 배열이 준비되어 있습니다
윈도우 메뉴 외에도 이제 윈도우 메뉴 막대에서 이 옵션에 간편하게 액세스할 수 있습니다
윈도우 두 개를 표시할 때 나란히 타일을 배열하면 이렇습니다 두 윈도우를 동시에 크기 조절하여 적합하다고 생각하는 비율로 맞춥니다
새 윈도우를 열면 타일 정렬이 적용되지 않은 크기로 나타납니다
윈도우 세 개를 모두 배열하려면 윈도우 세 개 배열을 선택하면 됩니다 근사하지 않나요? 윈도우 타일 정렬은 유용한 기능이며 macOS Sequoia의 모든 앱에서 이용 가능합니다 앱에서 윈도우 타일 정렬을 사용할 때 몇 가지를 고려하면 가장 잘 활용할 수 있습니다 윈도우의 최소 크기와 최대 크기를 고려하세요 윈도우 타일 정렬을 사용하면 사용자가 화면의 1/2 혹은 1/4을 채울 수 있습니다 앱의 윈도우 크기가 충분히 유연하다면 겹치는 부분 없이 윈도우를 배열할 수 있습니다 최소 크기에 영향을 주는 윈도우의 레이아웃 제약 조건을 확인하세요
윈도우 크기를 조절할 때 너비는 고정하고 높이만 늘려야 한다면 resizeIncrements 속성을 사용합니다 이 속성은 너비나 높이를 단일 문자만큼 더해 윈도우의 크기를 조절할 때 사용합니다 터미널의 경우처럼 말이죠 새 윈도우를 열 때 기존 윈도우와 비교해 새 윈도우가 어떻게 배치될지 고려하세요 새로운 cascadingReferenceFrame 속성을 사용하면 타일 정렬이 되지 않은 기존 윈도우의 프레임을 가져옵니다 새로 열리는 윈도우는 해당 프레임에 맞춰 계단식으로 배열됩니다 NSWindowController 속성을 사용하고 있는 경우 macOS Sequoia에서 이미 기본적으로 이 기능을 누릴 수 있습니다 저는 Mac 앱에서 SwiftUI를 사용하는 것을 좋아합니다 사용자 인터페이스를 빌드하는 정말 멋진 방법이기 때문이죠 AppKit과 함께 작동하도록 처음부터 설계된 덕분에 점진적으로 적용될 것입니다 저희 팀은 여러 해 동안 통합을 강화해 왔으며 macOS Sequoia에서는 한층 더 개선했습니다 NSHostingView를 사용하여 AppKit 앱 내부에서 SwiftUI 보기를 사용할 수 있는 것과 마찬가지로 이제 SwiftUI 메뉴도 사용 가능합니다 이렇게 하면 앱에서 AppKit을 사용하는 부분과 SwiftUI를 사용하는 부분 간의 메뉴 정의를 공유할 수 있습니다 NSHostingMenu를 통해 AppKit 컨텍스트의 SwiftUI 메뉴를 사용할 수 있으며 이 속성은 새로운 NSMenu의 하위 클래스입니다 작업은 쉽습니다
메뉴 정의를 만드는 데 SwiftUI 보기를 사용합니다 본문에서 데이터 관계를 가장 잘 설명하는 SwiftUI 보기를 사용합니다 Toggle을 사용하여 값을 켜거나 끄고 Picker로 목록에서 값 하나를 선택합니다 Button은 작업을 수행합니다
해당 SwiftUI 보기를 통해 NSHostingMenu를 초기화합니다 그런 다음 NSMenu를 허용하는 AppKit 컨텍스트에 사용합니다 예를 들어 풀다운 메뉴 매개변수를 사용하는 새로운 NSPopUpButton 이니셜라이저입니다 macOS Sequoia에서 AppKit은 SwiftUI로 애니메이션 효과를 적용합니다 이제 SwiftUI 애니메이션 유형을 사용하여 NSViews에 애니메이션 효과를 적용해 보세요 이렇게 하면 효과적인 전체 SwiftUI 애니메이션 유형을 사용할 수 있으며 SwiftUI CustomAnimations도 포함됩니다
NSViews에 애니메이션 효과를 적용하려면 NSAnimationContext를 사용하여 SwiftUI 애니메이션 유형을 전달하고 레이아웃이나 그림을 조정하세요 SwiftUI 애니메이션은 중단 가능하고 타겟 재설정도 가능합니다
UIKit과 AppKit의 SwiftUI 애니메이션에 대해 더 자세히 알아보려면 ‘UI 애니메이션 및 전환 효과 향상하기’ 동영상을 확인하세요 이어서 환상적인 AppKit API의 개선 사항 중 몇 가지를 알려드립니다
빠른 메뉴를 여는 새로운 방법 텍스트 시스템 및 SF Symbols의 새로운 기능 새롭고 간편한 문서 저장 방식 몇 가지 새로운 커서, 도구 막대에 대한 추가 제어 기능 텍스트 입력을 지원하는 새롭고 흥미로운 API가 있습니다 macOS Sequoia의 새로운 기능으로 키보드 활용도가 강화되어 현재 강조 표시된 UI 요소에서 빠른 메뉴를 열 수 있습니다 사용자는 이 기능을 사용하여 보다 신속하고 편하게 앱의 기능에 액세스할 수 있습니다 이 단축키는 기본적으로 Control-return 키이지만 시스템 설정에서 맞춤화할 수 있습니다 하지만 마우스가 아닌 키보드를 사용하여 빠른 메뉴가 표시되면 메뉴는 어디에 표시될까요? 이러한 빠른 메뉴의 위치를 어떻게 조절할 수 있는지 보여드리겠습니다
보기에 메뉴 속성에 대한 값이 있는 경우 메뉴가 자동으로 보기의 경계 위에 나타납니다
보기에 맞춤형 선택 항목이 나타나면 새로운 NSViewContentSelectionInfo 프로토콜을 구현하여 선택 항목에 대한 지오메트리 정보를 제공합니다 그러면 보기의 메뉴가 선택 항목 근처에 적절하게 배치됩니다 이러한 방법으로 키보드 제공 빠른 메뉴의 위치를 제어할 수 있습니다 다음으로 소개할 새 API 개선 사항은 텍스트 하이라이트입니다
하이라이트 기능을 사용하면 텍스트를 배경 색상 및 대비되는 전경 색상으로 강조할 수 있습니다 서식 있는 텍스트가 지원되는 모든 NSTextView에서 이용 가능합니다 먼저 텍스트 범위를 선택합니다 마우스 오른쪽 버튼을 클릭하고 서체 메뉴에서 하이라이트 하위 메뉴로 이동합니다 많은 하이라이트 색상 체계 중에서 선택하거나 앱의 강조 색상을 사용할 수 있습니다 텍스트 편집기의 경우 파란색으로 표시됩니다 이 기능이 서식 있는 텍스트 보기에서 자동으로 지원되지만 사용자가 이 새로운 기능을 구현할 수도 있습니다 앱에 맞춤형 텍스트 속성 제어 기능이 있으면
텍스트 하이라이트가 속성이 부여된 문자열 속성에 따라 제어됩니다 새로운 .textHighlight 속성은 텍스트 하이라이트 스타일에 해당합니다 .systemDefault로 설정하여 강조 표시되어야 하는 텍스트 범위를 나타냅니다 사용된 색상은 앱의 강조 색상을 기반으로 설정됩니다 색상을 제어하려면 새로운 .textHighlightColorScheme 속성을 사용하고 이를 시스템이 제공하는 색상 체계 중 하나와 연동합니다, 핑크처럼요 macOS Sequoia는 SF Symbols 6과 함께 제공되며 여기에는 다양한 사물을 다루는 800개 이상의 새로운 기호가 포함됩니다
또한 더 많은 효과가 포함되어 있으며 흔들흔들 회전 심호흡 옵션이 있습니다
새로운 재생 옵션도 있으며 기호 효과에서 특정 횟수만큼 효과를 반복하거나 연속 루프에서 애니메이션을 반복하는 예를 들 수 있습니다
제가 가장 좋아하는 기능은 기호의 배지나 슬래시를 마법처럼 대체하는 기능입니다 새로운 기호 효과는 정말 근사합니다 맞춤형 기호를 작성하는 방법에 대한 내용을 자세히 알아보려면 ‘SF Symbols 6의 새로운 기능’을 확인하세요 ‘앱의 기호에 애니메이션 적용하기’도 시청하여 표현력이 풍부한 애니메이션을 사용하는 방법에 대해 자세히 알아보세요 다음으로 저장 패널이 향상되었습니다
문서를 저장할 때 저장하려는 파일 형식을 선택하고 저장 패널에 바로 저장할 수 있다면 정말 편리할 것입니다 이제 macOS Sequoia에는 표준 파일 형식 선택기가 마련되어 있으므로 맞춤형 액세서리 보기를 생성하지 않으셔도 됩니다 표준 파일 형식 선택기 사용 및 설정 방법은 매우 간단하며 저장 패널의 showsContentTypes 속성을 true로 설정하기만 하면 됩니다 선택기에는 저장 패널에서 지원되는 각 허용된 콘텐츠 유형에 대한 옵션이 포함되어 있으며 이는 기존의 allowedContentTypes 속성에 따라 지정됩니다 기본적으로 각 메뉴 항목은 콘텐츠 유형의 현지화된 설명을 사용합니다 맞춤형 표시 이름을 입력하려면 대리자 함수인 panel(_ displayNameFor type:) 값을 사용하세요 이 함수를 사용하면 앱 컨텍스트에 적절한 콘텐츠 유형 이름이 반환됩니다
이 새로운 저장 패널 개선 사항을 통해 개발 시간을 단축할 수 있기를 바랍니다 그리고 마침내 macOS SDK에서 처음으로 공개되는 새로운 기능입니다 마우스를 따라다니는 것이죠 네, 맞습니다! 커서입니다! 이제 시스템의 커서를 macOS Sequoia SDK에서 사용할 수 있습니다 프레임 크기 조절 커서부터 살펴볼까요
이 기능으로 가장자리와 모서리에서 요소의 크기를 조절할 수 있습니다 두 개의 매개변수가 지원됩니다 첫 번째는 위치입니다 커서가 상호작용할 가장자리나 모서리를 의미합니다 두 번째는 방향이며 요소의 크기를 조절할 수 있습니다 요소가 최소 크기 혹은 최대 크기에 도달하는 지점에서 케이스를 처리합니다 프레임 크기 조절 커서는 단일 요소의 크기 조절을 염두에 둔 기능입니다 하지만 두 가지 요소 간에 구분 기호를 이동시키는 경우 columnResize와 rowResize 커서를 사용합니다 커서 아트워크에서 화살표에 수직 방향인 막대가 크기 조절이 이뤄지는 구분 기호를 나타냅니다 이러한 커서는 표 열의 너비 크기를 조절하거나 스프레드시트의 행 높이를 조절할 때 유용합니다 구분 기호를 이동하려는 방향을 지정하여 기준에 도달하는 지점에서 케이스를 처리합니다
확대하거나 축소할 경우 새로운 확대/축소 커서 기능이 지원됩니다 클릭을 통해 앱의 콘텐츠를 확대하거나 축소하려는 경우 이 커서 기능을 사용합니다 이러한 시스템 커서는 AppKit에서 새롭게 사용할 수 있습니다 시스템 커서로 일반적인 디자인을 확보하여 앱 전체에서 일관성을 제공하세요 앱의 맞춤형 커서가 시스템의 커서가 전달하지 않는 정보를 제공하지 않는다면 맞춤형 커서가 정말 필요한지 확인해 보아야 합니다 표준 커서를 활용하는 것이 더 쉬울 뿐만 아니라 직접 그리지 않아도 되고 또한 더 큰 손쉬운 사용 크기가 시스템 설정의 손쉬운 사용 섹션에 설정된 대로 지원됩니다 설정으로 포인터 색상을 조절하여 더 고유한 색상에 의존적인 사용자가 커서를 더 효과적으로 보고 위치를 찾도록 지원할 수도 있습니다 다음은 NSToolbar의 세 가지 개선 사항이며 더 많은 제어 기능을 디스플레이 모드 표시된 항목, 항목 가시성에 대해 제공합니다 NSToolbar는 텍스트 레이블이 있거나 없는 항목을 표시합니다 앱의 기본 스타일이 아이콘 전용인 경우에도 일부 사용자는 도구 막대 항목을 찾는 것이 더 편할 수 있습니다 텍스트 레이블을 통해 스캔할 수 있더라도 선택권을 제공하는 것이 좋습니다 macOS Sequoia에서는 이제 스타일 선택권을 제공할 수 있으며 도구 막대의 콘텐츠를 맞춤화할 수 없는 경우에도 allowsDisplayModeCustomization 속성을 사용하면 가능합니다 기본적으로 활성화된 기능입니다 도구 막대에 식별자가 포함되어 있어야 AppKit이 스타일 환경설정을 저장할 수 있으며 모든 도구 막대 항목의 레이블이 적정한지 이중으로 점검할 필요가 있습니다 NSToolbar의 기존 항목 속성보다 편리하게 새로운 itemIdentifiers 속성을 사용할 수 있습니다 도구 막대의 항목 식별자를 자동으로 설정하면 최소한의 추가와 제거 작업만 거치면 됩니다 allowsUserCustomization 속성이 활성화된 경우 여기에서 값을 변경하면 모든 맞춤화 설정을 덮어씁니다 따라서 이 옵션은 맞춤화할 수 없는 동적인 도구 막대에서만 사용하세요 현재 선택 항목에 적용되지 않는 항목을 비활성화하는 것이 좋습니다 윈도우 모드에서 변동이 있으면 프로그래밍 방식으로만 도구 막대에서 항목을 제거합니다 문서 편집과 보기 모드 전환을 예로 들 수 있습니다
조건부로 도구 막대 항목을 숨기거나 표시하는 데 isHidden 속성을 사용할 수도 있습니다 숨겨진 항목이 여전히 맞춤화에 표시되므로 사용자가 항목이 표시될 때 어디에 보여지길 원하는지 선택할 수 있습니다 윈도우의 현재 선택 항목과 관계없이 항목이 적용되지 않는 경우에 이 기능을 사용합니다
예를 들어 앱은 첫 다운로드가 시작될 때까지 다운로드를 표시하는 항목을 숨길 수 있습니다
다음으로 완전히 새로운 API인 텍스트 입력 제안을 소개합니다 이 기능을 사용하면 사용자가 시스템 표준 제안 메뉴에 입력할 때 앱에서 맞춤형 제안을 제공합니다 많은 앱에서 볼 수 있는 이 일반적인 패턴이 이제 macOS Sequoia의 AppKit에서 표준화되고 있습니다 이 기능은 NSSearchField와 같은 하위 클래스 등 모든 NSTextField에서 작동합니다 텍스트 필드에 suggestionsDelegate 속성을 설정하여 시작하세요 텍스트를 입력할 때 Delegate에 제안을 요청하고 그 결과에 대해 동기식과 비동기식으로 응답할 수 있습니다 필요에 따라 하이라이트와 선택 항목에서도 텍스트 완성을 맞춤화할 수 있습니다 다음은 텍스트 입력 제안을 사용할 때 유용한 몇 가지 디자인 팁입니다 특정 시점에 표시되는 제안이 입력된 텍스트와 연관성이 있어야 합니다 사용자는 입력 속도에 맞춰 인터페이스가 표시되기를 기대하기 때문입니다 일관성 있고 예측 가능한 제안을 제공하여 근육 기억을 유지하고 결과에 대한 신뢰를 구축합니다 동기식으로 제안이 제공되면 이미 제공한 제안들 바로 다음에 배치됩니다 단순하게 해야 합니다 가장 중요한 결과 및 세부 정보만 제공하여 적합한 결과를 신속하게 찾을 수 있어야 합니다 macOS Sequoia의 AppKit 개선 사항의 일부를 소개해 드렸습니다 더 많은 내용을 알고 싶으시면 developer.apple.com의 릴리스 노트를 읽어보시기 바랍니다
새로운 지능형 기능을 사용하고 API를 채택하여 앱을 원활하게 연동해 보세요
윈도우 타일 정렬 기능으로 윈도우 패널의 경계를 없애세요 앱 윈도우를 깔끔하게 정리될 준비가 되었는지 확인합니다 새로운 메뉴 및 애니메이션 API를 통해 SwiftUI를 계속 점진적으로 채택하세요 새로운 시스템 표준 구성 요소를 채택합니다 예를 들어 콘텐츠 유형 선택기, 커서, 텍스트 입력 제안 등입니다 키보드로 제공되는 빠른 메뉴를 사용하여 앱을 편하게 이동하도록 지원하고 도구 막대에서 모든 표시 모드를 지원하는지 확인합니다
시청해 주시고 Mac에서 멋진 앱을 개발해 주셔서 진심으로 감사드립니다 이러한 API가 페인트라고 가정하면 Xcode는 붓 Mac은 캔버스와 같습니다 여러분이 창조할 세상이 기대됩니다!
-
-
2:09 - Adding the Image Playground experience
extension DocumentCanvasViewController { @IBAction func importFromImagePlayground(_ sender: Any?) { // Initialize the playground, get set up to be notified of lifecycle events. let playground = ImagePlaygroundViewController() playground.delegate = self // Seed the playground with concepts and source imagery. (Optional) playground.concepts = [.text("birthday card")] playground.sourceImage = NSImage(named: "balloons") presentAsSheet(playground) } } extension DocumentCanvasViewController: ImagePlaygroundViewController.Delegate { func imagePlaygroundViewController( _ imagePlaygroundViewController: ImagePlaygroundViewController, didCreateImageAt resultingImageURL: URL ) { if let image = NSImage(contentsOf: resultingImageURL) { imageView.image = image } else { logger.error("Could not read image at \(resultingImageURL)") } dismiss(imagePlaygroundViewController) } }
-
5:50 - Using window resize increments
window.resizeIncrements = NSSize(width: characterWidth, height: characterHeight)
-
7:05 - Build menus with SwiftUI
struct ActionMenu: View { var body: some View { Toggle("Use Groups", isOn: $useGroups) Picker("Sort By", selection: $sortOrder) { ForEach(SortOrder.allCases) { Text($0.title) } }.pickerStyle(.inline) Button("Customize View…") { <#Action#> } } } let menu = NSHostingMenu(rootView: ActionMenu()) let pullDown = NSPopUpButton(image: image, pullDownMenu: menu)
-
7:43 - Get animated with SwiftUI
NSAnimationContext.animate(with: .spring(duration: 0.3)) { drawer.isExpanded.toggle() }
-
7:55 - Get animated with SwiftUI
class PaletteView: NSView { @Invalidating(.layout) var isExpanded: Bool = false private func onHover(_ isHovered: Bool) { NSAnimationContext.animate(with: .spring) { isExpanded = isHovered layoutSubtreeIfNeeded() } } }
-
10:31 - Text highlighting
let attributes: [NSAttributedString.Key: Any] = [ .textHighlight: NSAttributedString.TextHighlightStyle.systemDefault, .textHighlightColorScheme: NSAttributedString.TextHighlightColorScheme.pink, ]
-
11:11 - SF Symbols effects
imageView.addSymbolEffect(.wiggle) imageView.addSymbolEffect(.rotate) imageView.addSymbolEffect(.breathe)
-
11:24 - SF Symbols playback (periodic)
imageView.addSymbolEffect(.wiggle, options: .repeat(.periodic(3, delay: 0.5)))
-
11:30 - SF Symbols playback (continuous)
imageView.addSymbolEffect(.wiggle, options: .repeat(.continuous))
-
11:37 - SF Symbols magic replace
imageView.setSymbolImage(badgedSymbolImage, contentTransition: .replace)
-
12:19 - Save panel content types
extension ImageViewController: NSOpenSavePanelDelegate { @MainActor @IBAction internal func saveDocument(_ sender: Any?) { Task { let savePanel = NSSavePanel() savePanel.delegate = self savePanel.identifier = NSUserInterfaceItemIdentifier("ImageExport") savePanel.showsContentTypes = true savePanel.allowedContentTypes = [.png, .jpeg] let result = await savePanel.beginSheetModal(for: window) switch result { case .OK: let url = savePanel.url // Save the document to 'url'. It already has the appropriate extension. case .cancel: break default: break } } } func panel(_ panel: Any, displayNameFor type: UTType) -> String? { switch type { case .png: NSLocalizedString("PNG (Greater Quality)", comment: <#Comment#>) case .jpeg: NSLocalizedString("JPG (Smaller File Size)", comment: <#Comment#>) default: nil } } }
-
13:34 - Frame-resize cursors
let cursor = NSCursor.frameResize(position: .bottomRight, directions: .all)
-
14:20 - Column and row resize cursors
let cursor = NSCursor.columnResize(directions: .left) let cursor = NSCursor.rowResize(directions: .up)
-
14:29 - Zoom in and out cursors
let cursor = NSCusor.zoomIn let cursor = NSCusor.zoomOut
-
15:57 - Display mode customizable toolbar
let toolbar = NSToolbar(identifier: NSToolbar.Identifier("ViewerWindow")) toolbar.allowsDisplayModeCustomization // Defaults to `true`.
-
16:57 - Hidden toolbar items
let downloadsToolbarItem: NSToolbarItem downloadsToolbarItem.isHidden = downloadsManager.downloads.isEmpty
-
17:49 - Text entry suggestions
class MYViewController: NSViewController { let museumTextField = NSTextField(string: "") let museumTextSuggestionsController = MuseumTextSuggestionsController() override func viewDidLoad() { super.viewDidLoad() self.museumTextField.suggestionsDelegate = self.museumTextSuggestionsController } } class MuseumTextSuggestionsController: NSTextSuggestionsDelegate { typealias SuggestionItemType = Museum func textField( _ textField: NSTextField, provideUpdatedSuggestions responseHandler: @escaping ((ItemResponse) -> Void) ) { let searchString = textField.stringValue func museumItem(_ museum: Museum) -> Item { var item = NSSuggestionItem(representedValue: museum, title: museum.name) item.secondaryTitle = museum.address return item } let favoriteMuseums = Museum.favorites.filter({ $0.matches(searchString) }) let favorites = NSSuggestionItemSection( title: NSLocalizedString("Favorites", comment: "The title of suggestion results section containing favorite museums."), items: favoriteMuseums.map(museumItem(_:)) ) var response = NSSuggestionItemResponse(itemSections: [favorites]) response.phase = .intermediate responseHandler(response) Task { let otherMuseums = await Museum.allMatching(searchString) let nonFavorites = NSSuggestionItemSection(items: otherMuseums.map(museumItem(_:))) var response = NSSuggestionItemResponse(itemSections: [ favorites, nonFavorites, ]) response.phase = .final responseHandler(response) } } }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.