I have a UITextView
which display a paragraph. For example:
self.myTextView.text = @"This is a sample paragraph"
What I want to do now is when I touch up a word in this paragraph, such as "This", a function will be call: [self aFunction:@"This"]
Are there any ideas for handling this event and the way to get the parameter, which is the word user touched. Maybe, I need other way to display the paragraph, not by a UITextView
.
In following example use (UITextView
)
I created a simple UILabel subclass that allows me to set the inset value:
#import "WWLabel.h"
#define WWLabelDefaultInset 5
@implementation WWLabel
@synthesize topInset, leftInset, bottomInset, rightInset;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.topInset = WWLabelDefaultInset;
self.bottomInset = WWLabelDefaultInset;
self.rightInset = WWLabelDefaultInset;
self.leftInset = WWLabelDefaultInset;
}
return self;
}
- (void)drawTextInRect:(CGRect)rect
{
UIEdgeInsets insets = {self.topInset, self.leftInset,
self.bottomInset, self.rightInset};
return [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
Then I created a UIView subclass that contained my custom label, and on tap constructed the size of the text for each word in the label, until the size exceeded that of the tap location - this is the word that was tapped. It's not prefect, but works well enough for now.
I then used a simple NSAttributedString to highlight the text:
#import "WWPhoneticTextView.h"
#import "WWLabel.h"
#define WWPhoneticTextViewInset 5
#define WWPhoneticTextViewDefaultColor [UIColor blackColor]
#define WWPhoneticTextViewHighlightColor [UIColor yellowColor]
#define UILabelMagicTopMargin 5
#define UILabelMagicLeftMargin -5
@implementation WWPhoneticTextView {
WWLabel *label;
NSMutableAttributedString *labelText;
NSRange tappedRange;
}
// ... skipped init methods, very simple, just call through to configureView
- (void)configureView
{
if(!label) {
tappedRange.location = NSNotFound;
tappedRange.length = 0;
label = [[WWLabel alloc] initWithFrame:[self bounds]];
[label setLineBreakMode:NSLineBreakByWordWrapping];
[label setNumberOfLines:0];
[label setBackgroundColor:[UIColor clearColor]];
[label setTopInset:WWPhoneticTextViewInset];
[label setLeftInset:WWPhoneticTextViewInset];
[label setBottomInset:WWPhoneticTextViewInset];
[label setRightInset:WWPhoneticTextViewInset];
[self addSubview:label];
}
// Setup tap handling
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(handleSingleTap:)];
singleFingerTap.numberOfTapsRequired = 1;
[self addGestureRecognizer:singleFingerTap];
}
- (void)setText:(NSString *)text
{
labelText = [[NSMutableAttributedString alloc] initWithString:text];
[label setAttributedText:labelText];
}
- (void)handleSingleTap:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
// Get the location of the tap, and normalise for the text view (no margins)
CGPoint tapPoint = [sender locationInView:sender.view];
tapPoint.x = tapPoint.x - WWPhoneticTextViewInset - UILabelMagicLeftMargin;
tapPoint.y = tapPoint.y - WWPhoneticTextViewInset - UILabelMagicTopMargin;
// Iterate over each word, and check if the word contains the tap point in the correct line
__block NSString *partialString = @"";
__block NSString *lineString = @"";
__block int currentLineHeight = label.font.pointSize;
[label.text enumerateSubstringsInRange:NSMakeRange(0, [label.text length]) options:NSStringEnumerationByWords usingBlock:^(NSString* word, NSRange wordRange, NSRange enclosingRange, BOOL* stop){
CGSize sizeForText = CGSizeMake(label.frame.size.width-2*WWPhoneticTextViewInset, label.frame.size.height-2*WWPhoneticTextViewInset);
partialString = [NSString stringWithFormat:@"%@ %@", partialString, word];
// Find the size of the partial string, and stop if we've hit the word
CGSize partialStringSize = [partialString sizeWithFont:label.font constrainedToSize:sizeForText lineBreakMode:label.lineBreakMode];
if (partialStringSize.height > currentLineHeight) {
// Text wrapped to new line
currentLineHeight = partialStringSize.height;
lineString = @"";
}
lineString = [NSString stringWithFormat:@"%@ %@", lineString, word];
CGSize lineStringSize = [lineString sizeWithFont:label.font constrainedToSize:label.frame.size lineBreakMode:label.lineBreakMode];
lineStringSize.width = lineStringSize.width + WWPhoneticTextViewInset;
if (tapPoint.x < lineStringSize.width && tapPoint.y > (partialStringSize.height-label.font.pointSize) && tapPoint.y < partialStringSize.height) {
NSLog(@"Tapped word %@", word);
if (tappedRange.location != NSNotFound) {
[labelText addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:tappedRange];
}
tappedRange = wordRange;
[labelText addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:tappedRange];
[label setAttributedText:labelText];
*stop = YES;
}
}];
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With