14

UILabelテキストを(四角形ではなく)円に流し込みたいと思います。でいくつかの実験をNSLayoutManager行いNSTextContainerましNSTextStorageたが、うまくいかないようです。以下の例では、テキストを 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;

イデス?

4

4 に答える 4

21

これは非常に単純な解決策のように見えました。NSTextContainerプロパティを持っていexclusionPathsます。できることは、除外する必要がある領域を定義する 2 つのベジエ パスを作成することです。

ここに画像の説明を入力

だから私はそれをしました、そしてここに私の方法があります:

- (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];
}

使用例:

[self setCircularExclusionPathWithCenter:CGPointMake(160.0f, 200.0f)
                                  radius:100.0f
                                textView:_textView];

そして私の実験の結果:

ここに画像の説明を入力

もちろん、UILabel の代わりに UITextView を使用する必要がありますが、それが役立つことを願っています :)

于 2014-03-04T17:40:57.413 に答える
7

TextKit スタックにアクセスできないため、UILabel でこれを行うことはできません。私がやっていることは、独自の 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;
}

粗雑だが効果的。次のようになります。

ここに画像の説明を入力

于 2014-03-04T17:56:16.377 に答える
3

Swift 4 と iOS 11 では、NSTextContainerというプロパティがありますexclusionPathsexclusionPaths次の宣言があります。

テキスト コンテナーでテキストが表示されない領域を表すパス オブジェクトの配列。

var exclusionPaths: [UIBezierPath] { get set }

また、UIBezierPathというプロパティがありますusesEvenOddFillRuleusesEvenOddFillRule次の宣言があります。

パスの描画に偶奇ワインディング ルールが使用されているかどうかを示すブール値。

var usesEvenOddFillRule: Bool { get set }

を使用usesEvenOddFillRuleすると、わずか数行のコードで円を囲む除外パスを作成できます。

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

次のUITextViewおよびサブクラスは、 およびプロパティUIViewControllerを使用して円内にテキストを表示する方法を示しています。NSTextContainer exclusionPathsUIBezierPath usesEvenOddFillRule

TextView.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
    }

}
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()
     }
     */

}

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]
    }

}

のいずれかの実装を選択draw(_:)すると、次のように表示されます。

ここに画像の説明を入力

于 2017-08-08T00:22:22.160 に答える