UITextView 上的 NSMutableAttributedString 不可点击
NSMutableAttributedString on UITextView not clickable
我有一个 UITextView 并且 String 设置了一个属性文本 "See More"。我还为 UITextView 添加了手势。在任何其他地方执行点击时手势有效,但在 "See More".
上点击时无效
我需要点击才能响应 "See More" 点击。
以下是我的实现方式:
//link text
NSDictionary *linkAttributes = @{ NSForegroundColorAttributeName : [UIColor colorWithRed:0.05 green:0.4 blue:0.65 alpha:1.0],
NSFontAttributeName : [UIFont fontWithName:@"Roboto-Regular" size:10.0],
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle) };
[attributedString setAttributes:linkAttributes range:linkRange];
self.classDesc.userInteractionEnabled = YES;
[self.classDesc addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleExpand:)]];
self.classDesc.selectable = YES;
// Assign attributedText to UILabel
self.classDesc.attributedText = attributedString;
下面是手势监听器:
- (void)handleExpand:(UITapGestureRecognizer *)tapGesture
{
self.classDesc.text = selectedClasses.classDescription;
[self textViewDidChange:self.classDesc];
CGSize sizeThatFitsTextView = [self.classDesc sizeThatFits:CGSizeMake(self.classDesc.frame.size.width, MAXFLOAT)];
self.descHeight.constant = sizeThatFitsTextView.height ;
}
非常感谢任何帮助。
试试这个
实施 UITextFieldDelegate 协议 在您的视图控制器中添加文本
@interface YourViewController () <UITextViewDelegate>
In viewDidLoad set yourself as a delegate:
yourUITextView.delegate = self;
// 实现下面的委托方法:
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
return NO;
}
下面两行代码被注释掉,然后"See More"上的touch就开始起作用了:
self.classDesc.textContainer.lineFragmentPadding = 0;
self.classDesc.textContainerInset = UIEdgeInsetsZero;
您可以使用 UILabel
,这里是如何做的,
首先为 UITapGestureRecognizer
创建一个类别 class 并添加以下方法,
/**
Returns YES if the tap gesture was within the specified range of the attributed text of the label.
*/
- (BOOL)didTapAttributedTextInLabel:(UILabel *)label inRange:(NSRange)targetRange {
NSParameterAssert(label != nil);
CGSize labelSize = label.bounds.size;
// create instances of NSLayoutManager, NSTextContainer and NSTextStorage
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];
// configure layoutManager and textStorage
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];
// configure textContainer for the label
textContainer.lineFragmentPadding = 0.0;
textContainer.lineBreakMode = label.lineBreakMode;
textContainer.maximumNumberOfLines = label.numberOfLines;
textContainer.size = labelSize;
// find the tapped character location and compare it to the specified range
CGPoint locationOfTouchInLabel = [self locationInView:label];
CGRect textBoundingBox = [layoutManager usedRectForTextContainer:textContainer];
CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
(labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
locationOfTouchInLabel.y - textContainerOffset.y);
NSInteger indexOfCharacter = [layoutManager characterIndexForPoint:locationOfTouchInTextContainer
inTextContainer:textContainer
fractionOfDistanceBetweenInsertionPoints:nil];
if (NSLocationInRange(indexOfCharacter, targetRange)) {
return YES;
} else {
return NO;
}
}
实施
//Global variables
NSString *longString = @"very very long string";
NSRange moreRange;
NSRange lessRange;
-(void)setReadLessDescriptionText{
self.lblDescription.userInteractionEnabled = YES;
[self.lblDescription addGestureRecognizer:
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTapMore:)]];
// create your attributed text and keep an variable of your "link" text range
NSAttributedString *plainText;
NSAttributedString *linkText;
plainText = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ ...", [longString substringWithRange:NSMakeRange(0, 200)]] attributes:nil];//here 200 is your character limit, it can be any value depending your requirement
linkText = [[NSMutableAttributedString alloc] initWithString:@"more"
attributes:@{
NSForegroundColorAttributeName:[UIColor blueColor]
}];
NSMutableAttributedString *attrText = [[NSMutableAttributedString alloc] init];
[attrText appendAttributedString:plainText];
[attrText appendAttributedString:linkText];
// Variable -- keep track of the target range so you can compare in the callback
moreRange = NSMakeRange(plainText.length, linkText.length);
self.lblDescription.attributedText = attrText;
}
-(void)setReadMoreDescriptionText{
self.lblDescription.userInteractionEnabled = YES;
[self.lblDescription addGestureRecognizer:
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTapLess:)]];
// create your attributed text and keep an variable of your "link" text range
NSAttributedString *plainText;
NSAttributedString *linkText;
plainText = [[NSMutableAttributedString alloc] initWithString:longString attributes:nil];
linkText = [[NSMutableAttributedString alloc] initWithString:@" less"
attributes:@{
NSForegroundColorAttributeName:[UIColor blueColor]
}];
NSMutableAttributedString *attrText = [[NSMutableAttributedString alloc] init];
[attrText appendAttributedString:plainText];
[attrText appendAttributedString:linkText];
// Variable -- keep track of the target range so you can compare in the callback
lessRange = NSMakeRange(plainText.length, linkText.length);
self.lblDescription.attributedText = attrText;
}
手势方法
- (void)handleTapMore:(UITapGestureRecognizer *)tapGesture {
BOOL didTapLink = [tapGesture didTapAttributedTextInLabel:self.lblDescription
inRange:moreRange];
if (didTapLink) {
[self setReadMoreDescriptionText];
}
}
- (void)handleTapLess:(UITapGestureRecognizer *)tapGesture {
BOOL didTapLink = [tapGesture didTapAttributedTextInLabel:self.lblDescription
inRange:lessRange];
if (didTapLink) {
[self setReadLessDescriptionText];
}
}
我有一个 UITextView 并且 String 设置了一个属性文本 "See More"。我还为 UITextView 添加了手势。在任何其他地方执行点击时手势有效,但在 "See More".
上点击时无效我需要点击才能响应 "See More" 点击。
以下是我的实现方式:
//link text
NSDictionary *linkAttributes = @{ NSForegroundColorAttributeName : [UIColor colorWithRed:0.05 green:0.4 blue:0.65 alpha:1.0],
NSFontAttributeName : [UIFont fontWithName:@"Roboto-Regular" size:10.0],
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle) };
[attributedString setAttributes:linkAttributes range:linkRange];
self.classDesc.userInteractionEnabled = YES;
[self.classDesc addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleExpand:)]];
self.classDesc.selectable = YES;
// Assign attributedText to UILabel
self.classDesc.attributedText = attributedString;
下面是手势监听器:
- (void)handleExpand:(UITapGestureRecognizer *)tapGesture
{
self.classDesc.text = selectedClasses.classDescription;
[self textViewDidChange:self.classDesc];
CGSize sizeThatFitsTextView = [self.classDesc sizeThatFits:CGSizeMake(self.classDesc.frame.size.width, MAXFLOAT)];
self.descHeight.constant = sizeThatFitsTextView.height ;
}
非常感谢任何帮助。
试试这个
实施 UITextFieldDelegate 协议 在您的视图控制器中添加文本
@interface YourViewController () <UITextViewDelegate>
In viewDidLoad set yourself as a delegate:
yourUITextView.delegate = self;
// 实现下面的委托方法:
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
return NO;
}
下面两行代码被注释掉,然后"See More"上的touch就开始起作用了:
self.classDesc.textContainer.lineFragmentPadding = 0;
self.classDesc.textContainerInset = UIEdgeInsetsZero;
您可以使用 UILabel
,这里是如何做的,
首先为 UITapGestureRecognizer
创建一个类别 class 并添加以下方法,
/**
Returns YES if the tap gesture was within the specified range of the attributed text of the label.
*/
- (BOOL)didTapAttributedTextInLabel:(UILabel *)label inRange:(NSRange)targetRange {
NSParameterAssert(label != nil);
CGSize labelSize = label.bounds.size;
// create instances of NSLayoutManager, NSTextContainer and NSTextStorage
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeZero];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];
// configure layoutManager and textStorage
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];
// configure textContainer for the label
textContainer.lineFragmentPadding = 0.0;
textContainer.lineBreakMode = label.lineBreakMode;
textContainer.maximumNumberOfLines = label.numberOfLines;
textContainer.size = labelSize;
// find the tapped character location and compare it to the specified range
CGPoint locationOfTouchInLabel = [self locationInView:label];
CGRect textBoundingBox = [layoutManager usedRectForTextContainer:textContainer];
CGPoint textContainerOffset = CGPointMake((labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
(labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y);
CGPoint locationOfTouchInTextContainer = CGPointMake(locationOfTouchInLabel.x - textContainerOffset.x,
locationOfTouchInLabel.y - textContainerOffset.y);
NSInteger indexOfCharacter = [layoutManager characterIndexForPoint:locationOfTouchInTextContainer
inTextContainer:textContainer
fractionOfDistanceBetweenInsertionPoints:nil];
if (NSLocationInRange(indexOfCharacter, targetRange)) {
return YES;
} else {
return NO;
}
}
实施
//Global variables
NSString *longString = @"very very long string";
NSRange moreRange;
NSRange lessRange;
-(void)setReadLessDescriptionText{
self.lblDescription.userInteractionEnabled = YES;
[self.lblDescription addGestureRecognizer:
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTapMore:)]];
// create your attributed text and keep an variable of your "link" text range
NSAttributedString *plainText;
NSAttributedString *linkText;
plainText = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ ...", [longString substringWithRange:NSMakeRange(0, 200)]] attributes:nil];//here 200 is your character limit, it can be any value depending your requirement
linkText = [[NSMutableAttributedString alloc] initWithString:@"more"
attributes:@{
NSForegroundColorAttributeName:[UIColor blueColor]
}];
NSMutableAttributedString *attrText = [[NSMutableAttributedString alloc] init];
[attrText appendAttributedString:plainText];
[attrText appendAttributedString:linkText];
// Variable -- keep track of the target range so you can compare in the callback
moreRange = NSMakeRange(plainText.length, linkText.length);
self.lblDescription.attributedText = attrText;
}
-(void)setReadMoreDescriptionText{
self.lblDescription.userInteractionEnabled = YES;
[self.lblDescription addGestureRecognizer:
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTapLess:)]];
// create your attributed text and keep an variable of your "link" text range
NSAttributedString *plainText;
NSAttributedString *linkText;
plainText = [[NSMutableAttributedString alloc] initWithString:longString attributes:nil];
linkText = [[NSMutableAttributedString alloc] initWithString:@" less"
attributes:@{
NSForegroundColorAttributeName:[UIColor blueColor]
}];
NSMutableAttributedString *attrText = [[NSMutableAttributedString alloc] init];
[attrText appendAttributedString:plainText];
[attrText appendAttributedString:linkText];
// Variable -- keep track of the target range so you can compare in the callback
lessRange = NSMakeRange(plainText.length, linkText.length);
self.lblDescription.attributedText = attrText;
}
手势方法
- (void)handleTapMore:(UITapGestureRecognizer *)tapGesture {
BOOL didTapLink = [tapGesture didTapAttributedTextInLabel:self.lblDescription
inRange:moreRange];
if (didTapLink) {
[self setReadMoreDescriptionText];
}
}
- (void)handleTapLess:(UITapGestureRecognizer *)tapGesture {
BOOL didTapLink = [tapGesture didTapAttributedTextInLabel:self.lblDescription
inRange:lessRange];
if (didTapLink) {
[self setReadLessDescriptionText];
}
}