I have been searching this for hours but I\'ve failed. I probably don\'t even know what I should be looking for.
Many applications have text and in this text are web
Create the class with the following .h and .m files. In the .m file there is the following function
- (void)linkAtPoint:(CGPoint)location
Inside this function we will check the ranges of substrings for which we need to give actions. Use your own logic to put your ranges.
And following is the usage of the subclass
TaggedLabel *label = [[TaggedLabel alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[self.view addSubview:label];
label.numberOfLines = 0;
NSMutableAttributedString *attributtedString = [[NSMutableAttributedString alloc] initWithString : @"My name is @jjpp" attributes : @{ NSFontAttributeName : [UIFont systemFontOfSize:10],}];
//Do not forget to add the font attribute.. else it wont work.. it is very important
[attributtedString addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:NSMakeRange(11, 5)];//you can give this range inside the .m function mentioned above
following is the .h file
#import
@interface TaggedLabel : UILabel
@property(nonatomic, strong)NSLayoutManager *layoutManager;
@property(nonatomic, strong)NSTextContainer *textContainer;
@property(nonatomic, strong)NSTextStorage *textStorage;
@property(nonatomic, strong)NSArray *tagsArray;
@property(readwrite, copy) tagTapped nameTagTapped;
@end
following is the .m file
#import "TaggedLabel.h"
@implementation TaggedLabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.userInteractionEnabled = YES;
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
self.userInteractionEnabled = YES;
}
return self;
}
- (void)setupTextSystem
{
_layoutManager = [[NSLayoutManager alloc] init];
_textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
_textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedText];
// Configure layoutManager and textStorage
[_layoutManager addTextContainer:_textContainer];
[_textStorage addLayoutManager:_layoutManager];
// Configure textContainer
_textContainer.lineFragmentPadding = 0.0;
_textContainer.lineBreakMode = NSLineBreakByWordWrapping;
_textContainer.maximumNumberOfLines = 0;
self.userInteractionEnabled = YES;
self.textContainer.size = self.bounds.size;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!_layoutManager)
{
[self setupTextSystem];
}
// Get the info for the touched link if there is one
CGPoint touchLocation = [[touches anyObject] locationInView:self];
[self linkAtPoint:touchLocation];
}
- (void)linkAtPoint:(CGPoint)location
{
// Do nothing if we have no text
if (_textStorage.string.length == 0)
{
return;
}
// Work out the offset of the text in the view
CGPoint textOffset = [self calcGlyphsPositionInView];
// Get the touch location and use text offset to convert to text cotainer coords
location.x -= textOffset.x;
location.y -= textOffset.y;
NSUInteger touchedChar = [_layoutManager glyphIndexForPoint:location inTextContainer:_textContainer];
// If the touch is in white space after the last glyph on the line we don't
// count it as a hit on the text
NSRange lineRange;
CGRect lineRect = [_layoutManager lineFragmentUsedRectForGlyphAtIndex:touchedChar effectiveRange:&lineRange];
if (CGRectContainsPoint(lineRect, location) == NO)
{
return;
}
// Find the word that was touched and call the detection block
NSRange range = NSMakeRange(11, 5);//for this example i'm hardcoding the range here. In a real scenario it should be iterated through an array for checking all the ranges
if ((touchedChar >= range.location) && touchedChar < (range.location + range.length))
{
NSLog(@"range-->>%@",self.tagsArray[i][@"range"]);
}
}
- (CGPoint)calcGlyphsPositionInView
{
CGPoint textOffset = CGPointZero;
CGRect textBounds = [_layoutManager usedRectForTextContainer:_textContainer];
textBounds.size.width = ceil(textBounds.size.width);
textBounds.size.height = ceil(textBounds.size.height);
if (textBounds.size.height < self.bounds.size.height)
{
CGFloat paddingHeight = (self.bounds.size.height - textBounds.size.height) / 2.0;
textOffset.y = paddingHeight;
}
if (textBounds.size.width < self.bounds.size.width)
{
CGFloat paddingHeight = (self.bounds.size.width - textBounds.size.width) / 2.0;
textOffset.x = paddingHeight;
}
return textOffset;
}
@end