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];
    }
}