TextKit в Xamarin.iOSTextKit in Xamarin.iOS

TextKit — это новый API, который предлагает мощные текст функции макета и подготовки к просмотру.TextKit is a new API that offers powerful text layout and rendering features. Она построена на основе низкоуровневых framework основного текста, но гораздо проще в использовании, чем основного текста.It is built on top of the low-level Core Text framework, but is much easier to use than Core Text.

Чтобы сделать возможности TextKit доступным для стандартных элементов управления, несколько текстовых элементов управления iOS были заново реализованы для использования TextKit, включая:To make the features of TextKit available to standard controls, several iOS text controls have been re-implemented to use TextKit, including:

  • UITextViewUITextView
  • UITextFieldUITextField
  • UILabelUILabel

АрхитектураArchitecture

TextKit предоставляет многоуровневую архитектуру, которая отделяет хранилища текста из макета и отображения, включая следующие классы:TextKit provides a layered architecture that separates the text storage from the layout and display, including the following classes:

  • NSTextContainer — Предоставляет систему координат и geometry, который используется для макета текста.NSTextContainer – Provides the coordinate system and geometry that is used to layout text.
  • NSLayoutManager — Размещает текст, превратив текст в глифы.NSLayoutManager – Lays out text by turning text into glyphs.
  • NSTextStorage — Содержит текстовые данные, а также обрабатывает пакетные обновления свойств текста.NSTextStorage – Holds the text data, as well as handles batch text property updates. Любые пакетные обновления их обработкой и отправкой диспетчера макетов для фактической обработки изменения, такие как повторное вычисление макета и перерисовки текста.Any batch updates are handed to the layout manager for the actual processing of the changes, such as recalculating the layout and redrawing the text.

Эти три класса, применяются к представлению, который визуализирует текст.These three classes are applied to a view that renders text. Обработка представления, такие как встроенный текст UITextView, UITextField, и UILabel их установить еще нет, но можно создать и применить их к любому UIView также экземпляра.The built-in text handling views, such as UITextView, UITextField, and UILabel already have them set, but you can create and apply them to any UIView instance as well.

Эта архитектура показана на следующем рисунке:The following figure illustrates this architecture:

Хранилища текста и атрибутыText Storage and Attributes

NSTextStorage Класс содержит текст, отображаемый в представлении.The NSTextStorage class holds the text that is displayed by a view. Она также взаимодействует любые изменения в текст — такие как изменения символов или их атрибуты — для диспетчера макетов для отображения.It also communicates any changes to the text - such as changes to characters or their attributes - to the layout manager for display. NSTextStorage наследует от MSMutableAttributed строки, позволяя изменять атрибуты текста задается в виде пакетов между BeginEditing и EndEditing вызовов.NSTextStorage inherits from MSMutableAttributed string, allowing changes to text attributes to be specified in batches between BeginEditing and EndEditing calls.

Например следующий фрагмент кода указывает изменение на передний план и фон цвета, соответственно и предназначен для определенного диапазона:For example, the following code snippet specifies a change to the foreground and background colors, respectively, and targets particular ranges:

textView.TextStorage.BeginEditing ();
textView.TextStorage.AddAttribute(UIStringAttributeKey.ForegroundColor, UIColor.Green, new NSRange(200, 400));
textView.TextStorage.AddAttribute(UIStringAttributeKey.BackgroundColor, UIColor.Black, new NSRange(210, 300));
textView.TextStorage.EndEditing ();

После EndEditing является именем, изменения отправляются в диспетчер макет, который в свою очередь выполняет все необходимые макета и вычисления отрисовки для текста, отображаемого в представлении.After EndEditing is called, the changes are sent to the layout manager, which in turn performs any necessary layout and rendering calculations for the text to be displayed in the view.

Макет с путь исключенияLayout with Exclusion Path

TextKit также поддерживает макет и позволяет для сложных сценариев, например, несколькими столбцами и заполнение текста вокруг указанного пути вызывается исключить пути.TextKit also supports layout, and allows for complex scenarios such as multi-column text and flowing text around specified paths called exclusion paths. Исключить пути применяются к контейнера текста, который изменяет геометрию макета текста, в результате текст обтекает вокруг указанных путей.Exclusion paths are applied to the text container, which modifies the geometry of the text layout, causing the text to flow around the specified paths.

Добавление путь исключения требует параметр ExclusionPaths свойство диспетчер структуры.Adding an exclusion path requires setting the ExclusionPaths property on the layout manager. При задании этого свойства диспетчера макета сделать недействительными макета текста и потока текста вокруг путь исключения.Setting this property causes the layout manager to invalidate the text layout and flow the text around the exclusion path.

Исключения, исходя из CGPathExclusion based on a CGPath

Рассмотрим следующий UITextView подкласс реализации:Consider the following UITextView subclass implementation:

public class ExclusionPathView : UITextView
{
    CGPath exclusionPath;
    CGPoint initialPoint;
    CGPoint latestPoint;
    UIBezierPath bezierPath;

    public ExclusionPathView (string text)
    {
        Text = text;
        ContentInset = new UIEdgeInsets (20, 0, 0, 0);
        BackgroundColor = UIColor.White;
        exclusionPath = new CGPath ();
        bezierPath = UIBezierPath.Create ();

        LayoutManager.AllowsNonContiguousLayout = false;
    }

    public override void TouchesBegan (NSSet touches, UIEvent evt)
    {
        base.TouchesBegan (touches, evt);

        var touch = touches.AnyObject as UITouch;

        if (touch != null) {
            initialPoint = touch.LocationInView (this);
        }
    }

    public override void TouchesMoved (NSSet touches, UIEvent evt)
    {
        base.TouchesMoved (touches, evt);

        UITouch touch = touches.AnyObject as UITouch;

        if (touch != null) {
            latestPoint = touch.LocationInView (this);
            SetNeedsDisplay ();
        }
    }

    public override void TouchesEnded (NSSet touches, UIEvent evt)
    {
        base.TouchesEnded (touches, evt);

        bezierPath.CGPath = exclusionPath;
        TextContainer.ExclusionPaths = new UIBezierPath[] { bezierPath };
    }

    public override void Draw (CGRect rect)
    {
        base.Draw (rect);

        if (!initialPoint.IsEmpty) {

            using (var g = UIGraphics.GetCurrentContext ()) {

                g.SetLineWidth (4);
                UIColor.Blue.SetStroke ();

                if (exclusionPath.IsEmpty) {
                    exclusionPath.AddLines (new CGPoint[] { initialPoint, latestPoint });
                } else {
                    exclusionPath.AddLineToPoint (latestPoint);
                }

                g.AddPath (exclusionPath);
                g.DrawPath (CGPathDrawingMode.Stroke);
            }
        }
    }
}

Этот код добавляет поддержку для рисования текстового представления с помощью двухмерной графики.This code adds support for drawing on the text view using Core Graphics. Так как UITextView класс создана для использования TextKit для отрисовки текста и макет, он может использовать все возможности TextKit, например, задание путей для исключения.Since the UITextView class is now built to use TextKit for its text rendering and layout, it can use all the features of TextKit, such as setting exclusion paths.

Важно!

Этот пример подклассы UITextView Добавление сенсорного ввода, поддержка рисования.This example subclasses UITextView to add touch drawing support. Создание подкласса UITextView не является обязательным для доступа к возможностям TextKit.Subclassing UITextView isn’t necessary to get the features of TextKit.

После рисования для представления текста, рисуемого CGPath применяется к UIBezierPath экземпляра, задав UIBezierPath.CGPath свойство:After the user draws on the text view, the drawn CGPath is applied to a UIBezierPath instance by setting the UIBezierPath.CGPath property:

bezierPath.CGPath = exclusionPath;

Обновление следующая строка кода делает обновить путь макета текста:Updating the following line of code makes the text layout update around the path:

TextContainer.ExclusionPaths = new UIBezierPath[] { bezierPath };

Снимке экрана ниже показано, как макета текста меняется вокруг вычерченного пути:The following screenshot illustrates how the text layout changes to flow around the drawn path:

Обратите внимание, что диспетчер макета AllowsNonContiguousLayout свойству присваивается значение false, в данном случае.Notice that the layout manager’s AllowsNonContiguousLayout property is set to false in this case. В этом случае макет к пересчету во всех случаях, когда изменяется текст.This causes the layout to be recalculated for all cases where the text changes. Этот параметр может повысить производительность за счет отключения обновления полной компоновки, особенно в случае больших документов.Setting this to true may benefit performance by avoiding a full-layout refresh, especially in the case of large documents. Однако можно присвоить AllowsNonContiguousLayout для true мешающие путь исключения обновление макета в некоторых случаях — к примеру, если текст вводится во время выполнения без возврата каретки конечные до в пути.However, setting AllowsNonContiguousLayout to true would prevent the exclusion path from updating the layout in some circumstances - for example, if text is entered at runtime without a trailing carriage return prior to the path being set.