Xamarin. iOS içindeki TextKit

TextKit, güçlü metin düzeni ve işleme özellikleri sunan yeni bir API 'dir. Alt düzey çekirdek metin çerçevesinin üzerine kurulmuştur, ancak çekirdek metinden daha kolay bir şekilde kullanılır.

TextKit 'in özelliklerinin standart denetimler tarafından kullanılabilmesini sağlamak için, çeşitli iOS metin denetimleri, TextKit 'i kullanmak üzere yeniden uygulanmıştır, örneğin:

  • UITextView
  • Uitextalanı
  • UILabel

Mimari

TextKit, aşağıdaki sınıflar da dahil olmak üzere, metin depolamayı düzen ve görüntü ile ayıran katmanlı bir mimari sağlar:

  • NSTextContainer – Metin düzeninde kullanılan koordinat sistemi ve geometrisi sağlar.
  • NSLayoutManager : Metni karakterlere çevirip metni yerleştirir.
  • NSTextStorage – Metin verisini tutar ve toplu metin özelliği güncelleştirmelerini işler. Herhangi bir toplu güncelleştirme, değişiklikleri yeniden hesaplama ve metni yeniden çizme gibi değişikliklerin gerçek işlenmesi için Düzen yöneticisine devredilir.

Bu üç sınıf, metni işleyen bir görünüme uygulanır. , Ve gibi yerleşik metin işleme görünümleri UITextViewUITextFieldUILabel ayarlanır, ancak bunları herhangi bir örneğe de oluşturabilir ve uygulayabilirsiniz UIView .

Aşağıdaki şekilde bu mimari gösterilmektedir:

Bu şekilde TextKit mimarisi gösterilmektedir

metin Depolama ve öznitelikleri

NSTextStorageSınıfı, bir görünüm tarafından görüntülenen metni barındırır. Ayrıca, metinde yapılan değişiklikler (örneğin, karakterlere veya özniteliklerini), görüntüleme için Düzen Yöneticisi ' ne kadar olan değişiklikleri de iletişim kurar. NSTextStorage dizeden devralır MSMutableAttributed ve metin özniteliklerine yapılan değişikliklerin ve çağrıları arasındaki toplu işlerle belirtilmesini sağlar BeginEditingEndEditing .

Örneğin, aşağıdaki kod parçacığı ön plan ve arka plan renkleriyle, sırasıyla ve özel aralıklarda yapılan bir değişikliği belirtir:

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

Çağrıldıktan sonra EndEditing değişiklikler, düzen yöneticisine gönderilir, bu da görünümde görüntülenecek metin için gereken düzen ve işleme hesaplamalarını gerçekleştirir.

Dışlama yolu olan düzen

TextKit Ayrıca düzeni destekler ve birden çok sütunlu metin ve dışlama yollarıolarak belirtilen yolların etrafında akan metin gibi karmaşık senaryolara olanak tanır. Dışlama yolları metin kapsayıcısına uygulanır, bu da metin düzeninin geometrisini değiştirir ve metnin belirtilen yolların etrafında akamasına neden olur.

Dışlama yolu eklemek için, ExclusionPaths Düzen yöneticisinde özelliğin ayarlanması gerekir. Bu özelliğin ayarlanması, düzen yöneticisinin metin yerleşimini geçersiz kılması ve metni dışlama yolu etrafında akmasını sağlar.

Bir CGPath temelinde dışlama

Aşağıdaki UITextView alt sınıf uygulamasını göz önünde bulundurun:

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

Bu kod, ana grafikleri kullanarak metin görünümünde çizim için destek ekler. UITextViewSınıfı artık metin işleme ve düzeni Için TextKit 'i kullanacak şekilde oluşturulduğundan, hariç tutma yollarını ayarlama gibi textkit 'in tüm özelliklerini kullanabilir.

Önemli

Bu örnek, UITextView dokunma çizim desteği eklemek için alt sınıfları. Altsınıflama, UITextView TextKit 'in özelliklerini almak için gerekli değildir.

Kullanıcı metin görünümünü çizdikten sonra, bu, CGPathUIBezierPath özelliği ayarlanarak bir örneğe uygulanır UIBezierPath.CGPath :

bezierPath.CGPath = exclusionPath;

Aşağıdaki kod satırını güncelleştirmek, metin düzeninin yol etrafında güncelleştirilmesini sağlar:

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

Aşağıdaki ekran görüntüsünde, metin düzeninin çizilen yolun çevresinde nasıl değiştiği gösterilmektedir:

Bu ekran görüntüsünde, metin düzeninin çizilen yolun çevresinde akışa nasıl değiştiği gösterilmektedir

AllowsNonContiguousLayoutBu durumda düzen yöneticisinin özelliğinin false olarak ayarlandığını unutmayın. Bu, metnin değiştiği tüm durumlarda düzenin yeniden hesaplanmasına neden olur. Özellikle büyük belgeler söz konusu olduğunda, bunun doğru olarak ayarlanması, tam düzen yenilemenin önlenmesiyle performans sağlayabilir. Bununla birlikte, AllowsNonContiguousLayout true olarak ayarlandığında dışlama yolunun bazı koşullarda düzeni güncelleştirmesi önlenir. Örneğin, çalışma zamanında, ayarlanan yoldan önce bir bitiş satırı olmadan, metin girilmişse.