Partager via


TextKit dans Xamarin.iOS

TextKit est une nouvelle API qui offre de puissantes fonctionnalités de mise en page et de rendu de texte. Il est basé sur l’infrastructure Core Text de bas niveau, mais est beaucoup plus facile à utiliser que Core Text.

Pour rendre les fonctionnalités de TextKit disponibles pour les contrôles standard, plusieurs contrôles de texte iOS ont été ré-implémentés pour utiliser TextKit, notamment :

  • UITextView
  • UITextField
  • UILabel

Architecture

TextKit fournit une architecture en couches qui sépare le stockage de texte de la disposition et de l’affichage, y compris les classes suivantes :

  • NSTextContainer : fournit le système de coordonnées et la géométrie utilisés pour mettre en page le texte.
  • NSLayoutManager : place le texte en glyphes.
  • NSTextStorage : contient les données de texte, ainsi que gère les mises à jour des propriétés de texte par lots. Toutes les mises à jour par lots sont transmises au gestionnaire de disposition pour le traitement réel des modifications, telles que le recalcul de la disposition et le redessinage du texte.

Ces trois classes sont appliquées à une vue qui restitue du texte. Les vues de gestion de texte intégrées, telles que UITextView, UITextFieldet UILabel déjà définies, peuvent également être créées et appliquées à n’importe quelle UIView instance.

La figure suivante illustre cette architecture :

Cette figure illustre l’architecture TextKit

Stockage de texte et attributs

La NSTextStorage classe contient le texte affiché par un affichage. Il communique également les modifications apportées au texte, telles que les modifications apportées aux caractères ou à leurs attributs, au gestionnaire de disposition pour l’affichage. NSTextStorage hérite de la MSMutableAttributed chaîne, ce qui permet aux modifications apportées aux attributs de texte d’être spécifiés par lots entre BeginEditing et EndEditing appels.

Par exemple, l’extrait de code suivant spécifie une modification des couleurs de premier plan et d’arrière-plan, respectivement, et cible des plages particulières :

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 ();

Une fois EndEditing appelée, les modifications sont envoyées au gestionnaire de disposition, ce qui effectue à son tour les calculs de disposition et de rendu nécessaires pour que le texte s’affiche dans l’affichage.

Disposition avec chemin d’exclusion

TextKit prend également en charge la disposition et permet des scénarios complexes tels que le texte à plusieurs colonnes et le texte qui circule autour des chemins d’accès spécifiés appelés chemins d’exclusion. Les chemins d’exclusion sont appliqués au conteneur de texte, qui modifie la géométrie de la disposition du texte, ce qui entraîne le flux du texte autour des chemins spécifiés.

L’ajout d’un chemin d’exclusion nécessite la définition de la ExclusionPaths propriété sur le gestionnaire de disposition. La définition de cette propriété entraîne l’invalidation du gestionnaire de disposition par le gestionnaire de dispositions et le flux du texte autour du chemin d’exclusion.

Exclusion basée sur un CGPath

Considérez l’implémentation de sous-classe suivante UITextView :

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);
            }
        }
    }
}

Ce code ajoute la prise en charge du dessin sur l’affichage texte à l’aide de Core Graphics. Étant donné que la UITextView classe est désormais générée pour utiliser TextKit pour son rendu et sa disposition de texte, elle peut utiliser toutes les fonctionnalités de TextKit, telles que la définition des chemins d’exclusion.

Important

Cet exemple de sous-classe UITextView pour ajouter la prise en charge du dessin tactile. La sous-classe UITextView n’est pas nécessaire pour obtenir les fonctionnalités de TextKit.

Une fois que l’utilisateur s’appuie sur la vue de texte, le dessin CGPath est appliqué à une UIBezierPath instance en définissant la UIBezierPath.CGPath propriété :

bezierPath.CGPath = exclusionPath;

La mise à jour de la ligne de code suivante met à jour la disposition du texte autour du chemin d’accès :

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

La capture d’écran suivante montre comment la disposition du texte change pour circuler autour du chemin dessiné :

Cette capture d’écran montre comment la disposition du texte change pour circuler autour du chemin dessiné

Notez que la propriété du gestionnaire de AllowsNonContiguousLayout disposition est définie sur false dans ce cas. Cela entraîne le recalcul de la disposition pour tous les cas où le texte change. La définition de cette valeur peut bénéficier de performances en évitant une actualisation complète de la disposition, en particulier dans le cas de documents volumineux. Toutefois, la valeur AllowsNonContiguousLayout true empêcherait la mise à jour du chemin d’exclusion dans certaines circonstances , par exemple, si le texte est entré au moment de l’exécution sans retour chariot de fin avant la définition du chemin d’accès.