최신 macOS 앱 빌드Building Modern macOS Apps

이 문서에서는 개발자가 Xamarin.ios에서 최신 macOS 앱을 빌드하는 데 사용할 수 있는 몇 가지 팁, 기능 및 기술을 설명 합니다.This article covers several tips, features and techniques a developer can use to build a modern macOS app in Xamarin.Mac.

최신 보기를 사용 하 여 최신 빌드 빌드Building Modern Looks with Modern Views

최신 창 및 도구 모음 모양 (예: 아래에 표시 된 예제 앱)이 포함 됩니다.A modern look will include a modern Window and Toolbar appearance such as the example app shown below:

전체 크기의 콘텐츠 보기 사용Enabling Full Sized Content Views

이를 위해 Xamarin.ios 앱에서 개발자는 _전체 크기의 콘텐츠 보기_를 사용 하려고 합니다. 즉, 콘텐츠가 도구 및 제목 표시줄 영역 아래에 확장 되 고 macos에 의해 자동으로 흐리게 표시 됩니다.To achieve this looks in a Xamarin.Mac app, the developer will want to use a Full Size Content View, meaning the content extends under the Tool and Title Bar areas and will be automatically blurred by macOS.

코드에서이 기능을 사용 하도록 설정 하려면 NSWindowController에 대 한 사용자 지정 클래스를 만들고 다음과 같이 만듭니다.To enable this feature in code, create a custom class for the NSWindowController and make it look like the following:

using System;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainWindowController : NSWindowController
    {
        #region Constructor
        public MainWindowController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void WindowDidLoad ()
        {
            base.WindowDidLoad ();

            // Set window to use Full Size Content View
            Window.StyleMask = NSWindowStyle.FullSizeContentView;
        }
        #endregion
    }
}

창을 선택 하 고 전체 크기의 콘텐츠 보기를 확인 하 여 Xcode의 Interface Builder 에서도이 기능을 사용 하도록 설정할 수 있습니다.This feature can also be enabled in Xcode's Interface Builder by selecting the Window and checking Full Sized Content View:

전체 크기 콘텐츠 보기를 사용 하는 경우 개발자는 특정 콘텐츠 (예: 레이블)에서 슬라이드를 이동 하지 않도록 제목 및 도구 모음 영역 아래에 콘텐츠를 오프셋 해야 할 수 있습니다.When using a Full Size Content View, the developer may need to offset the content beneath the title and tool bar areas so that specific content (such as labels) doesn't slide under them.

이 문제를 복잡 하 게 하려면 제목 및 도구 모음 영역에 사용자가 현재 수행 하 고 있는 작업, 사용자가 설치한 macOS 버전 및/또는 앱이 실행 되 고 있는 Mac 하드웨어에 따라 동적 높이가 있을 수 있습니다.To complicate this issue, the Title and Tool Bar areas can have a dynamic height based on the action that the user is currently performing, the version of macOS the user has installed and/or the Mac hardware that the app is running on.

따라서 사용자 인터페이스를 레이아웃할 때 오프셋을 하드 코딩 하는 것은 쉽지 않습니다.As a result, simply hard coding the offset when laying out the User Interface will not work. 개발자가 동적 접근 방법을 사용 해야 합니다.The developer will need to take a dynamic approach.

Apple은 NSWindow 클래스의 키-값 관찰 가능 ContentLayoutRect 속성을 포함 하 여 코드에서 현재 콘텐츠 영역을 가져옵니다.Apple has included the Key-Value Observable ContentLayoutRect property of the NSWindow class to get the current Content Area in code. 개발자는이 값을 사용 하 여 콘텐츠 영역이 변경 될 때 필요한 요소를 수동으로 배치할 수 있습니다.The developer can use this value to manually position the required elements when the Content Area changes.

더 나은 솔루션은 자동 레이아웃 및 크기 클래스를 사용 하 여 UI 요소를 두 코드 또는 Interface Builder 배치 하는 것입니다.The better solution is to use Auto Layout and Size Classes to position the UI elements in either code or Interface Builder.

다음 예제와 같은 코드를 사용 하 여 앱의 뷰 컨트롤러에서 자동 레이아웃 및 크기 클래스를 사용 하 여 UI 요소를 배치할 수 있습니다.Code like the following example can be used to position UI elements using AutoLayout and Size Classes in the app's View Controller:

using System;
using AppKit;
using Foundation;

namespace MacModern
{
    public partial class ViewController : NSViewController
    {
        #region Computed Properties
        public NSLayoutConstraint topConstraint { get; set; }
        #endregion

        ...

        #region Override Methods
        public override void UpdateViewConstraints ()
        {
            // Has the constraint already been set?
            if (topConstraint == null) {
                // Get the top anchor point
                var contentLayoutGuide = ItemTitle.Window?.ContentLayoutGuide as NSLayoutGuide;
                var topAnchor = contentLayoutGuide.TopAnchor;

                // Found?
                if (topAnchor != null) {
                    // Assemble constraint and activate it
                    topConstraint = topAnchor.ConstraintEqualToAnchor (topAnchor, 20);
                    topConstraint.Active = true;
                }
            }

            base.UpdateViewConstraints ();
        }
        #endregion
    }
}

이 코드는 제목 및 도구 모음 영역에서 지연 되지 않도록 레이블 (ItemTitle)에 적용 되는 최상위 제약 조건에 대 한 저장소를 만듭니다.This code creates storage for a top constraint that will be applied to a Label (ItemTitle) to ensure that it doesn't slip under the Title and Tool Bar area:

public NSLayoutConstraint topConstraint { get; set; }

개발자는 뷰 컨트롤러의 UpdateViewConstraints 메서드를 재정의 하 여 필요한 제약 조건이 이미 빌드 되었는지 확인 하 고 필요한 경우이를 만들지를 테스트할 수 있습니다.By overriding the View Controller's UpdateViewConstraints method, the developer can test to see if the needed constraint has already been built and create it if needed.

새 제약 조건을 빌드해야 하는 경우 창의 ContentLayoutGuide 속성은 제한 되어야 하는 컨트롤에 액세스 하 여 NSLayoutGuide로 캐스팅 합니다.If a new constraint needs to be built, the ContentLayoutGuide property of the Window the control that needs to be constrained is accessed and cast into a NSLayoutGuide:

var contentLayoutGuide = ItemTitle.Window?.ContentLayoutGuide as NSLayoutGuide;

NSLayoutGuide의 TopAnchor 속성에 액세스 하 여 사용할 수 있는 경우, 원하는 오프셋 양만큼 새 제약 조건을 작성 하는 데 사용 되며 새 제약 조건이 활성으로 설정 되어 적용 됩니다.The TopAnchor property of the NSLayoutGuide is accessed and if it is available, it is used to build a new constraint with the desired offset amount and the new constraint is made active to apply it:

// Assemble constraint and activate it
topConstraint = topAnchor.ConstraintEqualToAnchor (topAnchor, 20);
topConstraint.Active = true;

간소화 된 도구 모음 사용Enabling Streamlined Toolbars

표준 macOS 창에는 창의 위쪽 가장자리를 따라 실행에 표준 제목 표시줄이 있습니다.A normal macOS Window includes a standard Title Bar at runs along to top edge of the Window. 창에도 도구 모음이 포함 되어 있으면이 제목 표시줄 영역 아래에 표시 됩니다.If the Window also includes a Tool Bar, it will be displayed under this Title Bar area:

간소화 된 도구 모음을 사용 하면 제목 영역이 사라지고 도구 모음이 창 닫기, 최소화 및 최대화 단추를 사용 하 여 제목 표시줄의 위치로 이동 합니다.When using a Streamlined Toolbar, the Title Area disappears and the Tool Bar moves up into the Title Bar's position, in-line with the Window Close, Minimize and Maximize buttons:

간소화 된 도구 모음은 NSViewControllerViewWillAppear 메서드를 재정의 하 여 사용 하도록 설정 되며 다음과 같이 표시 됩니다.The Streamlined Toolbar is enabled by overriding the ViewWillAppear method of the NSViewController and making it look like the following:

public override void ViewWillAppear ()
{
    base.ViewWillAppear ();

    // Enable streamlined Toolbars
    View.Window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}

이 효과는 일반적으로 지도, 일정, 메모 및 시스템 기본 설정과 같은 Shoebox 응용 프로그램 (하나의 창 앱)에 사용 됩니다.This effect is typically used for Shoebox Applications (one window apps) like Maps, Calendar, Notes and System Preferences.

액세서리 보기 컨트롤러 사용Using Accessory View Controllers

응용 프로그램의 디자인에 따라 개발자는 제목/도구 모음 영역 바로 아래에 표시 되는 액세서리 뷰 컨트롤러를 사용 하 여 제목 표시줄 영역을 보완 하 여 해당 활동에 따라 사용자에 게 상황에 맞는 컨트롤을 제공할 수도 있습니다. 현재 참여 하 고 있습니다.Depending on the design of the app, the developer might also want to complement the Title Bar area with an Accessory View Controller that appears right below the Title/Tool Bar area to provide context sensitive controls to the user based on the activity they are currently engaged in:

액세서리 뷰 컨트롤러는 개발자 개입 없이 시스템에 의해 자동으로 흐리게 표시 되 고 크기가 조정 됩니다.The Accessory View controller will automatically be blurred and resized by the system without developer intervention.

액세서리 뷰 컨트롤러를 추가 하려면 다음을 수행 합니다.To add an Accessory View Controller, do the following:

  1. 편집하기 위해 솔루션 탐색기에서 Main.storyboard 파일을 두 번 클릭하여 엽니다.In the Solution Explorer, double-click the Main.storyboard file to open it for editing.

  2. 사용자 지정 뷰 컨트롤러 를 창의 계층으로 끌어 옵니다.Drag a Custom View Controller into the Window's hierarchy:

  3. 액세서리 보기의 UI 레이아웃:Layout the Accessory View's UI:

  4. 해당 UI에 대 한 콘센트 및 기타 작업 또는 콘센트 로 액세서리 보기를 노출 합니다.Expose the Accessory View as an Outlet and any other Actions or Outlets for its UI:

  5. 변경 내용을 저장합니다.Save the changes.

  6. Mac용 Visual Studio로 돌아와서 변경 내용을 동기화 합니다.Return to Visual Studio for Mac to sync the changes.

NSWindowController 편집 하 고 다음과 같이 표시 합니다.Edit the NSWindowController and make it look like the following:

using System;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainWindowController : NSWindowController
    {
        #region Constructor
        public MainWindowController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void WindowDidLoad ()
        {
            base.WindowDidLoad ();

            // Create a title bar accessory view controller and attach
            // the view created in Interface Builder
            var accessoryView = new NSTitlebarAccessoryViewController ();
            accessoryView.View = AccessoryViewGoBar;

            // Set the location and attach the accessory view to the
            // titlebar to be displayed
            accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;
            Window.AddTitlebarAccessoryViewController (accessoryView);

        }
        #endregion
    }
}

이 코드의 핵심 요소는 뷰가 Interface Builder 정의 되 고 유출로 노출 되는 사용자 지정 뷰로 설정 되는 위치입니다.The key points of this code are where the View is set to the custom View that was defined in Interface Builder and exposed as an Outlet:

accessoryView.View = AccessoryViewGoBar;

그리고 액세서리를 표시할 위치 를 정의 하는 LayoutAttribute:And the LayoutAttribute that defines where the accessory will be displayed:

accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;

이제 macOS는 완전히 지역화 되었으므로 LeftRight NSLayoutAttribute 속성은 더 이상 사용 되지 않으므로 LeadingTrailing으로 바꾸어야 합니다.Because macOS is now fully localized, the Left and Right NSLayoutAttribute properties have been deprecated and should be replaced with Leading and Trailing.

탭 창 사용Using Tabbed Windows

또한 macOS 시스템은 앱의 창에 액세서리 보기 컨트롤러를 추가할 수 있습니다.Additionally, the macOS system might add Accessory View Controllers to the app's Window. 예를 들어 여러 앱 창이 하나의 가상 창으로 병합 되는 탭 창을 만들려면 다음을 수행 합니다.For example, to create Tabbed Windows where several of the App's Windows are merged into one virtual Window:

일반적으로 개발자는 사용자의 Xamarin.ios 앱에서 탭 창을 사용 하 여 제한 된 작업을 수행 해야 합니다. 시스템은 다음과 같이 자동으로 처리 합니다.Typically, the developer will need to take limited action use Tabbed Windows in their Xamarin.Mac apps, the system will handle them automatically as follows:

  • OrderFront 메서드가 호출 되 면 Windows가 자동으로 탭 됩니다.Windows will automatically be Tabbed when the OrderFront method is invoked.
  • OrderOut 메서드가 호출 되 면 Windows가 자동으로 탭 되지 않습니다.Windows will automatically be Untabbed when the OrderOut method is invoked.
  • 코드에서 모든 탭 창은 여전히 "표시" 된 것으로 간주 되지만 CoreGraphics를 사용 하 여 시스템에서 맨 앞에 있지 않은 탭은 숨겨집니다.In code all Tabbed windows are still considered "visible", however any non-frontmost Tabs are hidden by the system using CoreGraphics.
  • NSWindowTabbingIdentifier 속성을 사용 하 여 창을 탭으로 그룹화 합니다.Use the TabbingIdentifier property of NSWindow to group Windows together into Tabs.
  • NSDocument 기반 앱 인 경우 이러한 기능 중 일부는 개발자 작업 없이 자동으로 설정 됩니다 (예: 탭 모음에 추가 되는 더하기 단추).If it is an NSDocument based app, several of these features will be enabled automatically (such as the plus button being added to the Tab Bar) without any developer action.
  • NSDocument 기반이 아닌 앱은 NSWindowsControllerGetNewWindowForTab 메서드를 재정의 하 여 새 문서를 추가 하는 탭 그룹의 "더하기" 단추를 사용할 수 있습니다.Non-NSDocument based apps can enable the "plus" button in the Tab Group to add a new document by overriding the GetNewWindowForTab method of the NSWindowsController.

모든 부분을 결합 하 여 시스템 기반 탭 창을 사용 하고자 하는 앱의 AppDelegate은 다음과 같습니다.Bringing all of the pieces together, the AppDelegate of an app that wanted to use system based Tabbed Windows could look like the following:

using AppKit;
using Foundation;

namespace MacModern
{
    [Register ("AppDelegate")]
    public class AppDelegate : NSApplicationDelegate
    {
        #region Computed Properties
        public int NewDocumentNumber { get; set; } = 0;
        #endregion

        #region Constructors
        public AppDelegate ()
        {
        }
        #endregion

        #region Override Methods
        public override void DidFinishLaunching (NSNotification notification)
        {
            // Insert code here to initialize your application
        }

        public override void WillTerminate (NSNotification notification)
        {
            // Insert code here to tear down your application
        }
        #endregion

        #region Custom Actions
        [Export ("newDocument:")]
        public void NewDocument (NSObject sender)
        {
            // Get new window
            var storyboard = NSStoryboard.FromName ("Main", null);
            var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

            // Display
            controller.ShowWindow (this);
        } 
        #endregion
    }
}

NewDocumentNumber 속성은 만들어진 새 문서 수를 추적 하 고 NewDocument 메서드는 새 문서를 만들어 표시 합니다.Where the NewDocumentNumber property keeps track of the number of new documents created and the NewDocument method creates a new document and displays it.

NSWindowController는 다음과 같습니다.The NSWindowController could then look like:

using System;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainWindowController : NSWindowController
    {
        #region Application Access
        /// <summary>
        /// A helper shortcut to the app delegate.
        /// </summary>
        /// <value>The app.</value>
        public static AppDelegate App {
            get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
        }
        #endregion

        #region Constructor
        public MainWindowController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Public Methods
        public void SetDefaultDocumentTitle ()
        {
            // Is this the first document?
            if (App.NewDocumentNumber == 0) {
                // Yes, set title and increment
                Window.Title = "Untitled";
                ++App.NewDocumentNumber;
            } else {
                // No, show title and count
                Window.Title = $"Untitled {App.NewDocumentNumber++}";
            }
        }
        #endregion

        #region Override Methods
        public override void WindowDidLoad ()
        {
            base.WindowDidLoad ();

            // Prefer Tabbed Windows
            Window.TabbingMode = NSWindowTabbingMode.Preferred;
            Window.TabbingIdentifier = "Main";

            // Set default window title
            SetDefaultDocumentTitle ();

            // Set window to use Full Size Content View
            // Window.StyleMask = NSWindowStyle.FullSizeContentView;

            // Create a title bar accessory view controller and attach
            // the view created in Interface Builder
            var accessoryView = new NSTitlebarAccessoryViewController ();
            accessoryView.View = AccessoryViewGoBar;

            // Set the location and attach the accessory view to the
            // titlebar to be displayed
            accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;
            Window.AddTitlebarAccessoryViewController (accessoryView);

        }

        public override void GetNewWindowForTab (NSObject sender)
        {
            // Ask app to open a new document window
            App.NewDocument (this);
        }
        #endregion
    }
}

여기서 정적 App 속성은 AppDelegate를 가져올 수 있는 바로 가기를 제공 합니다.Where the static App property provides a shortcut to get to the AppDelegate. SetDefaultDocumentTitle 메서드는 생성 된 새 문서 수를 기준으로 새 문서 제목을 설정 합니다.The SetDefaultDocumentTitle method sets a new documents title based on the number of new documents created.

다음 코드는 응용 프로그램에서 탭 사용을 선호 하 고 앱의 창을 탭으로 그룹화 할 수 있도록 하는 문자열을 제공 하도록 macOS에 지시 합니다.The following code, tells macOS that the app prefers to use tabs and provides a string that allows the app's Windows to be grouped into Tabs:

// Prefer Tabbed Windows
Window.TabbingMode = NSWindowTabbingMode.Preferred;
Window.TabbingIdentifier = "Main";

다음 재정의 메서드는 사용자가 클릭 했을 때 새 문서를 만들 탭 표시줄에 plus 단추를 추가 합니다.And the following override method adds a plus button to the Tab Bar that will create a new document when clicked by the user:

public override void GetNewWindowForTab (NSObject sender)
{
    // Ask app to open a new document window
    App.NewDocument (this);
}

핵심 애니메이션 사용Using Core Animation

핵심 애니메이션은 macOS에 내장 된 고성능 그래픽 렌더링 엔진입니다.Core Animation is a high powered graphics rendering engine that is built into macOS. 핵심 애니메이션은 CPU에서 그래픽 작업을 실행 하는 것이 아니라 최신 macOS 하드웨어에서 사용할 수 있는 GPU (그래픽 처리 장치)를 활용 하도록 최적화 되었습니다 .이로 인해 컴퓨터의 속도가 느려질 수 있습니다.Core Animation has been optimized to take advantage of the GPU (Graphics Processing Unit) available in modern macOS hardware as opposed to running the graphics operations on the CPU, which can slow down the machine.

핵심 애니메이션에 의해 제공 되는 CALayer는 고속, 유체 스크롤 및 애니메이션과 같은 작업에 사용할 수 있습니다.The CALayer, provided by Core Animation, can be used for tasks such as fast and fluid scrolling and animations. 코어 애니메이션을 완벽 하 게 활용 하려면 앱의 사용자 인터페이스를 여러 하위 뷰 및 계층으로 구성 해야 합니다.An app's User Interface should be composed of multiple subviews and layers to fully take advantage of Core Animation.

CALayer 개체는 개발자가 사용자에 게 화면에 표시 되는 내용을 제어할 수 있는 여러 가지 속성을 제공 합니다.A CALayer object provides several properties that allow the developer to control what is presented onscreen to the user such as:

  • Content-계층의 내용을 제공 하는 NSImage 또는 CGImage 수 있습니다.Content - Can be a NSImage or CGImage that provides the contents of the layer.
  • BackgroundColor-계층의 배경색을 CGColor 설정 합니다.BackgroundColor - Sets the background color of the layer as a CGColor
  • BorderWidth-테두리 두께를 설정 합니다.BorderWidth - Sets the border width.
  • BorderColor-테두리 색을 설정 합니다.BorderColor - Sets the border color.

앱의 UI에서 핵심 그래픽을 활용 하려면 계층 지원 뷰를 사용 해야 합니다 .이 뷰는 Apple에서 개발자가 항상 창의 콘텐츠 보기에서 사용 하도록 설정 해야 한다는 것을 제안 합니다.To utilize Core Graphics in the app's UI, it must be using Layer Backed Views, which Apple suggests that the developer should always enable in the Window's Content View. 이러한 방식으로 모든 자식 보기는 계층 백업도 자동으로 상속 합니다.This way, all child views will automatically inherit Layer Backing as well.

또한 Apple은 새 CALayer를 하위 계층으로 추가 하는 것과는 반대로 계층 기반 뷰를 사용 하는 것을 제안 합니다 .이는 시스템에서 필요한 설정 (예: 레 티 나 표시에 필요한 설정)을 자동으로 처리 하기 때문입니다.Additionally, Apple suggests using Layer Backed Views as opposed to adding a new CALayer as a sublayer because the system will automatically handle several of the required settings (such as those required by a Retina Display).

계층 백업은 핵심 애니메이션 계층을 확인 하 여 보기 효과 검사자 아래에 있는 Xcode의 Interface Builder true NSView WantsLayer 설정 하 여 활성화할 수 있습니다.Layer Backing can be enabled by setting the WantsLayer of a NSView to true or inside of Xcode's Interface Builder under the View Effects Inspector by checking Core Animation Layer:

레이어를 사용 하 여 뷰 다시 그리기Redrawing Views with Layers

Xamarin.ios 앱에서 계층 기반 뷰를 사용 하는 경우 또 다른 중요 한 단계는 NSViewController에서 OnSetNeedsDisplay NSView LayerContentsRedrawPolicy 설정 하는 것입니다.Another important step when using Layer Backed Views in a Xamarin.Mac app is setting the LayerContentsRedrawPolicy of the NSView to OnSetNeedsDisplay in the NSViewController. 예를 들면,For example:

public override void ViewWillAppear ()
{
    base.ViewWillAppear ();

    // Set the content redraw policy
    View.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}

개발자가이 속성을 설정 하지 않으면 해당 프레임 원본이 변경 될 때마다 뷰가 다시 그려져 성능상의 이유로 적절 하지 않습니다.If the developer doesn't set this property, the View will be redrawn whenever its frame origin changes, which is not desired for performance reasons. 그러나이 속성을 OnSetNeedsDisplay로 설정 하면 개발자는 수동으로 NeedsDisplaytrue로 설정 하 여 콘텐츠를 다시 그리도록 강제할 수 있습니다.With this property set to OnSetNeedsDisplay the developer will manually have to set NeedsDisplay to true to force the content to redraw, however.

뷰가 커밋되지 않은 것으로 표시 되 면 시스템은 뷰의 WantsUpdateLayer 속성을 확인 합니다.When a View is marked as dirty, the system checks the WantsUpdateLayer property of the View. true 반환 하는 경우 UpdateLayer 메서드를 호출 합니다 .이 경우 뷰의 DrawRect 메서드를 호출 하 여 뷰의 내용을 업데이트 합니다.If it returns true then the UpdateLayer method is called, else the DrawRect method of the View is called to update the View's contents.

Apple에는 필요할 때 보기 콘텐츠를 업데이트 하기 위한 다음과 같은 제안이 있습니다.Apple has the following suggestions for updating a Views contents when required:

  • Apple은 가능한 경우 상당한 성능 향상을 제공 하므로 DrawRect를 사용 하 여 UpdateLater를 선호 합니다.Apple prefers using UpdateLater over DrawRect whenever possible as it provides a significant performance boost.
  • 비슷한 모양의 UI 요소에 대해 동일한 layer.Contents를 사용 합니다.Use the same layer.Contents for UI elements that look similar.
  • 또한 Apple은 가능한 한 언제 든 지 NSTextField와 같은 표준 뷰를 사용 하 여 UI를 작성 하도록 개발자에 게 선호 합니다.Apple also prefers the developer to compose their UI using standard views such as NSTextField, again whenever possible.

UpdateLayer을 사용 하려면 NSView에 대 한 사용자 지정 클래스를 만들고 코드를 다음과 같이 만듭니다.To use UpdateLayer, create a custom class for the NSView and make the code look like the following:

using System;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainView : NSView
    {
        #region Computed Properties
        public override bool WantsLayer {
            get { return true; }
        }

        public override bool WantsUpdateLayer {
            get { return true; }
        }
        #endregion

        #region Constructor
        public MainView (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void DrawRect (CoreGraphics.CGRect dirtyRect)
        {
            base.DrawRect (dirtyRect);

        }

        public override void UpdateLayer ()
        {
            base.UpdateLayer ();

            // Draw view 
            Layer.BackgroundColor = NSColor.Red.CGColor;
        }
        #endregion
    }
}

최신 끌어서 놓기를 사용 하 여Using Modern Drag and Drop

사용자에 게 최신 끌어서 놓기 환경을 제공 하기 위해 개발자는 앱의 끌어서 놓기 작업에서 끌어서 놓기를 채택 해야 합니다.To present a modern Drag and Drop experience for the user, the developer should adopt Drag Flocking in their app's Drag and Drop operations. 끌기 flocking는 사용자가 끌기 작업을 계속할 때 처음에 끌어 오는 개별 파일 또는 항목이 각각 flocking의 개별 요소로 표시 됩니다 (항목 수를 포함 하 여 커서 아래에 그룹화).Drag Flocking is where each individual file or item being dragged initially appears as an individual element that flocks (group together under the cursor with a count of the number of items) as the user continues the drag operation.

사용자가 끌기 작업을 종료 하면 개별 요소가 Unflock 원래 위치로 돌아갑니다.If the user terminates the Drag operation, the individual elements will Unflock and return to their original locations.

다음 예제 코드에서는 사용자 지정 뷰에서 끌기를 사용할 수 있습니다.The following example code enables Drag Flocking on a custom View:

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainView : NSView, INSDraggingSource, INSDraggingDestination
    {
        #region Constructor
        public MainView (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void MouseDragged (NSEvent theEvent)
        {
            // Create group of string to be dragged
            var string1 = new NSDraggingItem ((NSString)"Item 1");
            var string2 = new NSDraggingItem ((NSString)"Item 2");
            var string3 = new NSDraggingItem ((NSString)"Item 3");

            // Drag a cluster of items
            BeginDraggingSession (new [] { string1, string2, string3 }, theEvent, this);
        }
        #endregion
    }
}

NSViewBeginDraggingSession 메서드로 끌어 온 각 항목을 배열의 개별 요소로 보내 flocking 효과를 달성 했습니다.The flocking effect was achieved by sending each item being dragged to the BeginDraggingSession method of the NSView as a separate element in an array.

NSTableView 또는 NSOutlineView작업 하는 경우 NSTableViewDataSource 클래스의 PastboardWriterForRow 메서드를 사용 하 여 끌기 작업을 시작 합니다.When working with a NSTableView or NSOutlineView, use the PastboardWriterForRow method of the NSTableViewDataSource class to start the Dragging operation:

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace MacModern
{
    public class ContentsTableDataSource: NSTableViewDataSource
    {
        #region Constructors
        public ContentsTableDataSource ()
        {
        }
        #endregion

        #region Override Methods
        public override INSPasteboardWriting GetPasteboardWriterForRow (NSTableView tableView, nint row)
        {
            // Return required pasteboard writer
            ...
            
            // Pasteboard writer failed
            return null;
        }
        #endregion
    }
}

이를 통해 개발자는 모든 행을 단일 그룹으로 모든 행을 기록 하는 이전 메서드 WriteRowsWith를 비롯 하 여 끌고 있는 테이블의 모든 항목에 대해 개별 NSDraggingItem를 제공할 수 있습니다.This allows the developer to provide an individual NSDraggingItem for every item in the table that is being dragged as opposed to the older method WriteRowsWith that write all of the rows as a single group to the pasteboard.

NSCollectionViews작업할 때 끌기를 시작할 때 WriteItemsAt 메서드와 달리 PasteboardWriterForItemAt 메서드를 다시 사용 합니다.When working with NSCollectionViews, again use the PasteboardWriterForItemAt method as opposed to the WriteItemsAt method when Dragging begins.

개발자는 항상 많은 파일을 대지의 위에 배치 하지 않아야 합니다.The developer should always avoid putting large files on the pasteboard. MacOS Sierra를 처음 사용 하는 경우 파일 약속 을 사용 하면 개발자가 새 NSFilePromiseProviderNSFilePromiseReceiver 클래스를 사용 하 여 삭제 작업을 완료할 때 나중에 충족 될 수 있는 지정 된 파일에 대 한 참조를 추가할 수 있습니다.New to macOS Sierra, File Promises allow the developer to place references to given files on the pasteboard that will later be fulfilled when the user finishes the Drop operation using the new NSFilePromiseProvider and NSFilePromiseReceiver classes.

최신 이벤트 추적 사용Using Modern Event Tracking

제목 또는 도구 모음 영역에 추가 된 사용자 인터페이스 요소 (예: NSButton)의 경우 사용자는 요소를 클릭 하 여 이벤트를 정상적으로 발생 시킬 수 있어야 합니다 (예: 팝업 창 표시).For a User Interface element (such as a NSButton) that has been added to a Title or Tool Bar area, the user should be able to click the element and have it fire an event as normal (such as displaying a popup window). 그러나 항목은 제목 또는 도구 모음 영역에도 있으므로 사용자는 요소를 클릭 하 고 끌어서 창도 이동할 수 있어야 합니다.However, since the item is also in the Title or Tool Bar area, the user should be able to click and drag the element to move the window as well.

코드에서이 작업을 수행 하려면 요소에 대 한 사용자 지정 클래스 (예: NSButton)를 만들고 다음과 같이 MouseDown 이벤트를 재정의 합니다.To accomplish this in code, create a custom class for the element (such as NSButton) and override the MouseDown event as follows:

public override void MouseDown (NSEvent theEvent)
{
    var shouldCallSuper = false;

    Window.TrackEventsMatching (NSEventMask.LeftMouseUp, 2000, NSRunLoop.NSRunLoopEventTracking, (NSEvent evt, ref bool stop) => {
        // Handle event as normal
        stop = true;
        shouldCallSuper = true;
    });

    Window.TrackEventsMatching(NSEventMask.LeftMouseDragged, 2000, NSRunLoop.NSRunLoopEventTracking, (NSEvent evt, ref bool stop) => {
        // Pass drag event to window
        stop = true;
        Window.PerformWindowDrag (evt);
    });

    // Call super to handle mousedown
    if (shouldCallSuper) {
        base.MouseDown (theEvent);
    }
}

이 코드는 UI 요소가 연결 된 NSWindowTrackEventsMatching 메서드를 사용 하 여 LeftMouseUpLeftMouseDragged 이벤트를 가로챕니다.This code uses the TrackEventsMatching method of the NSWindow that the UI element is attached to intercept the LeftMouseUp and LeftMouseDragged events. LeftMouseUp 이벤트의 경우 UI 요소는 정상적으로 응답 합니다.For a LeftMouseUp event, the UI element responds as normal. LeftMouseDragged 이벤트의 경우 이벤트를 NSWindowPerformWindowDrag 메서드로 전달 하 여 창을 화면으로 이동 합니다.For the LeftMouseDragged event, the event is passed to the NSWindow's PerformWindowDrag method to move the window on screen.

NSWindow 클래스의 PerformWindowDrag 메서드를 호출 하면 다음과 같은 이점이 있습니다.Calling the PerformWindowDrag method of the NSWindow class provides the following benefits:

  • 앱이 중지 된 경우 (예: 심층 루프를 처리 하는 경우)에도 창이 이동 될 수 있습니다.It allows for the Window to move, even if the app is hung (such as when processing a deep loop).
  • 공간 전환은 예상 대로 작동 합니다.Space switching will work as expected.
  • 공백 막대가 정상적으로 표시 됩니다.The Spaces Bar will be displayed as normal.
  • 창 맞춤 및 맞춤은 정상적으로 작동 합니다.Window snapping and alignment work as normal.

최신 컨테이너 뷰 컨트롤 사용Using Modern Container View Controls

macOS Sierra는 이전 버전의 OS에서 사용할 수 있는 기존 컨테이너 뷰 컨트롤의 많은 최신 향상 기능을 제공 합니다.macOS Sierra provides many modern improvements to the existing Container View Controls available in previous version of the OS.

테이블 뷰 향상Table View Enhancements

개발자는 항상 NSTableView와 같은 컨테이너 뷰 컨트롤의 새로운 NSView 기반 버전을 사용 해야 합니다.The developer should always use the new NSView based version of Container View Controls such as NSTableView. 예를 들면,For example:

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace MacModern
{
    public class ContentsTableDelegate : NSTableViewDelegate
    {
        #region Constructors
        public ContentsTableDelegate ()
        {
        }
        #endregion

        #region Override Methods
        public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
        {
            // Build new view
            var view = new NSView ();
            ...

            // Return the view representing the item to display
            return view;
        }
        #endregion
    }
}

이렇게 하면 테이블의 지정 된 행에 사용자 지정 테이블 행 작업을 연결할 수 있습니다 (예: 행을 삭제 하려면 오른쪽으로 살짝 밀기).This allows for custom Table Row Actions to be attached to given rows in the table (such as swiping right to delete the row). 이 동작을 사용 하려면 NSTableViewDelegateRowActions 메서드를 재정의 합니다.To enable this behavior, override the RowActions method of the NSTableViewDelegate:

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace MacModern
{
    public class ContentsTableDelegate : NSTableViewDelegate
    {
        #region Constructors
        public ContentsTableDelegate ()
        {
        }
        #endregion

        #region Override Methods
        public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
        {
            // Build new view
            var view = new NSView ();
            ...

            // Return the view representing the item to display
            return view;
        }

        public override NSTableViewRowAction [] RowActions (NSTableView tableView, nint row, NSTableRowActionEdge edge)
        {
            // Take action based on the edge
            if (edge == NSTableRowActionEdge.Trailing) {
                // Create row actions
                var editAction = NSTableViewRowAction.FromStyle (NSTableViewRowActionStyle.Regular, "Edit", (action, rowNum) => {
                    // Handle row being edited
                    ...
                });

                var deleteAction = NSTableViewRowAction.FromStyle (NSTableViewRowActionStyle.Destructive, "Delete", (action, rowNum) => {
                    // Handle row being deleted
                    ...
                });

                // Return actions
                return new [] { editAction, deleteAction };
            } else {
                // No matching actions
                return null;
            }
        }
        #endregion
    }
}

정적 NSTableViewRowAction.FromStyle은 다음 스타일의 새 테이블 행 작업을 만드는 데 사용 됩니다.The static NSTableViewRowAction.FromStyle is used to create a new Table Row Action of the following styles:

  • Regular-행 내용 편집과 같은 표준 비 소거식 작업을 수행 합니다.Regular - Performs a standard non-destructive action such as edit the row's contents.
  • Destructive-테이블에서 행을 삭제 하는 등의 파괴적인 작업을 수행 합니다.Destructive - Performs a destructive action such as delete the row from the table. 이러한 작업은 빨간색 배경으로 렌더링 됩니다.These actions will be rendered with a red background.

스크롤 뷰 향상Scroll View Enhancements

스크롤 뷰 (NSScrollView)를 직접 사용 하거나 다른 컨트롤의 일부로 사용 하는 경우 (예: NSTableView), 최신 모양과 보기를 사용 하 여 Xamarin.ios 앱의 제목 및 도구 모음 영역에서 스크롤 뷰의 내용을 슬라이드에 표시할 수 있습니다.When using a Scroll View (NSScrollView) directly, or as part of another control (such as NSTableView), the contents of the Scroll View can slide under the Title and Tool Bar areas in a Xamarin.Mac app using a Modern Look and Views.

결과적으로, 스크롤 뷰 콘텐츠 영역의 첫 번째 항목은 제목 및 도구 모음 영역에 의해 부분적으로 가려져 있을 수 있습니다.As a result, the first item in the Scroll View content area can be partially obscured by the Title and Tool Bar area.

이 문제를 해결 하기 위해 Apple은 NSScrollView 클래스에 두 가지 새 속성을 추가 했습니다.To correct this issue, Apple has added two new properties to the NSScrollView class:

  • ContentInsets-개발자는 스크롤 뷰의 위쪽에 적용 될 오프셋을 정의 하는 NSEdgeInsets 개체를 제공할 수 있습니다.ContentInsets - Allows the developer to provide a NSEdgeInsets object defining the offset that will be applied to the top of the Scroll View.
  • AutomaticallyAdjustsContentInsets-true 스크롤 뷰에서 개발자에 대 한 ContentInsets 자동으로 처리 됩니다.AutomaticallyAdjustsContentInsets - If true the Scroll View will automatically handle the ContentInsets for the developer.

ContentInsets를 사용 하 여 개발자는 스크롤 뷰의 시작을 조정 하 여 다음과 같은 액세서리를 포함할 수 있습니다.By using the ContentInsets the developer can adjust the start of the Scroll View to allow for the inclusion of accessories such as:

  • 메일 응용 프로그램에 표시 되는 것과 같은 정렬 표시기입니다.A Sort indicator like the one shown in the Mail app.
  • 검색 필드입니다.A Search Field.
  • 새로 고침 또는 업데이트 단추입니다.A Refresh or Update button.

최신 앱에서 자동 레이아웃 및 지역화Auto Layout and Localization in Modern Apps

Apple은 개발자가 국제화 된 macOS 앱을 쉽게 만들 수 있도록 하는 Xcode의 여러 기술을 포함 하 고 있습니다.Apple has included several technologies in Xcode that allow the developer to easily create an internationalized macOS app. 이제 개발자는 Xcode를 사용 하 여 사용자가 제공 하는 텍스트를 해당 스토리 보드 파일에 있는 앱의 사용자 인터페이스 디자인과 분리 하 고 UI가 변경 되는 경우이 분리를 유지 하는 도구를 제공 합니다.Xcode now allows the developer to separate user-facing text from the app's User Interface design in its Storyboard files and provides tools to maintain this separation if the UI changes.

자세한 내용은 Apple의 국제화 및 지역화 가이드를 참조 하세요.For more information, please see Apple's Internationalization and Localization Guide.

기본 국제화 구현Implementing Base Internationalization

개발자는 기본 국제화를 구현 하 여 응용 프로그램의 UI를 나타내는 단일 스토리 보드 파일을 제공 하 고 모든 사용자 연결 문자열을 구분할 수 있습니다.By implementing Base Internationalization, the developer can provide a single Storyboard file to represent the app's UI and separate out all of the user-facing strings.

개발자가 앱의 사용자 인터페이스를 정의 하는 초기 Storyboard 파일 (또는 파일)을 만드는 경우 기본 국제화 (개발자가 말하는 언어)에서 빌드됩니다.When the developer is creating the initial Storyboard file (or files) that define the app's User Interface, they will be built in the Base Internationalization (the language that the developer speaks).

그런 다음 개발자는 여러 언어로 변환할 수 있는 지역화 및 기본 국제화 문자열 (스토리 보드 UI 디자인)을 내보낼 수 있습니다.Next, the developer can export localizations and the Base Internationalization strings (in the Storyboard UI design) that can be translated into multiple languages.

나중에 이러한 지역화를 가져올 수 있으며 Xcode는 스토리 보드에 대 한 언어별 문자열 파일을 생성 합니다.Later, these localizations can be imported and Xcode will generate the language-specific string files for the Storyboard.

지역화를 지원 하기 위한 자동 레이아웃 구현Implementing Auto Layout to Support Localization

지역화 된 버전의 문자열 값은 크기 및/또는 읽기 방향이 크게 다를 수 있으므로 개발자는 자동 레이아웃을 사용 하 여 응용 프로그램의 사용자 인터페이스를 스토리 보드 파일에 배치 하 고 크기를 조정 해야 합니다.Because localized versions of string values can have vastly different sizes and/or reading direction, the developer should use Auto Layout to position and size the app's User Interface in a Storyboard file.

Apple에서는 다음을 수행 하는 것이 좋습니다.Apple suggest doing the following:

  • 고정 폭 제약 조건 제거 -모든 텍스트 기반 보기는 내용에 따라 크기를 조정할 수 있어야 합니다.Remove Fixed Width Constraints - All text-based Views should be allowed to resize based on their content. 고정 폭 보기가 특정 언어로 콘텐츠를 자를 수 있습니다.Fixed width View may crop their content in specific languages.
  • 내장 콘텐츠 크기 사용 -기본적으로 텍스트 기반 보기는 내용에 맞게 자동으로 크기가 조정 됩니다.Use Intrinsic Content Sizes - By default text-based Views will auto-size to fit their content. 크기를 올바르게 조정 하지 않는 텍스트 기반 보기의 경우 Xcode의 Interface Builder에서 선택한 다음 내용에 맞게 > 크기 편집 을 선택 합니다.For text-based View that are not sizing correctly, select them in Xcode's Interface Builder then choose Edit > Size To Fit Content.
  • 선행 및 후행 특성 적용 -텍스트의 방향이 사용자의 언어에 따라 변경 될 수 있으므로 기존 RightLeft 특성과 달리 새 LeadingTrailing 제약 조건 특성을 사용 합니다.Apply Leading and Trailing Attributes - Because the direction of the text can change based on the user's language, use the new Leading and Trailing constraint attributes as opposed to the existing Right and Left attributes. LeadingTrailing는 언어 방향에 따라 자동으로 조정 됩니다.Leading and Trailing will automatically adjust based on the languages direction.
  • 인접 뷰에 뷰 고정 -선택한 언어에 대 한 응답으로 뷰를 변경 하 고 크기를 조정할 수 있습니다.Pin Views to Adjacent Views - This allows the Views to reposition and resize as the Views around them change in response to the language selected.
  • Windows 최소 및/또는 최대 크기를 설정 하지 마세요 . 선택한 언어가 콘텐츠 영역의 크기를 조정 하므로 windows에서 크기를 변경할 수 있습니다.Don't Set a Windows Minimum and/or Maximum Sizes - Allow Windows to change size as the language selected resizes their content areas.
  • 레이아웃 변경 내용을 지속적으로 테스트 -앱에서 개발 하는 동안 다른 언어로 지속적으로 테스트 해야 합니다.Test Layout Changes Constantly - During development at app should be tested constantly in different languages. 자세한 내용은 Apple의 국제화 앱 테스트 설명서를 참조 하세요.See Apple's Testing Your Internationalized app documentation for more details.
  • NSStackViews를 사용 하 여 뷰 를 - NSStackViews 함께 고정 하면 예측 가능한 방식으로 콘텐츠를 이동 하 고 확장할 수 있으며 선택한 언어에 따라 콘텐츠 크기를 변경할 수 있습니다.Use NSStackViews to Pin Views Together - NSStackViews allows their contents to shift and grow in predictable ways and the content change size based on the language selected.

Xcode의 Interface Builder에서 지역화Localizing in Xcode's Interface Builder

Apple은 지역화를 지원 하기 위해 응용 프로그램의 UI를 디자인 하거나 편집할 때 개발자가 사용할 수 있는 Xcode의 Interface Builder에 몇 가지 기능을 제공 합니다.Apple has provided several features in Xcode's Interface Builder that the developer can use when designing or editing an app's UI to support localization. 개발자는 특성 검사자텍스트 방향 섹션을 사용 하 여 텍스트 기반 보기 선택 (예: NSTextField)에서 방향을 사용 하 고 업데이트 하는 방법에 대 한 힌트를 제공할 수 있습니다.The Text Direction section of the Attribute Inspector allows the developer to provide hints on how direction should be used and updated on a select Text-Based View (such as NSTextField):

텍스트 방향에는 세 가지 값을 사용할 수 있습니다.There are three possible values for the Text Direction:

  • 자연 -레이아웃은 컨트롤에 할당 된 문자열을 기반으로 합니다.Natural - The layout is based on the string assigned to the control.
  • 왼쪽에서 오른쪽 으로 레이아웃은 항상 왼쪽에서 오른쪽으로 강제 적용 됩니다.Left to Right - The layout is always forced to left to right.
  • 오른쪽에서 왼쪽 -레이아웃은 항상 오른쪽에서 왼쪽으로 강제 적용 됩니다.Right to Left - The layout is always forced to right to left.

레이아웃에 사용할 수 있는 값에는 두 가지가 있습니다.There are two possible values for the Layout:

  • 왼쪽에서 오른쪽 으로 레이아웃은 항상 왼쪽에서 오른쪽입니다.Left to Right - The layout is always left to right.
  • 오른쪽에서 왼쪽 -레이아웃은 항상 오른쪽에서 왼쪽입니다.Right to Left - The layout is always right to left.

일반적으로 특정 맞춤이 필요 하지 않으면 이러한 항목을 변경 하면 안 됩니다.Typically these should not be changed unless a specific alignment is required.

미러 속성은 특정 컨트롤 속성 (예: 셀 이미지 위치)을 대칭 이동 하도록 시스템에 지시 합니다.The Mirror property tells the system to flip specific control properties (such as the Cell Image Position). 다음과 같은 세 가지 값을 사용할 수 있습니다.It has three possible values:

  • 자동 -선택한 언어의 방향에 따라 위치가 자동으로 변경 됩니다.Automatically - The position will automatically change based on the direction of the language selected.
  • 오른쪽에서 왼쪽으로의 인터페이스 -위치는 오른쪽에서 왼쪽으로만 변경 됩니다.In Right To Left Interface - The position will only be changed in right to left based languages.
  • Never -위치가 변경 되지 않습니다.Never - The position will never change.

개발자가 텍스트 기반 뷰의 내용에 대해 가운데맞춤, 양쪽 맞춤 또는 전체 맞춤을 지정한 경우 선택한 언어에 따라 대칭 이동 되지 않습니다.If the developer has specified Center, Justify or Full alignment on the content of a text-based View, these will never be flipped based on language selected.

MacOS Sierra 이전에는 코드에서 만든 컨트롤이 자동으로 미러링 되지 않습니다.Prior to macOS Sierra, controls created in code would not be mirrored automatically. 개발자는 다음과 같은 코드를 사용 하 여 미러링을 처리 해야 했습니다.The developer had to use code like the following to handle mirroring:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Setting a button's mirroring based on the layout direction
    var button = new NSButton ();
    if (button.UserInterfaceLayoutDirection == NSUserInterfaceLayoutDirection.LeftToRight) {
        button.Alignment = NSTextAlignment.Right;
        button.ImagePosition = NSCellImagePosition.ImageLeft;
    } else {
        button.Alignment = NSTextAlignment.Left;
        button.ImagePosition = NSCellImagePosition.ImageRight;
    }
}

AlignmentImagePosition이 컨트롤의 UserInterfaceLayoutDirection에 따라 설정 됩니다.Where the Alignment and ImagePosition are being set based on the UserInterfaceLayoutDirection of the control.

macOS Sierra는 여러 가지 매개 변수 (예: 제목, 이미지 및 작업)를 사용 하는 몇 가지 새로운 편의 CreateButton 생성자를 추가 하 고 올바르게 자동으로 미러링됩니다.macOS Sierra adds several new convenience constructors (via the static CreateButton method) that take several parameters (such as Title, Image and Action) and will automatically mirror correctly. 예를 들면,For example:

var button2 = NSButton.CreateButton (myTitle, myImage, () => {
    // Take action when the button is pressed
    ...
});

시스템 모양 사용Using System Appearances

최신 macOS 앱은 이미지 생성, 편집 또는 프레젠테이션 앱에서 잘 작동 하는 새로운 짙은 인터페이스 모양을 채택할 수 있습니다.Modern macOS apps can adopt a new Dark Interface Appearance that works well for image creation, editing or presentation apps:

이 작업은 창이 표시 되기 전에 코드 줄 하나를 추가 하 여 수행할 수 있습니다.This can be done by adding one line of code before the Window is presented. 예를 들면,For example:

using System;
using AppKit;
using Foundation;

namespace MacModern
{
    public partial class ViewController : NSViewController
    {
        ...
    
        #region Override Methods
        public override void ViewWillAppear ()
        {
            base.ViewWillAppear ();

            // Apply the Dark Interface Appearance
            View.Window.Appearance = NSAppearance.GetAppearance (NSAppearance.NameVibrantDark);

            ...
        }
        #endregion
    }
}

NSAppearance 클래스의 정적 GetAppearance 메서드는 시스템에서 명명 된 모양 (이 경우 NSAppearance.NameVibrantDark)을 가져오는 데 사용 됩니다.The static GetAppearance method of the NSAppearance class is used to get a named appearance from the system (in this case NSAppearance.NameVibrantDark).

Apple에는 시스템 모양새 사용에 대 한 다음과 같은 제안이 있습니다.Apple has the following suggestions for using System Appearances:

  • 하드 코드 된 값 (예: LabelColorSelectedControlColor)에 대해 명명 된 색을 선호 합니다.Prefer named colors over hardcoded values (such as LabelColor and SelectedControlColor).
  • 가능 하면 시스템 표준 컨트롤 스타일을 사용 합니다.Use system standard control style where possible.

시스템 모양새를 사용 하는 macOS 앱은 시스템 기본 설정 앱에서 내게 필요한 옵션 기능을 사용 하도록 설정한 사용자에 대해 자동으로 제대로 작동 합니다.A macOS app that uses the System Appearances will automatically work correctly for users that have enabled Accessibility features from the System Preferences app. 따라서 Apple은 개발자가 macOS 앱에서 항상 시스템 모양새를 사용 하도록 제안 합니다.As a result, Apple suggests that the developer should always use System Appearances in their macOS apps.

스토리 보드를 사용 하 여 Ui 디자인Designing UIs with Storyboards

개발자는 스토리 보드를 사용 하 여 응용 프로그램의 사용자 인터페이스를 구성 하는 개별 요소를 디자인할 뿐만 아니라 UI 흐름과 지정 된 요소의 계층 구조를 시각화 하 고 디자인할 수 있습니다.Storyboards allow the developer to not only design the individual elements that make up an app's User Interface, but to visualize and design the UI flow and the hierarchy of the given elements.

개발자는 컨트롤러를 사용 하 여 요소를 컴퍼지션 및 Segue abstract 단위로 수집 하 고, 뷰 계층 구조 전체에서 이동 하는 데 필요한 일반적인 "글 루 코드"를 제거할 수 있습니다.Controllers allow the developer to collect elements into a unit of composition and Segues abstract and remove the typical "glue code" required to move throughout the View Hierarchy:

자세한 내용은 Storyboard 소개 설명서를 참조 하세요.For more information, please see our Introduction to Storyboards documentation.

스토리 보드에 정의 된 지정 된 장면이 뷰 계층 구조에 있는 이전 장면의 데이터를 요구 하는 경우가 많습니다.There are many instances where a given scene defined in a storyboard will require data from a previous scene in the View Hierarchy. Apple에는 장면 간에 정보를 전달 하기 위한 다음과 같은 제안이 있습니다.Apple has the following suggestions for passing information between scenes:

  • 데이터 dependancies은 항상 계층 구조를 통해 하위 중첩 되어야 합니다.Data dependancies should always cascade downwards through the hierarchy.
  • Ui 구조적 dependancies을 사용 하지 마십시오 .이는 UI 유연성이 제한 되기 때문입니다.Avoid hardcoding UI structural dependancies, as this limits UI flexibility.
  • 인터페이스 C# 를 사용 하 여 제네릭 데이터 dependancies을 제공 합니다.Use C# Interfaces to provide generic data dependancies.

Segue의 소스로 작동 하는 뷰 컨트롤러는 Segue를 실행 하 여 대상 뷰 컨트롤러를 표시 하기 전에 PrepareForSegue 메서드를 재정의 하 고 데이터 전달과 같은 모든 초기화 작업을 수행할 수 있습니다.The View Controller that is acting as the source of the Segue, can override the PrepareForSegue method and do any initialization required (such as passing data) before the Segue is executed to display the target View Controller. 예를 들면,For example:

public override void PrepareForSegue (NSStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    // Take action based on Segue ID
    switch (segue.Identifier) {
    case "MyNamedSegue":
        // Prepare for the segue to happen
        ...
        break;
    }
}

자세한 내용은 segue 설명서를 참조 하세요.For more information, please see our Segues documentation.

작업 전파Propagating Actions

MacOS 앱의 디자인에 따라 ui 컨트롤에 대 한 작업에 대 한 최상의 처리기가 UI 계층 구조의 다른 위치에 있을 수 있습니다.Based on the design of the macOS app, there might be times when the best handler for an Action on a UI control might be in elsewhere in the UI Hierarchy. 이는 일반적으로 자신의 장면에 상주 하는 메뉴 및 메뉴 항목에 적용 되며, 나머지 앱 UI와는 별개입니다.This is typically true of Menus and Menu Items that live in their own scene, separate from the rest of the app's UI.

이러한 상황을 처리 하기 위해 개발자는 사용자 지정 작업을 만들고 해당 작업을 응답자 체인에 전달할 수 있습니다.To handle this situation, the developer can create a Custom Action and pass the Action up the responder chain. 자세한 내용은 사용자 지정 창 작업 작업 설명서를 참조 하세요.For more information please see our Working with Custom Window Actions documentation.

최신 Mac 기능Modern Mac Features

Apple은 개발자가 다음과 같은 대부분의 Mac 플랫폼을 만들 수 있도록 하는 macOS Sierra에 몇 가지 사용자 측 기능을 포함 하 고 있습니다.Apple has included several user-facing features in macOS Sierra that allow the developer to make the most of the Mac platform, such as:

  • NSUserActivity -앱에서 사용자가 현재 관련 된 작업을 설명할 수 있습니다.NSUserActivity - This allows the app to describe the activity that the user is currently involved in. 처음에는 사용자의 장치 중 하나에서 시작 된 활동을 선택 하 고 다른 장치에서 계속 진행할 수 있는 전달 기능을 지원 하기 위해 처음에 NSUserActivity을 만들었습니다.NSUserActivity was initially created to support HandOff, where an activity started on one of the user's devices could be picked up and continued on another device. iOS에서와 마찬가지로 macOS 에서도 NSUserActivity 작동 합니다. 자세한 내용은 microsoft의 핸드 오프 기능 소개 문서를 참조 하세요.NSUserActivity works the same in macOS as it does in iOS so please see our Introduction to Handoff iOS documentation for more details.
  • Mac의 siri -Siri는 현재 활동 (NSUserActivity)을 사용 하 여 사용자가 발급할 수 있는 명령에 대 한 컨텍스트를 제공 합니다.Siri on Mac - Siri uses the Current Activity (NSUserActivity) to provide context to the commands a user can issue.
  • 상태 복원 -사용자가 macos에서 앱을 종료 한 다음 나중에 relaunches 앱이 이전 상태로 자동으로 돌아갑니다.State Restoration - When the user quits an app on macOS and then later relaunches it, the app will automatically be returned to its previous state. 개발자는 사용자 인터페이스가 사용자에 게 표시 되기 전에 상태 복원 API를 사용 하 여 임시 UI 상태를 인코딩 및 복원할 수 있습니다.The developer can use the State Restoration API to encode and restore transient UI states before the User Interface is displayed to the user. 앱이 NSDocument 기반 인 경우 상태 복원이 자동으로 처리 됩니다.If the app is NSDocument based, State Restoration is handled automatically. NSDocument 기반이 아닌 앱에 대해 상태 복원을 사용 하도록 설정 하려면 NSWindow 클래스의 Restorabletrue로 설정 합니다.To enable State Restoration for non-NSDocument based apps, set the Restorable of the NSWindow class to true.
  • 클라우드의 문서 -macOS Sierra 하기 전에 앱은 사용자의 iCloud 드라이브에서 문서를 사용 하도록 명시적으로 옵트인 (opt in) 해야 했습니다.Documents in the Cloud - Prior to macOS Sierra, an app had to explicitly opt-in to working with documents in the user's iCloud Drive. MacOS Sierra 사용자의 데스크톱문서 폴더가 시스템에 의해 자동으로 iCloud 드라이브와 동기화 될 수 있습니다.In macOS Sierra the user's Desktop and Documents folders may be synced with their iCloud Drive automatically by the system. 따라서 문서의 로컬 복사본을 삭제 하 여 사용자 컴퓨터의 공간을 확보할 수 있습니다.As a result, local copies of documents may be deleted to free up space on the user's machine. NSDocument 기반 앱은이 변경 내용을 자동으로 처리 합니다.NSDocument based apps will automatically handle this change. 다른 모든 앱 형식은 NSFileCoordinator를 사용 하 여 문서 읽기 및 쓰기를 동기화 해야 합니다.All other app types will need to use a NSFileCoordinator to sync reading and writing of documents.

요약Summary

이 문서에서는 개발자가 Xamarin.ios에서 최신 macOS 앱을 빌드하는 데 사용할 수 있는 몇 가지 팁, 기능 및 기술에 대해 설명 했습니다.This article has covered several tips, features and techniques a developer can use to build a modern macOS app in Xamarin.Mac.