TextKit en Xamarin.iOS
TextKit es una nueva API que ofrece características eficaces de representación y diseño de texto. Se basa en el marco de texto principal de bajo nivel, pero es mucho más fácil de usar que Core Text.
Para que las características de TextKit estén disponibles para los controles estándar, se han implementado de nuevo varios controles de texto de iOS para usar TextKit, incluidos:
- UITextView
- UITextField
- UILabel
Arquitectura
TextKit proporciona una arquitectura en capas que separa el almacenamiento de texto del diseño y la presentación, incluidas las clases siguientes:
NSTextContainer: proporciona el sistema de coordenadas y la geometría que se usa para el diseño de texto.NSLayoutManager: divide el texto convirtiendo texto en glifos.NSTextStorage: contiene los datos de texto, así como controla las actualizaciones de propiedades de texto por lotes. Las actualizaciones por lotes se entregan al administrador de diseño para el procesamiento real de los cambios, como volver a calcular el diseño y volver a dibujar el texto.
Estas tres clases se aplican a una vista que representa texto. Las vistas de control de texto integradas, como , y ya tienen establecidas, pero también puede crearlas y aplicarlas UITextViewUITextField a cualquier UILabelUIView instancia.
En la ilustración siguiente se muestra esta arquitectura:

Atributos Storage texto
La NSTextStorage clase contiene el texto que muestra una vista. También comunica los cambios en el texto ,como los cambios en los caracteres o sus atributos, al administrador de diseño para su presentación. NSTextStorage hereda de la cadena, lo que permite que los cambios en los atributos de texto se especifiquen en MSMutableAttributed lotes entre llamadas y BeginEditingEndEditing .
Por ejemplo, el siguiente fragmento de código especifica un cambio en los colores de primer plano y fondo, respectivamente, y tiene como destino intervalos concretos:
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 ();
Después de llamar a , los cambios se envían al administrador de diseño, que a su vez realiza los cálculos de diseño y representación necesarios para que el texto se muestre EndEditing en la vista.
Diseño con ruta de exclusión
TextKit también admite el diseño y permite escenarios complejos, como texto de varias columnas y texto que fluye alrededor de rutas de acceso especificadas denominadas rutas de exclusión. Las rutas de exclusión se aplican al contenedor de texto, lo que modifica la geometría del diseño de texto, lo que hace que el texto fluya alrededor de las rutas de acceso especificadas.
Agregar una ruta de exclusión requiere establecer ExclusionPaths la propiedad en el administrador de diseño. Al establecer esta propiedad, el administrador de diseño invalida el diseño de texto y fluye el texto alrededor de la ruta de exclusión.
Exclusión basada en UNA RUTA DE ACCESO
Considere la siguiente UITextView implementación de subclase:
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);
}
}
}
}
Este código agrega compatibilidad para dibujar en la vista de texto mediante gráficos principales. Puesto que la clase ahora se ha creado para usar TextKit para su representación y diseño de texto, puede usar todas las características de TextKit, como establecer rutas de UITextView exclusión.
Importante
En este ejemplo se agregan subclases UITextView para agregar compatibilidad con dibujo táctil. No es UITextView necesario crear subclases para obtener las características de TextKit.
Una vez que el usuario dibuja en la vista de texto, el dibujo se CGPath aplica a una instancia UIBezierPath estableciendo la propiedad UIBezierPath.CGPath :
bezierPath.CGPath = exclusionPath;
Al actualizar la siguiente línea de código, el diseño de texto se actualiza alrededor de la ruta de acceso:
TextContainer.ExclusionPaths = new UIBezierPath[] { bezierPath };
En la captura de pantalla siguiente se muestra cómo cambia el diseño del texto para que fluya alrededor del trazado dibujado:

Observe que la propiedad del administrador de AllowsNonContiguousLayout diseño está establecida en false en este caso. Esto hace que el diseño se recalcule para todos los casos en los que cambia el texto. Establecer esto en true puede beneficiar al rendimiento evitando una actualización de diseño completo, especialmente en el caso de documentos grandes. Sin embargo, establecer en true impediría que la ruta de exclusión actualizara el diseño en algunas circunstancias; por ejemplo, si el texto se introduce en tiempo de ejecución sin un retorno de carro final antes de establecer la ruta AllowsNonContiguousLayout de acceso.