다음을 통해 공유


Xamarin.iOS의 TextKit

TextKit은 강력한 텍스트 레이아웃 및 렌더링 기능을 제공하는 새로운 API입니다. 하위 수준 Core Text 프레임워크를 기반으로 빌드되지만 Core Text보다 사용하기가 훨씬 쉽습니다.

TextKit의 기능을 표준 컨트롤에서 사용할 수 있도록 하기 위해 다음과 같은 TextKit을 사용하도록 여러 iOS 텍스트 컨트롤이 다시 구현되었습니다.

  • UITextView
  • UITextField
  • UILabel

아키텍처

TextKit은 다음 클래스를 포함하여 텍스트 스토리지를 레이아웃 및 디스플레이와 구분하는 계층화된 아키텍처를 제공합니다.

  • NSTextContainer – 텍스트를 레이아웃하는 데 사용되는 좌표계 및 기하 도형을 제공합니다.
  • NSLayoutManager – 텍스트를 문자 모양으로 바꿔 텍스트를 배치합니다.
  • NSTextStorage – 텍스트 데이터를 보관하고 일괄 처리 텍스트 속성 업데이트를 처리합니다. 레이아웃 다시 계산 및 텍스트 다시 그리기와 같은 변경 내용의 실제 처리를 위해 모든 일괄 업데이트가 레이아웃 관리자에게 전달됩니다.

이러한 세 클래스는 텍스트를 렌더링하는 뷰에 적용됩니다. 기본 제공 텍스트 처리 뷰(예: UITextView, UITextFieldUILabel 이미 설정됨)는 만들면 모든 인스턴스에도 적용할 UIView 수 있습니다.

다음 그림에서는 이 아키텍처를 보여 줍니다.

이 그림에서는 TextKit 아키텍처를 보여 줍니다.

Text Storage 및 특성

클래스는 NSTextStorage 뷰에 표시되는 텍스트를 보유합니다. 또한 텍스트 변경 내용(예: 문자 또는 특성 변경)을 레이아웃 관리자에 전달하여 표시합니다. NSTextStorage 는 문자열에서 MSMutableAttributed 상속되므로 텍스트 특성에 대한 변경 내용을 호출 간에 BeginEditingEndEditing 일괄 처리로 지정할 수 있습니다.

예를 들어 다음 코드 조각은 각각 전경색과 배경색의 변경 사항을 지정하고 특정 범위를 대상으로 합니다.

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 변경 내용이 레이아웃 관리자로 전송되고, 그러면 보기에 표시할 텍스트에 필요한 레이아웃 및 렌더링 계산이 수행됩니다.

제외 경로가 있는 레이아웃

TextKit은 레이아웃도 지원하며, 다중 열 텍스트 및 제외 경로라는 지정된 경로 주위에 흐르는 텍스트와 같은 복잡한 시나리오를 허용합니다. 제외 경로는 텍스트 레이아웃의 기하 도형을 수정하여 지정된 경로 주위에 텍스트가 흐르도록 하는 텍스트 컨테이너에 적용됩니다.

제외 경로를 추가하려면 레이아웃 관리자에서 ExclusionPaths 속성을 설정해야 합니다. 이 속성을 설정하면 레이아웃 관리자가 텍스트 레이아웃을 무효화하고 제외 경로 주위에 텍스트를 흐릅니다.

CGPath 기반 제외

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

이 코드는 핵심 그래픽을 사용하여 텍스트 보기에 그리기를 지원합니다. 이제 클래스는 UITextView 텍스트 렌더링 및 레이아웃에 TextKit을 사용하도록 빌드되었으므로 제외 경로 설정과 같은 TextKit의 모든 기능을 사용할 수 있습니다.

Important

다음은 터치 그리기 지원을 추가하는 서브클래스 UITextView 예제입니다. TextKit의 기능을 가져오는 데는 서브클래싱 UITextView 이 필요하지 않습니다.

사용자가 텍스트 뷰를 그린 후에는 속성을 설정하여 그리기를 CGPath 인스턴스에 적용합니다UIBezierPath.CGPath.UIBezierPath

bezierPath.CGPath = exclusionPath;

다음 코드 줄을 업데이트하면 경로 주위에 텍스트 레이아웃이 업데이트됩니다.

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

다음 스크린샷은 텍스트 레이아웃이 그려지는 경로 주위에 흐르는 방식을 보여 줍니다.

이 스크린샷은 텍스트 레이아웃이 그려지는 경로 주위에 흐르도록 변경되는 방법을 보여 줍니다.

이 경우 레이아웃 관리자의 AllowsNonContiguousLayout 속성이 false로 설정됩니다. 이렇게 하면 텍스트가 변경되는 모든 경우에 레이아웃이 다시 계산됩니다. 이 값을 true로 설정하면 특히 큰 문서의 경우 전체 레이아웃 새로 고침을 방지하여 성능에 도움이 될 수 있습니다. 그러나 true로 설정 AllowsNonContiguousLayout 하면 경로가 설정되기 전에 후행 캐리지 리턴 없이 런타임에 텍스트를 입력하는 경우와 같이 경우에 따라 제외 경로가 레이아웃을 업데이트하지 못하게 됩니다.