在 iPhone 上的 UILabel 中查找特定字符的位置

发布于 2024-09-08 03:04:25 字数 239 浏览 9 评论 0原文

我有一个带有一些文本的 UILabel,比如“Hello World abcdefg” 该标签可以有多行、不同的字体大小等。

问题:如何找到此 UILabel 中所有字母“d”的坐标。

逻辑上的第一步是找到这些字符在字符串(UILabel.text)中的位置,但是当它实际绘制在屏幕上时,如何将其转换为坐标

这个想法是找到这些坐标并在该字符的顶部绘制一些自定义的内容(基本上是用自定义图像覆盖它)

I have a UILabel with some text, say "Hello World abcdefg" The label can have multiple lines, different font sizes etc.

Question: How do I find the coordinates of all letters "d" in this UILabel.

Logical first step is find the position of those characters in the string (UILabel.text), but then how do I translate that into coordinates when it's actually drawn on screen

The idea is to find those coordinates and draw something custom on top of that character (basically to cover it with a custom image)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

潇烟暮雨 2024-09-15 03:04:25

在 iPhone 上测量文本的基本工具位于 UIStringDrawing.h 中,但它们都无法满足您的需求。您基本上必须一次迭代一个字符来测量每个子字符串。当行换行时(结果更高),在最后一个未换行的字符之后分割并将行高添加到 y 坐标。

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode;

The basic tools for measuring text on iPhone are in UIStringDrawing.h but none of them do what you need. You will basically have to iterate through substrings one character at a time measuring each. When a line wraps (the result is taller), split after the last character that did not wrap and add the line height to your y coordinate.

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode;
梦明 2024-09-15 03:04:25

自 iOS 7.0 发布以来,方法已经发生了变化。试试这个

- (CGFloat)charactersOffsetBeforeDayPartOfLabel {
    NSRange range = [[self stringFromDate:self.currentDate] rangeOfString:[NSString stringWithFormat:@"%i",[self dayFromDate:self.currentDate]]];
    NSString *chars = [[self stringFromDate:self.currentDate] substringToIndex:range.location];
    NSMutableArray *arrayOfChars = [[NSMutableArray alloc]init];
    [chars enumerateSubstringsInRange:NSMakeRange(0, [chars length]) options:(NSStringEnumerationByComposedCharacterSequences) usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        [arrayOfChars addObject:substring];
    }];
    CGFloat charsOffsetTotal = 0;
    for (NSString *i in arrayOfChars){
        NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"Helvetica Neue" size:16.0f]};
        charsOffsetTotal += [i sizeWithAttributes:attributes].width;
    }
    return charsOffsetTotal;
}

Methods have changed since iOS 7.0 came out. Try this

- (CGFloat)charactersOffsetBeforeDayPartOfLabel {
    NSRange range = [[self stringFromDate:self.currentDate] rangeOfString:[NSString stringWithFormat:@"%i",[self dayFromDate:self.currentDate]]];
    NSString *chars = [[self stringFromDate:self.currentDate] substringToIndex:range.location];
    NSMutableArray *arrayOfChars = [[NSMutableArray alloc]init];
    [chars enumerateSubstringsInRange:NSMakeRange(0, [chars length]) options:(NSStringEnumerationByComposedCharacterSequences) usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        [arrayOfChars addObject:substring];
    }];
    CGFloat charsOffsetTotal = 0;
    for (NSString *i in arrayOfChars){
        NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"Helvetica Neue" size:16.0f]};
        charsOffsetTotal += [i sizeWithAttributes:attributes].width;
    }
    return charsOffsetTotal;
}
℡寂寞咖啡 2024-09-15 03:04:25

开始吧:

fileprivate let selfSizing = UILabel()

class DualColorLabel: UILabel
{
    var filled: UIColor?
    var unfilled: UIColor?
    var origin: String?
    var widths: [CGFloat] = []
    var fuckupLockup = false
    override var text: String? {
        didSet {
            if fuckupLockup {
                print ("SDBOFLAG-13822 wtf?")
            }
        }
    }
    func setupColorsAndText(filled: UIColor,
                    unfilled: UIColor)
    {
        self.filled = filled
        self.unfilled = unfilled
        guard let text = origin, text.count > 0 else {
            assertionFailure("usage error")
            return
        }
        guard font != nil else {
            usageError()
            return
        }
        for index in 1...text.count {
            let s = String.Index(utf16Offset: 0, in: text)
            let e = String.Index(utf16Offset: index, in: text)
            let beginning = text[s..<e]
            let p = String(beginning)
            
            selfSizing.font = font
            selfSizing.text = p
            let size = selfSizing.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
            let width = size.width
            widths.append(width)
        }
    }
    
    func setupfill(adjusted: CGRect)
    {
        assert(adjusted.origin.x <= 0, "fixed this code for fill in the middle: currently supported only fill at start")
        let endOffset = adjusted.width + adjusted.origin.x
        guard let font = self.font else {
            usageError()
            return
        }
        guard let origin = origin, let filled = filled,
              let unfilled = unfilled else {
            usageError()
            return
        }
        var idx = String.Index(utf16Offset: origin.count, in: origin)
        for (index, width) in widths.enumerated() {
            if endOffset < width {
                idx = String.Index(utf16Offset: index, in: origin)
                print ("SDBOFLAG-13822 index \(index) for text \(origin)")
                break
            }
        }
        let total = NSMutableAttributedString()
        do {
            let s = String.Index(utf16Offset: 0, in: origin)
            let beginning = origin[s..<idx]
            let p = String(beginning)
            print("SDBOFLAG-13822 filled text \(p)")
            let filledAttributes:
                [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor:
//                                                    UIColor.yellow,
                                                    filled,
                                                  NSAttributedString.Key.font:
                                                    font
                ]
            
            let filledPortion = NSAttributedString(string: p, attributes: filledAttributes)
            total.append(filledPortion)
        }
        let unfilledAttributes:
            [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor:
//                                                UIColor.blue,
                                              unfilled,
                                              NSAttributedString.Key.font: font]
        let e = String.Index(utf16Offset: origin.count, in: origin)
        let ending = origin[idx..<e]
        let str = String(ending)
        print("SDBOFLAG-13822 unfilled text \(str)")
        let unfilledPortion = NSAttributedString(string: str, attributes: unfilledAttributes)
        total.append(unfilledPortion)

        self.attributedText = total
        fuckupLockup = true
    }
    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

}

func usageError()
{
    assertionFailure("usage error")
}

根据提供的建议,片段的宽度计算将进入宽度数组。

Here ya go:

fileprivate let selfSizing = UILabel()

class DualColorLabel: UILabel
{
    var filled: UIColor?
    var unfilled: UIColor?
    var origin: String?
    var widths: [CGFloat] = []
    var fuckupLockup = false
    override var text: String? {
        didSet {
            if fuckupLockup {
                print ("SDBOFLAG-13822 wtf?")
            }
        }
    }
    func setupColorsAndText(filled: UIColor,
                    unfilled: UIColor)
    {
        self.filled = filled
        self.unfilled = unfilled
        guard let text = origin, text.count > 0 else {
            assertionFailure("usage error")
            return
        }
        guard font != nil else {
            usageError()
            return
        }
        for index in 1...text.count {
            let s = String.Index(utf16Offset: 0, in: text)
            let e = String.Index(utf16Offset: index, in: text)
            let beginning = text[s..<e]
            let p = String(beginning)
            
            selfSizing.font = font
            selfSizing.text = p
            let size = selfSizing.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
            let width = size.width
            widths.append(width)
        }
    }
    
    func setupfill(adjusted: CGRect)
    {
        assert(adjusted.origin.x <= 0, "fixed this code for fill in the middle: currently supported only fill at start")
        let endOffset = adjusted.width + adjusted.origin.x
        guard let font = self.font else {
            usageError()
            return
        }
        guard let origin = origin, let filled = filled,
              let unfilled = unfilled else {
            usageError()
            return
        }
        var idx = String.Index(utf16Offset: origin.count, in: origin)
        for (index, width) in widths.enumerated() {
            if endOffset < width {
                idx = String.Index(utf16Offset: index, in: origin)
                print ("SDBOFLAG-13822 index \(index) for text \(origin)")
                break
            }
        }
        let total = NSMutableAttributedString()
        do {
            let s = String.Index(utf16Offset: 0, in: origin)
            let beginning = origin[s..<idx]
            let p = String(beginning)
            print("SDBOFLAG-13822 filled text \(p)")
            let filledAttributes:
                [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor:
//                                                    UIColor.yellow,
                                                    filled,
                                                  NSAttributedString.Key.font:
                                                    font
                ]
            
            let filledPortion = NSAttributedString(string: p, attributes: filledAttributes)
            total.append(filledPortion)
        }
        let unfilledAttributes:
            [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor:
//                                                UIColor.blue,
                                              unfilled,
                                              NSAttributedString.Key.font: font]
        let e = String.Index(utf16Offset: origin.count, in: origin)
        let ending = origin[idx..<e]
        let str = String(ending)
        print("SDBOFLAG-13822 unfilled text \(str)")
        let unfilledPortion = NSAttributedString(string: str, attributes: unfilledAttributes)
        total.append(unfilledPortion)

        self.attributedText = total
        fuckupLockup = true
    }
    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

}

func usageError()
{
    assertionFailure("usage error")
}

The width calculation for fragments goes into widths array per suggestions provided.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文