Подтвердить что ты не робот

CGRect для выбранной настройки UITextRange для многострочного текста?

Я использовал этот ответ, чтобы создать CGRect для определенного диапазона текста.

В этом UITextView я установил его attributedText (поэтому у меня есть куча стилизованного текста с разными размерами глифов).

Это отлично подходит для первой строки текста, выровненной по горизонтали, но при работе с NSTextAlignmentJustified или NSTextAlignmentCenter она имеет некоторые странные результаты.

Он также неправильно вычисляет, когда строки обтекают или (иногда), если есть разрыв строки \n.

Я получаю такие вещи (это выравнивание по центру):

enter image description here

Вместо этого я ожидаю этого:

enter image description here

У этого есть разрыв строки \n - первые два кодовых бита были выделены успешно, но последний more code for you to see был не потому, что перенос текста не учитывается в вычислениях x, y.

Здесь моя реализация:

- (void)formatMarkdownCodeBlockWithAttributes:(NSDictionary *)attributesDict
                      withHighlightProperties:(NSDictionary *)highlightProperties
                               forFontSize:(CGFloat)pointSize
{
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"`.+?`" options:NO error:nil];
    NSArray *matchesArray = [regex matchesInString:[self.attributedString string] options:NO range:NSMakeRange(0, self.attributedString.length)];
    for (NSTextCheckingResult *match in matchesArray)
    {
        NSRange range = [match range];
        if (range.location != NSNotFound) {

            self.textView.attributedText = self.attributedString;

            CGRect codeRect = [self frameOfTextRange:range forString:[[self.attributedString string] substringWithRange:range] forFontSize:pointSize];
            UIView *highlightView = [[UIView alloc] initWithFrame:codeRect];
            highlightView.layer.cornerRadius = 4;
            highlightView.layer.borderWidth = 1;
            highlightView.backgroundColor = [highlightProperties valueForKey:@"backgroundColor"];
            highlightView.layer.borderColor = [[highlightProperties valueForKey:@"borderColor"] CGColor];
            [self.contentView insertSubview:highlightView atIndex:0];

            [self.attributedString addAttributes:attributesDict range:range];

            //strip first and last `
            [[self.attributedString mutableString] replaceOccurrencesOfString:@"(^`|`$)" withString:@" " options:NSRegularExpressionSearch range:range];
        }
    }
}

- (CGRect)frameOfTextRange:(NSRange)range forString:(NSString *)string forFontSize:(CGFloat)pointSize
{
    self.textView.selectedRange = range;
    UITextRange *textRange = [self.textView selectedTextRange];
    CGRect rect = [self.textView firstRectForRange:textRange];
    //These three lines are a workaround for getting the correct width of the string since I'm always using the monospaced Menlo font.
    rect.size.width = ((pointSize / 1.65) * string.length) - 4;
    rect.origin.x+=2;
    rect.origin.y+=2;
    return rect;
}

О, и в случае, если вы этого хотите, вот строка, в которую я играю:

*This* is **awesome** @mention `code` more \n `code and code` #hashtag [markdown](http://google.com) __and__ @mention2 {#FFFFFF|colored text} This**will also** work but ** will not ** **work** Also, some `more code for you to see`

Примечание: Пожалуйста, не предлагайте использовать TTTAttributedLabel или OHAttributedLabel.

4b9b3361

Ответ 1

Я думаю, что все ваши проблемы вызваны неправильным порядком инструкций.

Вы должны

  • Установить текст.
  • Найти необходимые подстроки и добавить к ним определенные атрибуты
  • И только потом выделите строки с subviews.

Кроме того, вам не нужно использовать "обходной путь для получения правильной ширины строки, поскольку я всегда использую шрифт Menospace Menlo" в таком случае.

Я немного упростил ваш код, чтобы сделать его более понятным.

Результат: enter image description here

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSDictionary *basicAttributes = @{ NSFontAttributeName : [UIFont boldSystemFontOfSize:18],
                                       NSForegroundColorAttributeName : [UIColor blackColor] };
    NSDictionary *attributes = @{ NSFontAttributeName : [UIFont systemFontOfSize:15],
                                  NSForegroundColorAttributeName : [UIColor darkGrayColor]};


    _textView.attributedText = [[NSAttributedString alloc] initWithString:
                                @"*This* is **awesome** @mention `code` more \n `code and code` #hashtag [markdown](http://google.com) __and__ @mention2 {#FFFFFF|colored text} This**will also** work but ** will not ** **work** Also, some `more code for you to see`" attributes:attributes];
    _textView.textAlignment = NSTextAlignmentCenter;

    [self formatMarkdownCodeBlockWithAttributes:basicAttributes];
}

- (void)formatMarkdownCodeBlockWithAttributes:(NSDictionary *)attributesDict
{
    NSMutableString *theString = [_textView.attributedText.string mutableCopy];
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"`.+?`" options:NO error:nil];
    NSArray *matchesArray = [regex matchesInString:theString options:NO range:NSMakeRange(0, theString.length)];

    NSMutableAttributedString *theAttributedString = [_textView.attributedText mutableCopy];
    for (NSTextCheckingResult *match in matchesArray)
    {
        NSRange range = [match range];
        if (range.location != NSNotFound) {
            [theAttributedString addAttributes:attributesDict range:range];
        }
    }

    _textView.attributedText = theAttributedString;

    for (NSTextCheckingResult *match in matchesArray)
    {
        NSRange range = [match range];
        if (range.location != NSNotFound) {

            CGRect codeRect = [self frameOfTextRange:range];
            UIView *highlightView = [[UIView alloc] initWithFrame:codeRect];
            highlightView.layer.cornerRadius = 4;
            highlightView.layer.borderWidth = 1;
            highlightView.backgroundColor = [UIColor yellowColor];
            highlightView.layer.borderColor = [[UIColor redColor] CGColor];
            [_textView insertSubview:highlightView atIndex:0];
        }
    }
}

- (CGRect)frameOfTextRange:(NSRange)range
{
    self.textView.selectedRange = range;
    UITextRange *textRange = [self.textView selectedTextRange];
    CGRect rect = [self.textView firstRectForRange:textRange];
    return rect;
}

Ответ 2

Мне просто нужно было сделать что-то подобное этому. Предполагая, что вы используете iOS 7:

// Build the range that you want for your text
NSRange range = NSMakeRange(location, length);

// Get the substring of the attributed text at that range
NSAttributedString *substring = [textView.attributedText attributedSubstringFromRange:range];

// Find the frame that would enclose the substring of text.
CGRect frame = [substring boundingRectWithSize:maxSize
                                           options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                           context:nil];

Это должно использовать NSTextAlignment, назначенный для атрибутной строки.

Ответ 3

Как @Avt ответил fooobar.com/info/412174/... на этот вопрос. Я просто отвечаю за проблему новой строки. Эта проблема с новой строкой возникает в iOS 7+, даже если вы используете

[self.textView selectedTextRange] or [self.textView positionFromPosition: offset:]

Мы просто должны обеспечить компоновку textView перед вызовом firstRectForRange на

[self.textView.layoutManager ensureLayoutForTextContainer:self.textView.textContainer];

Предоставлено: fooobar.com/info/412175/...

P.S: Сначала я добавил это как комментарий к вопросу. Поскольку большинство людей не читают комментарии, я добавил это как ответ.