如何在UILabel中将文本放入圆圈中

pku*_*har 12 objective-c uilabel ios ios7 textkit

我想将文本UILabel转换为圆形(而不是矩形).我做了一些实验用NSLayoutManager,NSTextContainerNSTextStorage,但它似乎并没有工作.以下示例应该将文本流入40x40的较小矩形(标签为120x120),但似乎没有任何影响.

UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:12];
NSTextStorage *ts = [[NSTextStorage alloc] initWithString:multiline.title attributes:@{NSFontAttributeName:font}];
NSLayoutManager *lm = [[NSLayoutManager alloc] init];
NSTextContainer *tc = [[NSTextContainer alloc] initWithSize:CGSizeMake(40, 40)];
[lm addTextContainer:tc];
[ts addLayoutManager:lm];
self.label.attributedText = ts;
Run Code Online (Sandbox Code Playgroud)

Ides的?

Raf*_*fAl 19

这似乎是一个非常简单的解决方案.NSTextContainerexclusionPaths房产.您可以做的是创建两个Bezier路径,这些路径将定义应排除的区域.

在此输入图像描述

所以我这样做了,这是我的方法:

- (void)setCircularExclusionPathWithCenter:(CGPoint)center radius:(CGFloat)radius textView:(UITextView *)textView
{
    UIBezierPath *topHalf = [UIBezierPath bezierPath];
    [topHalf moveToPoint:CGPointMake(center.x - radius, center.y + radius)];
    [topHalf addLineToPoint:CGPointMake(center.x - radius, center.y)];
    [topHalf addArcWithCenter:center radius:radius startAngle:M_PI endAngle:0.0f clockwise:NO];
    [topHalf addLineToPoint:CGPointMake(center.x + radius, center.y + radius)];
    [topHalf closePath];

    UIBezierPath *bottomHalf = [UIBezierPath bezierPath];
    [bottomHalf moveToPoint:CGPointMake(center.x - radius, center.y - radius)];
    [bottomHalf addLineToPoint:CGPointMake(center.x - radius, center.y)];
    [bottomHalf addArcWithCenter:center radius:radius startAngle:M_PI endAngle:0 clockwise:YES];
    [bottomHalf addLineToPoint:CGPointMake(center.x + radius, center.y - radius)];
    [bottomHalf closePath];

    textView.textContainer.exclusionPaths = @[bottomHalf, topHalf];
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

[self setCircularExclusionPathWithCenter:CGPointMake(160.0f, 200.0f)
                                  radius:100.0f
                                textView:_textView];
Run Code Online (Sandbox Code Playgroud)

我的实验结果如下:

在此输入图像描述

当然你必须使用UITextView而不是UILabel,但我希望它有帮助:)


mat*_*att 7

您无法在UILabel中执行此操作,因为它不允许您访问TextKit堆栈.我所做的是构建自己的TextKit堆栈和子类NSTextContainer:

-(CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect atIndex:(NSUInteger)characterIndex writingDirection:(NSWritingDirection)baseWritingDirection remainingRect:(CGRect *)remainingRect {
    CGRect result = [super lineFragmentRectForProposedRect:proposedRect atIndex:characterIndex writingDirection:baseWritingDirection remainingRect:remainingRect];
    CGRect r = CGRectMake(0,0,self.size.width,self.size.height);
    UIBezierPath* circle = [UIBezierPath bezierPathWithOvalInRect:r];
    CGPoint p = result.origin;
    while (![circle containsPoint:p]) {
        p.x += .1;
        result.origin = p;
    }
    CGFloat w = result.size.width;
    p = result.origin;
    p.x += w;
    while (![circle containsPoint:p]) {
        w -= .1;
        result.size.width = w;
        p = result.origin;
        p.x += w;
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

原油但有效.看起来像这样:

在此输入图像描述


Ima*_*tit 5

在 Swift 4 和 iOS 11 中,NSTextContainer有一个名为exclusionPaths. exclusionPaths有以下声明:

表示文本容器中未显示文本的区域的路径对象数组。

var exclusionPaths: [UIBezierPath] { get set }
Run Code Online (Sandbox Code Playgroud)

此外,UIBezierPath还有一个名为 的属性usesEvenOddFillRuleusesEvenOddFillRule有以下声明:

一个布尔值,指示是否使用奇偶缠绕规则来绘制路径。

var usesEvenOddFillRule: Bool { get set }
Run Code Online (Sandbox Code Playgroud)

通过使用usesEvenOddFillRule,您只需几行代码即可创建围绕圆的排除路径:

var exclusionPath: UIBezierPath {
    let path = UIBezierPath(ovalIn: bounds)
    path.append(UIBezierPath(rect: bounds))
    path.usesEvenOddFillRule = true
    return path
}
Run Code Online (Sandbox Code Playgroud)

以下UITextView及其子类展示了如何使用和属性UIViewController在圆圈内显示文本:NSTextContainer exclusionPathsUIBezierPath usesEvenOddFillRule

文本视图.swift

import UIKit

class TextView: UITextView {

    convenience init() {
        self.init(frame: .zero, textContainer: nil)
    }

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)

        isScrollEnabled = false
        isEditable = false
        textContainerInset = .zero
        self.textContainer.lineBreakMode = .byTruncatingTail
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    var exclusionPath: UIBezierPath {
        let path = UIBezierPath(ovalIn: bounds)
        path.append(UIBezierPath(rect: bounds))
        path.usesEvenOddFillRule = true
        return path
    }

}
Run Code Online (Sandbox Code Playgroud)
extension TextView {

    // Draw circle

    override func draw(_ rect: CGRect) {
        UIColor.orange.setFill()
        let path = UIBezierPath(ovalIn: rect)
        path.fill()
    }

    // Draw exclusion path

    /*
     override func draw(_ rect: CGRect) {
         UIColor.orange.setFill()
         exclusionPath.fill()
     }
     */

}
Run Code Online (Sandbox Code Playgroud)

ViewController.swift

import UIKit

class ViewController: UIViewController {

    let textView = TextView()

    override func viewDidLoad() {
        super.viewDidLoad()

        let string = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda."
        textView.attributedText = NSAttributedString(string: string)
        view.addSubview(textView)

        textView.translatesAutoresizingMaskIntoConstraints = false
        let horizontalConstraint = textView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        let verticalConstraint = textView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        let widthConstraint = textView.widthAnchor.constraint(equalToConstant: 240)
        let heightConstraint = textView.heightAnchor.constraint(equalToConstant: 240)
        NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])            
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        textView.textContainer.exclusionPaths = [textView.exclusionPath]
    }

}
Run Code Online (Sandbox Code Playgroud)

通过选择 的一种或另一种实现draw(_:),您将看到以下显示:

在此输入图像描述