[ios] UILabel에 윤곽선이있는 텍스트를 표시하려면 어떻게해야합니까?

내가 원하는 것은 흰색 UILabel 텍스트 주위에 1 픽셀의 검은 색 테두리입니다.

나는 아래 코드로 UILabel을 서브 클래 싱하는 데까지 이르렀는데, 접선 적으로 관련된 몇 가지 온라인 예제에서 서투르게 조합했습니다. 그리고 그것은 작동하지만 매우 느립니다 (시뮬레이터 제외) 텍스트를 세로로 중앙에 놓을 수 없었습니다 (그래서 마지막 줄에 y 값을 일시적으로 하드 코딩했습니다). 아아!

void ShowStringCentered(CGContextRef gc, float x, float y, const char *str) {
    CGContextSetTextDrawingMode(gc, kCGTextInvisible);
    CGContextShowTextAtPoint(gc, 0, 0, str, strlen(str));
    CGPoint pt = CGContextGetTextPosition(gc);

    CGContextSetTextDrawingMode(gc, kCGTextFillStroke);

    CGContextShowTextAtPoint(gc, x - pt.x / 2, y, str, strlen(str));
}


- (void)drawRect:(CGRect)rect{

    CGContextRef theContext = UIGraphicsGetCurrentContext();
    CGRect viewBounds = self.bounds;

    CGContextTranslateCTM(theContext, 0, viewBounds.size.height);
    CGContextScaleCTM(theContext, 1, -1);

    CGContextSelectFont (theContext, "Helvetica", viewBounds.size.height,  kCGEncodingMacRoman);

    CGContextSetRGBFillColor (theContext, 1, 1, 1, 1);
    CGContextSetRGBStrokeColor (theContext, 0, 0, 0, 1);
    CGContextSetLineWidth(theContext, 1.0);

    ShowStringCentered(theContext, rect.size.width / 2.0, 12, [[self text] cStringUsingEncoding:NSASCIIStringEncoding]);
}

나는 이것을하는 더 간단한 방법을 간과하고 있다는 잔소리를 느낀다. 아마도 “drawTextInRect”를 재정의하는 것입니다. 그러나 저는 drawTextInRect를 열심히 쳐다보고 정말 열심히 찌푸리고 있음에도 불구하고 내 의지에 구부러지는 것처럼 보이지 않습니다.



답변

drawTextInRect를 재정 의하여 수행 할 수있었습니다.

- (void)drawTextInRect:(CGRect)rect {

  CGSize shadowOffset = self.shadowOffset;
  UIColor *textColor = self.textColor;

  CGContextRef c = UIGraphicsGetCurrentContext();
  CGContextSetLineWidth(c, 1);
  CGContextSetLineJoin(c, kCGLineJoinRound);

  CGContextSetTextDrawingMode(c, kCGTextStroke);
  self.textColor = [UIColor whiteColor];
  [super drawTextInRect:rect];

  CGContextSetTextDrawingMode(c, kCGTextFill);
  self.textColor = textColor;
  self.shadowOffset = CGSizeMake(0, 0);
  [super drawTextInRect:rect];

  self.shadowOffset = shadowOffset;

}


답변

더 간단한 해결책은 다음과 같이 속성 문자열 을 사용하는 것입니다.

스위프트 4 :

let strokeTextAttributes: [NSAttributedStringKey : Any] = [
    NSAttributedStringKey.strokeColor : UIColor.black,
    NSAttributedStringKey.foregroundColor : UIColor.white,
    NSAttributedStringKey.strokeWidth : -2.0,
    ]

myLabel.attributedText = NSAttributedString(string: "Foo", attributes: strokeTextAttributes)

Swift 4.2 :

let strokeTextAttributes: [NSAttributedString.Key : Any] = [
    .strokeColor : UIColor.black,
    .foregroundColor : UIColor.white,
    .strokeWidth : -2.0,
    ]

myLabel.attributedText = NSAttributedString(string: "Foo", attributes: strokeTextAttributes)

A의 UITextField당신은 설정할 수있는 defaultTextAttributes과를 attributedPlaceholder잘한다.

참고가 NSStrokeWidthAttributeName 부정적하는 이 경우, 즉, 단지 내부 윤곽 작동합니다.

속성이있는 텍스트를 사용하는 윤곽선이있는 UITextFields


답변

수락 된 답변과 이에 대한 두 가지 수정 사항 및 Axel Guilmin의 답변을 읽은 후 Swift로 전체 솔루션을 컴파일하기로 결정했습니다.

import UIKit

class UIOutlinedLabel: UILabel {

    var outlineWidth: CGFloat = 1
    var outlineColor: UIColor = UIColor.whiteColor()

    override func drawTextInRect(rect: CGRect) {

        let strokeTextAttributes = [
            NSStrokeColorAttributeName : outlineColor,
            NSStrokeWidthAttributeName : -1 * outlineWidth,
        ]

        self.attributedText = NSAttributedString(string: self.text ?? "", attributes: strokeTextAttributes)
        super.drawTextInRect(rect)
    }
}

이 사용자 정의 UILabel 클래스를 Interface Builder의 기존 레이블에 추가하고 다음과 같이 사용자 정의 런타임 속성을 추가하여 테두리의 두께와 색상을 변경할 수 있습니다.
Interface Builder 설정

결과:

윤곽선이있는 큰 빨간색 G


답변

답변의 구현에는 한 가지 문제가 있습니다. 획을 사용하여 텍스트를 그리는 것은 획이없는 텍스트를 그리는 것과 약간 다른 문자 글리프 너비를 가지므로 “중심이없는”결과를 얻을 수 있습니다. 채우기 텍스트 주위에 보이지 않는 선을 추가하여 문제를 해결할 수 있습니다.

바꾸다:

CGContextSetTextDrawingMode(c, kCGTextFill);
self.textColor = textColor;
self.shadowOffset = CGSizeMake(0, 0);
[super drawTextInRect:rect];

와:

CGContextSetTextDrawingMode(context, kCGTextFillStroke);
self.textColor = textColor;
[[UIColor clearColor] setStroke]; // invisible stroke
self.shadowOffset = CGSizeMake(0, 0);
[super drawTextInRect:rect];

나는 그것이 진짜 거래인지 100 % 확신하지 못합니다. 왜냐하면 self.textColor = textColor;과 같은 효과가 있는지는 모르기 때문 [textColor setFill]입니다.하지만 작동해야합니다.

공개 : 저는 THLabel의 개발자입니다.

얼마 전에 UILabel 하위 클래스를 출시하여 텍스트 및 기타 효과의 개요를 허용합니다. 여기에서 찾을 수 있습니다 : https://github.com/tobihagemann/THLabel


답변

이렇게하면 외곽선이 만들어지지는 않지만 텍스트 주위에 그림자가 생기며 그림자 반경을 충분히 작게 만들면 외곽선과 비슷할 수 있습니다.

label.layer.shadowColor = [[UIColor blackColor] CGColor];
label.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
label.layer.shadowOpacity = 1.0f;
label.layer.shadowRadius = 1.0f;

이전 버전의 iOS와 호환되는지 모르겠습니다 ..

어쨌든 도움이 되었으면합니다 …


답변

kprevas답변을 기반으로 한 Swift 4 클래스 버전

import Foundation
import UIKit

public class OutlinedText: UILabel{
    internal var mOutlineColor:UIColor?
    internal var mOutlineWidth:CGFloat?

    @IBInspectable var outlineColor: UIColor{
        get { return mOutlineColor ?? UIColor.clear }
        set { mOutlineColor = newValue }
    }

    @IBInspectable var outlineWidth: CGFloat{
        get { return mOutlineWidth ?? 0 }
        set { mOutlineWidth = newValue }
    }

    override public func drawText(in rect: CGRect) {
        let shadowOffset = self.shadowOffset
        let textColor = self.textColor

        let c = UIGraphicsGetCurrentContext()
        c?.setLineWidth(outlineWidth)
        c?.setLineJoin(.round)
        c?.setTextDrawingMode(.stroke)
        self.textColor = mOutlineColor;
        super.drawText(in:rect)

        c?.setTextDrawingMode(.fill)
        self.textColor = textColor
        self.shadowOffset = CGSize(width: 0, height: 0)
        super.drawText(in:rect)

        self.shadowOffset = shadowOffset
    }
}

UILabel의 사용자 정의 클래스를 OutlinedText로 설정하여 인터페이스 빌더에서 전적으로 구현할 수 있습니다. 그런 다음 속성 창에서 윤곽선의 너비와 색상을 설정할 수 있습니다.

여기에 이미지 설명 입력


답변

복잡한 애니메이션을 적용하려는 경우 가장 좋은 방법은 대신 애니메이션으로 해당 애니메이션의 스크린 샷을 프로그래밍 방식으로 찍는 것입니다!

뷰의 스크린 샷을 찍으려면 다음과 같은 코드가 필요합니다.

UIGraphicsBeginImageContext(mainContentView.bounds.size);
[mainContentView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext(); 

여기서 mainContentView는 스크린 샷을 찍으려는 뷰입니다. UIImageView에 viewImage를 추가하고 애니메이션을 적용합니다.

애니메이션 속도가 빨라지 길 바랍니다 !!