Создание современных приложений macOS
В этой статье рассматриваются несколько советов, функций и методов, которые разработчик может использовать для создания современного приложения macOS в Xamarin.Mac.
Создание современных взглядов с помощью современных представлений
Современный внешний вид будет включать современный внешний вид окна и панели инструментов, например пример приложения, показанного ниже:
Включение представлений содержимого полного размера
Чтобы добиться этого в приложении Xamarin.Mac, разработчику потребуется использовать представление содержимого полного размера, что означает, что содержимое распространяется в области панели инструментов и заголовков и автоматически размыто macOS.
Чтобы включить эту функцию в коде, создайте пользовательский класс и NSWindowController
сделайте его следующим образом:
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, выбрав окно и проверив представление содержимого полного размера:
При использовании представления содержимого полного размера разработчик может потребовать смещения содержимого под заголовком и областями панели инструментов, чтобы определенное содержимое (например, метки) не скользит под ними.
Чтобы усложнить эту проблему, области заголовка и панели инструментов могут иметь динамическую высоту на основе действия, которое пользователь в настоящее время выполняет, версия macOS, установленная пользователем и (или) оборудование Mac, на котором работает приложение.
В результате просто жесткое кодирование смещения при создании пользовательского интерфейса не будет работать. Разработчику потребуется использовать динамический подход.
Apple включила свойство Key-Value Observable ContentLayoutRect
класса, чтобы получить текущую область содержимого NSWindow
в коде. Разработчик может использовать это значение для ручного размещения необходимых элементов при изменении области содержимого.
Лучше всего использовать классы автоматического макета и размера для размещения элементов пользовательского интерфейса в коде или построителе интерфейсов.
Код, как и в следующем примере, можно использовать для размещения элементов пользовательского интерфейса с помощью классов AutoLayout и Size в контроллере представления приложения:
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
), чтобы убедиться, что он не скольжения в области заголовка и панели инструментов:
public NSLayoutConstraint topConstraint { get; set; }
Переопределив метод контроллера UpdateViewConstraints
представления, разработчик может проверить, уже создано ли необходимое ограничение и при необходимости создайте его.
Если необходимо создать новое ограничение, ContentLayoutGuide
свойство окна, к которому необходимо получить доступ и приведение к элементу NSLayoutGuide
управления:
var contentLayoutGuide = ItemTitle.Window?.ContentLayoutGuide as NSLayoutGuide;
Свойство TopAnchor NSLayoutGuide
для доступа и если оно доступно, оно используется для создания нового ограничения с требуемой суммой смещения, и новое ограничение активируется для его применения:
// Assemble constraint and activate it
topConstraint = topAnchor.ConstraintEqualToAnchor (topAnchor, 20);
topConstraint.Active = true;
Включение оптимизированных панелей инструментов
Обычное окно macOS включает стандартную строку заголовка при выполнении вдоль верхней границы окна. Если окно также включает панель инструментов, она будет отображаться в этой области заголовка:
При использовании упрощенной панели инструментов область заголовка исчезает, а панель инструментов перемещается в положение заголовка, в строке с кнопками "Закрыть окно", "Свернуть" и "Развернуть":
Оптимизированная панель инструментов включена, переопределяя ViewWillAppear
метод и NSViewController
делая его похожим следующим образом:
public override void ViewWillAppear ()
{
base.ViewWillAppear ();
// Enable streamlined Toolbars
View.Window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
Этот эффект обычно используется для приложений Shoebox (одно окно), таких как карты, календарь, заметки и системные настройки.
Использование контроллеров представления аксессуаров
В зависимости от дизайна приложения разработчик может также дополнить область заголовка панелью заголовков с контроллером представления аксессуара, который отображается прямо под областью заголовка или панели инструментов, чтобы предоставить пользователю контекстные элементы управления на основе действия, в который они в настоящее время участвуют:
Контроллер доступа будет автоматически размыт и изменен системой без вмешательства разработчика.
Чтобы добавить контроллер представления аксессуаров, сделайте следующее:
В обозревателе решений дважды щелкните файл
Main.storyboard
, чтобы открыть его для редактирования.Перетащите контроллер пользовательского представления в иерархию окна:
Макет пользовательского интерфейса представления аксессуара:
Предоставление представления аксессуара в качестве выхода и любых других действий или точек для пользовательского интерфейса:
Сохраните изменения.
Вернитесь к Visual Studio для Mac для синхронизации изменений.
Измените NSWindowController
и сделайте его следующим образом:
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
}
}
Ключевые точки этого кода определяются в представлении пользовательского представления, определенного в построителе интерфейсов и предоставляемом в качестве выхода:
accessoryView.View = AccessoryViewGoBar;
И определяет LayoutAttribute
, где будет отображаться аксессуар:
accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;
Так как macOS теперь полностью локализован, Left
свойства устарели и NSLayoutAttribute
Right
должны быть заменены на Leading
и Trailing
.
Использование вкладки Windows
Кроме того, система macOS может добавлять контроллеры представления аксессуаров в окно приложения. Например, чтобы создать вкладки Windows, где несколько windows приложения объединяются в одно виртуальное окно:
Как правило, разработчику потребуется предпринять ограниченные действия с помощью табуляции Windows в приложениях Xamarin.Mac, система будет обрабатывать их автоматически следующим образом:
- Windows автоматически будет добавлена на вкладку при вызове
OrderFront
метода. - Windows автоматически будет отключен при вызове
OrderOut
метода. - В коде все окна табуляции по-прежнему считаются "видимыми", однако все внешние вкладки скрыты системой с помощью CoreGraphics.
TabbingIdentifier
Используйте свойство для группировкиNSWindow
Windows на вкладки.- Если это
NSDocument
приложение на основе, некоторые из этих функций будут включены автоматически (например, кнопка "плюс", добавляемая на панель вкладок) без каких-либо действий разработчика. NSDocument
Не зависящие от приложений могут включить кнопку "плюс" в группе вкладок, чтобы добавить новый документ, переопределивGetNewWindowForTab
метод объектаNSWindowsController
.
Объединение всех частей приложения, AppDelegate
которое хотело использовать системные вкладки Windows, может выглядеть следующим образом:
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
метод создает новый документ и отображает его.
Затем NSWindowController
может выглядеть следующим образом:
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
. Метод SetDefaultDocumentTitle
задает новое название документов на основе количества созданных новых документов.
Следующий код сообщает macOS, что приложение предпочитает использовать вкладки и предоставляет строку, которая позволяет приложению группироваться на вкладки:
// Prefer Tabbed Windows
Window.TabbingMode = NSWindowTabbingMode.Preferred;
Window.TabbingIdentifier = "Main";
И следующий метод переопределения добавляет кнопку "плюс" на панель вкладок, которая создаст новый документ при нажатии пользователем:
public override void GetNewWindowForTab (NSObject sender)
{
// Ask app to open a new document window
App.NewDocument (this);
}
Использование основной анимации
Базовая анимация — это высокопроизводительный модуль отрисовки графики, встроенный в macOS. Базовая анимация оптимизирована для использования gpu (единица обработки графики), доступной в современном оборудовании macOS, а не для выполнения графических операций на ЦП, что может замедлить работу компьютера.
С CALayer
помощью основной анимации можно использовать такие задачи, как быстрая и динамная прокрутка и анимация. Пользовательский интерфейс приложения должен состоять из нескольких вложенных представлений и слоев, чтобы полностью воспользоваться преимуществами основной анимации.
Объект CALayer
предоставляет несколько свойств, позволяющих разработчику управлять тем, что отображается на экране пользователю, например:
Content
— может быть илиNSImage
CGImage
предоставляет содержимое слоя.BackgroundColor
— задает цвет фона слоя в видеCGColor
BorderWidth
— задает ширину границы.BorderColor
— задает цвет границы.
Чтобы использовать базовую графику в пользовательском интерфейсе приложения, она должна использовать представления с поддержкой слоев , которые Apple предлагает разработчику всегда включить в представлении содержимого окна. Таким образом, все дочерние представления автоматически наследуют резервное копирование слоев.
Кроме того, Apple предлагает использовать представления с поддержкой слоев вместо добавления нового CALayer
в подложку, так как система будет автоматически обрабатывать несколько необходимых параметров (например, необходимых для дисплея Сетчатки).
Резервное копирование слоев можно включить, задав WantsLayer
true
NSView
для конструктора интерфейсов Xcode или внутри конструктора интерфейсов Xcode в инспекторе эффектов представления, проверив основной уровень анимации:
Перерисовка представлений с помощью слоев
Еще одним важным шагом при использовании представлений с поддержкой слоев в приложении Xamarin.Mac является установка LayerContentsRedrawPolicy
NSView
значения OnSetNeedsDisplay
в элементе NSViewController
. Например:
public override void ViewWillAppear ()
{
base.ViewWillAppear ();
// Set the content redraw policy
View.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
Если разработчик не задает это свойство, представление будет перезавернуто всякий раз, когда изменяется источник кадра, что не нужно по соображениям производительности. Однако при использовании этого свойства OnSetNeedsDisplay
разработчику придется вручную задать NeedsDisplay
для true
принудительного перерисовки содержимого.
Если представление помечается как грязное, система проверяет WantsUpdateLayer
свойство View. Если метод возвращается true
, UpdateLayer
метод вызывается, а другой DrawRect
метод представления вызывается для обновления содержимого представления.
Apple предлагает следующие предложения по обновлению содержимого представления при необходимости:
- Apple предпочитает использовать
UpdateLater
поDrawRect
мере возможности, так как она обеспечивает значительный рост производительности. - Используйте то же самое
layer.Contents
для элементов пользовательского интерфейса, которые выглядят аналогично. - Apple также предпочитает разработчику создавать свой пользовательский интерфейс с помощью стандартных представлений, таких как
NSTextField
, когда это возможно.
Чтобы использовать UpdateLayer
, создайте пользовательский класс для NSView
кода и сделайте код следующим образом:
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
}
}
Использование современного перетаскивания
Чтобы представить современный интерфейс перетаскивания для пользователя, разработчик должен применить перетаскивание в операциях перетаскивания приложения. Перетащите Flocking — это место, в котором каждый отдельный файл или элемент, перетаскиваемый изначально, отображается как отдельный элемент, который стекает (группирует вместе под курсором число элементов), так как пользователь продолжает операцию перетаскивания.
Если пользователь завершает операцию перетаскивания, отдельные элементы разблокируются и возвращаются в исходные расположения.
В следующем примере кода включена блокировка перетаскивания в пользовательском представлении:
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
}
}
Эффект стека был достигнут путем отправки каждого элемента, перетаскиваемого в BeginDraggingSession
метод NSView
отдельного элемента в массиве.
При работе с классом NSTableView
или NSOutlineView
используйте PastboardWriterForRow
метод NSTableViewDataSource
класса, чтобы запустить операцию перетаскивания:
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
}
}
Это позволяет разработчику предоставлять отдельный NSDraggingItem
элемент в таблице, который перетаскивается, а не старый метод WriteRowsWith
, который записывает все строки как одну группу в вставку.
При работе NSCollectionViews
с ним снова используйте PasteboardWriterForItemAt
метод, а не WriteItemsAt
метод при начале перетаскивания.
Разработчик всегда должен избегать размещения больших файлов на вставке. Новые для macOS Sierra, File Promises позволяют разработчику размещать ссылки на заданные файлы на вставке, которые позже будут выполнены, когда пользователь завершит операцию drop с помощью новых NSFilePromiseProvider
и NSFilePromiseReceiver
классов.
Использование современного отслеживания событий
Для элемента пользовательского интерфейса (например NSButton
, который был добавлен в область заголовка или панели инструментов), пользователь должен иметь возможность щелкнуть элемент и запустить событие как обычное (например, отображение всплывающего окна). Однако, так как элемент также находится в области заголовка или панели инструментов, пользователь должен иметь возможность щелкнуть и перетащить элемент для перемещения окна.
Чтобы выполнить это в коде, создайте пользовательский класс для элемента (например NSButton
) и переопределите MouseDown
событие следующим образом:
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);
}
}
Этот код использует TrackEventsMatching
метод присоединенного элемента пользовательского NSWindow
интерфейса для перехвата LeftMouseUp
событий и LeftMouseDragged
событий. Для события элемент пользовательского LeftMouseUp
интерфейса отвечает как обычно. LeftMouseDragged
Для события событие передается методу NSWindow
PerformWindowDrag
метода перемещения окна на экране.
PerformWindowDrag
Вызов метода NSWindow
класса обеспечивает следующие преимущества:
- Он позволяет перемещать окно, даже если приложение зависается (например, при обработке глубокого цикла).
- Переключение пространства будет работать должным образом.
- Панель пробелов будет отображаться как обычная.
- Привязка окна и выравнивание работают нормально.
Использование современных элементов управления представления контейнеров
macOS Sierra предоставляет множество современных улучшений существующих элементов управления представлением контейнеров, доступных в предыдущей версии ОС.
Улучшения представления таблиц
Разработчик всегда должен использовать новую NSView
версию элементов управления представлением контейнеров, NSTableView
например . Например:
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
}
}
Это позволяет подключить пользовательские действия строк таблицы к заданным строкам в таблице (например, прокрутить право на удаление строки). Чтобы включить это поведение, переопределите RowActions
метод 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
Статический используется для создания нового действия строки таблицы следующих стилей:
Regular
— выполняет стандартное неразрушительное действие, например изменение содержимого строки.Destructive
— выполняет деструктивное действие, например удаление строки из таблицы. Эти действия будут отображаться красным фоном.
Усовершенствования представления прокрутки
При использовании представления прокрутки () напрямую или в составе другого элемента управления (напримерNSTableView
, содержимое представленияNSScrollView
прокрутки может скользить в области заголовка и панели инструментов в приложении Xamarin.Mac с помощью современного внешнего вида и представлений).
В результате первый элемент в области содержимого представления прокрутки может быть частично скрыт областью заголовка и панели инструментов.
Чтобы устранить эту проблему, Apple добавила в класс два новых свойства NSScrollView
:
ContentInsets
— Позволяет разработчику предоставить объект, определяющийNSEdgeInsets
смещение, которое будет применено к верхней части представления прокрутки.AutomaticallyAdjustsContentInsets
— Еслиtrue
представление прокрутки будет автоматически обрабатыватьсяContentInsets
для разработчика.
С помощью ContentInsets
разработчика можно настроить начало представления прокрутки, чтобы разрешить включение таких аксессуаров, как:
- Индикатор сортировки, как в приложении "Почта".
- Поле поиска.
- Кнопка "Обновить" или "Обновить".
Автоматическое макет и локализация в современных приложениях
Apple включила несколько технологий в Xcode, которые позволяют разработчику легко создавать международное приложение macOS. Теперь Xcode позволяет разработчику отделять текст, доступный для пользователя, от дизайна пользовательского интерфейса приложения в файлах раскадровки и предоставляет средства для поддержания этого разделения при изменении пользовательского интерфейса.
Дополнительные сведения см. в руководстве по интернационализации и локализации Apple.
Реализация базовой интернационализации
Реализуя базовую интернационализацию, разработчик может предоставить один раскадровочный файл, чтобы представить пользовательский интерфейс приложения и разделить все строки, доступные для пользователя.
Когда разработчик создает исходный раскадровки (или файлы), определяющий пользовательский интерфейс приложения, он будет создан в базовой интернационализации (язык, на котором говорит разработчик).
Затем разработчик может экспортировать локализации и строки базовой интернационализации (в конструкторе пользовательского интерфейса раскадровки), которые можно перевести на несколько языков.
Позже эти локализации можно импортировать, и Xcode создаст файлы строк для раскадровки для конкретного языка.
Реализация автоматического макета для поддержки локализации
Так как локализованные версии строковых значений могут иметь значительно разные размеры и /или направление чтения, разработчик должен использовать авто макет для размещения и размера пользовательского интерфейса приложения в раскадровки-файле.
Apple предлагает сделать следующее:
- Удалить ограничения фиксированной ширины. Все текстовые представления должны быть разрешены для изменения размера на основе их содержимого. Представление фиксированной ширины может обрезать содержимое на определенных языках.
- Используйте встроенные размеры контента. По умолчанию текстовые представления автоматически будут размерировать их содержимое. В текстовом представлении, которое неправильно изменяет размер, выберите их в построителе интерфейсов Xcode, а затем выберите "Изменить>размер в соответствии с содержимым".
- Применение начальных и конечных атрибутов . Так как направление текста может меняться на основе языка пользователя, используйте новые
Leading
иTrailing
ограничивающие атрибуты, а не существующиеRight
иLeft
атрибуты.Leading
иTrailing
будет автоматически настраиваться на основе направления языков. - Закрепление представлений к смежным представлениям . Это позволяет представлениям изменять положение и изменять размер в виде представлений вокруг них в ответ на выбранный язык.
- Не устанавливайте минимальный и /или максимальный размер Windows. Разрешить Windows изменять размер, так как выбранный язык изменяет размер областей содержимого.
- Изменения макета теста постоянно изменяются. Во время разработки в приложении следует постоянно тестировать на разных языках. Дополнительные сведения см. в документации по тестированию приложений Apple internationalized .
- Использование NSStackViews для объединения представлений -
NSStackViews
позволяет их содержимому перемещаться и увеличиваться прогнозируемыми способами и размером изменения содержимого на основе выбранного языка.
Локализация в построителе интерфейсов Xcode
Apple предоставила несколько функций в конструкторе интерфейсов Xcode, которые разработчик может использовать при проектировании или редактировании пользовательского интерфейса приложения для поддержки локализации. Раздел "Направление текста" инспектора атрибутов позволяет разработчику предоставлять указания о том, как следует использовать направление и обновляться в представлении на основе текста (напримерNSTextField
: ):
Для направления текста можно использовать три возможных значения:
- Natural — макет основан на строке, назначенной элементу управления.
- Слева направо — макет всегда вынужден слева направо.
- Справа налево — макет всегда вынужден справа налево .
Для макета можно использовать два возможных значения:
- Слева направо — макет всегда слева направо.
- Справа налево — макет всегда справа налево .
Как правило, их не следует изменять, если не требуется определенное выравнивание.
Свойство Mirror сообщает системе перевернуть определенные свойства элемента управления (например, положение изображения ячейки). У него есть три возможных значения:
- Автоматически — позиция будет автоматически меняться в зависимости от направления выбранного языка.
- В интерфейсе справа налево — позиция будет изменена только вправо на языки налево.
- Никогда - позиция никогда не изменится.
Если разработчик указал Центр, оправдание или полное выравнивание содержимого текстового представления, они никогда не будут перевернуты на основе выбранного языка.
До macOS Sierra элементы управления, созданные в коде, не будут автоматически зеркально отображаться. Разработчик должен был использовать следующий код для обработки зеркального отображения:
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;
}
}
Alignment
Где устанавливается и ImagePosition
устанавливается на UserInterfaceLayoutDirection
основе элемента управления.
macOS Sierra добавляет несколько новых удобных конструкторов (через статический CreateButton
метод), которые принимают несколько параметров (например, Title, Image и Action) и автоматически зеркально отражаются. Например:
var button2 = NSButton.CreateButton (myTitle, myImage, () => {
// Take action when the button is pressed
...
});
Использование системных внешних типов
Современные приложения macOS могут использовать новый внешний вид темного интерфейса, который хорошо подходит для создания изображений, редактирования или презентации приложений:
Это можно сделать, добавив одну строку кода перед представлением окна. Например:
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
}
}
Статический GetAppearance
метод NSAppearance
класса используется для получения именованного внешнего вида из системы (в данном случае NSAppearance.NameVibrantDark
).
Apple предлагает следующие варианты использования системных внешних элементов:
- Предпочитайте именованные цвета для жестко закодированных значений (например
LabelColor
, иSelectedControlColor
). - По возможности используйте стандартный стиль управления системой.
Приложение macOS, использующее системные внешние виды, автоматически работает для пользователей, которые включили специальные возможности из приложения "Системные настройки". В результате Apple предлагает разработчику всегда использовать системные внешние возможности в своих приложениях macOS.
Проектирование пользовательских интерфейсов с помощью раскадровки
Раскадровки позволяют разработчику создавать не только отдельные элементы, составляющие пользовательский интерфейс приложения, но и визуализировать поток пользовательского интерфейса и иерархию заданных элементов.
Контроллеры позволяют разработчику собирать элементы в единицу композиции и абстрактных segues и удалять типичный "клей код", необходимый для перемещения по иерархии представлений:
Дополнительные сведения см. в документации по раскадровкам.
Существует множество случаев, когда определенная сцена, определенная в раскадровке, потребует данных из предыдущей сцены в иерархии представлений. Apple предлагает следующие предложения для передачи информации между сценами:
- Зависимости данных всегда должны каскадироваться вниз по иерархии.
- Избегайте жестких зависимостей пользовательского интерфейса, так как это ограничивает гибкость пользовательского интерфейса.
- Используйте интерфейсы C# для предоставления универсальных зависимостей данных.
Контроллер представления, который выступает в качестве источника segue, может переопределить PrepareForSegue
метод и выполнить все необходимые инициализации (например, передачи данных) перед выполнением segue для отображения целевого контроллера представления. Например:
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;
}
}
Дополнительные сведения см. в документации по Segues .
Распространение действий
На основе дизайна приложения macOS может возникнуть время, когда лучший обработчик действия элемента управления пользовательского интерфейса может находиться в другом месте иерархии пользовательского интерфейса. Обычно это верно для элементов меню и меню, которые живут в собственной сцене, отдельно от остального пользовательского интерфейса приложения.
Чтобы справиться с этой ситуацией, разработчик может создать настраиваемое действие и передать действие в цепочку отклика. Дополнительные сведения см . в документации по работе с пользовательскими действиями окна.
Современные функции Mac
Apple включила в macOS Sierra несколько пользовательских функций, которые позволяют разработчику использовать большую часть платформы Mac, например:
- NSUserActivity — это позволяет приложению описать действие, к которому в настоящее время участвует пользователь.
NSUserActivity
изначально был создан для поддержки HandOff, где действие, запущенное на одном из устройств пользователя, может быть выбрано и продолжено на другом устройстве.NSUserActivity
работает так же в macOS, как и в iOS, поэтому дополнительные сведения см. в нашей документации по handoff iOS. - Siri в Mac — Siri использует текущее действие (
NSUserActivity
) для предоставления контекста командам, которые пользователь может выдавать. - Восстановление состояния. Когда пользователь выходит из приложения в macOS, а затем повторно запускает его, приложение автоматически будет возвращено в предыдущее состояние. Разработчик может использовать API восстановления состояния для кодирования и восстановления временных состояний пользовательского интерфейса перед отображением пользовательского интерфейса пользователю. Если приложение
NSDocument
основано, восстановление состояния обрабатывается автоматически. Чтобы включить восстановление состояния для приложений, неNSDocument
основанных на основе, задайтеRestorable
NSWindow
для классаtrue
значение . - Документы в облаке — до macOS Sierra приложение пришлось явно согласиться на работу с документами в iCloud Drive пользователя. В macOS Sierra папки рабочего стола и документов пользователя могут быть синхронизированы с iCloud Drive автоматически системой. В результате локальные копии документов могут быть удалены, чтобы освободить место на компьютере пользователя.
NSDocument
приложения на основе автоматически обрабатывают это изменение. Все остальные типы приложений должны использоватьNSFileCoordinator
для синхронизации чтения и записи документов.
Итоги
В этой статье рассматриваются несколько советов, функций и методов, которые разработчик может использовать для создания современного приложения macOS в Xamarin.Mac.