How do you make a UITextView detect link part in the text and still have userInteractionDisabled?

前端 未结 3 941
遇见更好的自我
遇见更好的自我 2020-12-19 03:08

I have a textView that is layered on a tableView cell. I need the user to click on the tableView row to open a viewController but if the textView has a link it must be click

相关标签:
3条回答
  • 2020-12-19 03:40

    One possible (and complex) solution would be using UIViews with UITapGestureRecogniser inside your UITextView.

    • Firstly, you will need to find the NSRange of your link.

    • Convert NSRange to UITextRange

    • Use code similar to the following to add a UITapGestureRecogniser right on top of the link-text in your UITextView.

      UITextPosition *pos = textView.endOfDocument;// textView ~ UITextView
      
      for (int i = 0; i < words*2 - 1; i++){// *2 since UITextGranularityWord considers a whitespace to be a word
      
          UITextPosition *pos2 = [textView.tokenizer positionFromPosition:pos toBoundary:UITextGranularityWord inDirection:UITextLayoutDirectionLeft];
          UITextRange *range = [textView textRangeFromPosition:pos toPosition:pos2];
          CGRect resultFrame = [textView firstRectForRange:(UITextRange *)range ];
      
          UIView* tapViewOnText = [[UIView alloc] initWithFrame:resultFrame];
          [tapViewOnText addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(targetRoutine)]];
          tapViewOnText.tag = 125;
          [textView addSubview:tapViewOnText];
          [tapViewOnText release];
      
          pos = pos2;
      

      }

    What I have done in this code is, got the UITextRange of relevant text, get it's firstRectForRange and added a transparent tap-able UIView right on top of it.

    You would have to get the range of your link using some regEx, convert it to UITextRange, and add tap-able UIViews over them. In case, there might be more than one link in a single textView you might add a tag to each view corresponding to their 'link', and open that link in the target method by checking it's tag.

    NOTE: If your UITextViews are universally un-editable, you might want to try TTTAttributedLabel instead. That is what I do in my UITableViewCells

    0 讨论(0)
  • 2020-12-19 03:45

    If you are trying to add a UITextView with links to a cell, and want didSelectRow to be called when the user taps on anything but the link, then you should use hitTest:withEvent:

    Swift 3

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // location of the tap
        var location = point
        location.x -= self.textContainerInset.left
        location.y -= self.textContainerInset.top
    
        // find the character that's been tapped
        let characterIndex = self.layoutManager.characterIndex(for: location, in: self.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        if characterIndex < self.textStorage.length {
            // if the character is a link, handle the tap as UITextView normally would
            if (self.textStorage.attribute(NSLinkAttributeName, at: characterIndex, effectiveRange: nil) != nil) {
                return self
            }
        }
    
        // otherwise return nil so the tap goes on to the next receiver
        return nil
    }
    

    I wrote an article about this with a bit more details.

    0 讨论(0)
  • 2020-12-19 03:47

    Maybe it will be ok for your purposes:

    textView.editable=NO;
    textView.userInteractionEnabled=YES;
    textView.dataDetectorTypes =UIDataDetectorTypeLink;
    

    But in fact UITextView uses UIWebView parts internally, and this way may be slowly in table cells. enter image description here

    I can advice to use CoreText or NSAttributedString's with touches. For example you may read this SO post.

    0 讨论(0)
提交回复
热议问题