UILabel touch и получить текст, который коснулся

У меня есть UILabel, у которого есть текстовые и 2-месячные имена, такие как "В январе и июле солнечный блеск будет пиком" Я подклассифицировал UILabel и добавил к нему событие touch. Теперь я хочу получить слово под текстом, где пользователь коснулся и узнать, коснулся ли пользователь январь/июль или нет. Возможно ли это?

Ответ 1

Я думаю, вы найдете то, что ищете в документации для UITextInputProtocol.

Для получения более подробной информации посетите веб-сайт Apple "Руководство по редактированию текста, Интернета и редактирования" , в частности, в разделе "Экскурсия по UITextInput реализации". В нем обсуждается, как вы можете создавать индексированные позиции в тексте и спрашивать, касается какой позиции текста они приземлились ближе всего.

Apple ссылается на образец, спроецированный под названием SimpleTextInput, но я не могу его найти. Я буду продолжать искать.

Ответ 2

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

Просто я подклассифицировал UILabel, добавив touchEnded, чтобы распознать позицию касания и положение букв.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
  UITouch *touch = [[touches allObjects] objectAtIndex:0];
  CGPoint pos    = [touch locationInView:self];

  int sizes[self.text.length];
  for ( int i=0; i<self.text.length; i++ )
  {
    char letter         = [self.text characterAtIndex:i];
    NSString *letterStr = [NSString stringWithFormat:@"%c", letter];

    CGSize letterSize   = [letterStr sizeWithFont:self.font];
    sizes[i]            = letterSize.width;
  }

  int sum = 0;
  for ( int i=0; i<self.text.length; i++)
  {
    sum += sizes[i];
    if ( sum >= pos.x )
    {
      [ _delegate didLetterFound:[ self.text characterAtIndex:i] ];
      return;
    }
  }
}

Надеюсь, что это поможет веселит.

Ответ 3

Я справился с этой проблемой, поставив трансапарентные UIView на вершине UILabel, которые были подключены для обработки событий касания. Вы можете отрегулировать положение и размер ярлыков зоны вызова, вычислив размер соответствующих частей текста. Этот подход также имеет то преимущество, что вы можете настроить размеры зон попадания, чтобы сделать их более крупными и так легче нажимать жирными пальцами.

Ответ 4

У меня была аналогичная проблема с оригинальным плакатом. Я хотел, чтобы пользователь имел возможность долгое нажатие на UILabel, который показывал список строк, разделенных запятыми, и извлекал подстроку, соответствующую местоположению касания между ближайшими закрывающими запятыми.

Проблема в том, что UILabel не реализует протокол UITextInput, иначе реализация была бы простой.

Мне не нравились какие-либо из предложенных обходных решений, которые я нашел, поэтому я решил придумать свое решение. После некоторых размышлений и исследований я понял, что, хотя UILabel не поддерживает UITextInput, UITextView делает. Я не хотел заменять все UILabels в пользовательском интерфейсе с помощью UITextViews, поэтому я подумал: "Почему бы не программно создать UITextView за кулисами, с теми же параметрами рендеринга текста и использовать его методы UITextInput для сопоставления точки касания с нужная подстрока?".

Это оказалось идеальным решением с моей точки зрения.

Я подключил UILongPressGestureRecognizer к UILabels и вызвал следующую функцию в обработчике жестов:

-(NSString*)commaDelineatedTextAtTouchPosition:(UILongPressGestureRecognizer*)longPress
{
    UILabel *gestureRecipient = (UILabel*)longPress.view;
    UITextView *textRegionClone = [[UITextView alloc] initWithFrame:gestureRecipient.frame];

    // tweak the text view content area to get the same rendering (placement and wrapping)
    textRegionClone.textContainerInset = UIEdgeInsetsMake(0.0, -5.0, 0.0, -5.0);
    // copy the label text properties
    textRegionClone.text = gestureRecipient.text;
    textRegionClone.font = gestureRecipient.font;
    [textRegionClone setNeedsDisplay];
    CGPoint loc = [longPress locationInView:gestureRecipient];
    UITextPosition *charR = [textRegionClone closestPositionToPoint:loc];

    id<UITextInputTokenizer> tokenizer = textRegionClone.tokenizer;
    UITextRange *searchRange = [tokenizer rangeEnclosingPosition:charR withGranularity:UITextGranularityCharacter inDirection:UITextStorageDirectionBackward];
    NSString *commaEnclosedText = @"";

    if (searchRange != nil) {
        NSString *tapChar = [textRegionClone textInRange:searchRange];

        if ([tapChar isEqualToString:@","]) { // tapped right on a ","
            // move the end of the range to immediately before the ","
            searchRange = [textRegionClone textRangeFromPosition:searchRange.start toPosition:[textRegionClone positionFromPosition:searchRange.end offset:-1]];
        }

        UITextPosition *docStart = textRegionClone.beginningOfDocument;

        // search back to find the leading comma or the beginning of the text
        do {
            searchRange = [textRegionClone textRangeFromPosition:[textRegionClone positionFromPosition:searchRange.start offset:-1] toPosition:searchRange.end];
            commaEnclosedText = [textRegionClone textInRange:searchRange];
        }
        while (([searchRange.start isEqual:docStart] == NO) && ([commaEnclosedText characterAtIndex:0] != ','));

        // now search forward to the trailing comma or the end of the text
        UITextPosition *docEnd = textRegionClone.endOfDocument;

        while (([searchRange.end isEqual:docEnd] == NO) && ([commaEnclosedText characterAtIndex:commaEnclosedText.length - 1] != ',')) {
            searchRange = [textRegionClone textRangeFromPosition:searchRange.start toPosition:[textRegionClone positionFromPosition:searchRange.end offset:1]];
            commaEnclosedText = [textRegionClone textInRange:searchRange];
        }

        commaEnclosedText = [[commaEnclosedText stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    }

    return commaEnclosedText;
}

Единственное, что немного взломано в этом методе - это то, что вам нужно вручную настроить рендеринг в UITextView, отредактировав область textContainerInset. В противном случае вы не получите точно такую ​​же упаковку и размещение текста в UITextView, как в UILabel. В противном случае это достаточно общий код, который должен работать для кого-либо еще.

Ответ 5

 
- (void)tapped:(UITapGestureRecognizer *)tap
{
    CGPoint location = [tap locationInView:_label];

    NSDictionary *attribute = @{NSFontAttributeName: _label.font};
    CGFloat width = 0;
    for (int i = 0; i substringWithRange:NSMakeRange(i, 1)];
        CGSize lettersize = [letterStr sizeWithAttributes:attribute];
        width += lettersize.width;
        if (width >= location.x ) {
            NSLog(@"str: %@", letterStr);
            break;
        }
    }
}