5

Ho il seguente codice e voglio rendere le parti del mio testo selezionabili e chiamare un altro UIViewController (non un sito Web).Aggiungere un evento click a un testo in ios NSString

NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"testing it out @clickhere"]; 
NSInteger length = str.length; 
[str addAttribute:NSForegroundColorAttributeName value:[UIColor bestTextColor] range:NSMakeRange(0,length)]; 

Il NSMutableAttributedString viene impostato su un UILabel in questo modo:

label.attributedText = str; 

cosa è il modo migliore per fare questo? Non riesco a trovare una grande risposta.

Un esempio di quello che voglio è supponiamo Ho un UILabel in questo modo con il seguente testo:

This is my label. Click here to go to UIViewController1 and then go to UIViewController1 by this #tag. 

voglio il testo "qui" per essere passato per il primo evento click e la parola "# tag "da passare allo stesso evento click.

+0

Vedere se questo lui lps: http://stackoverflow.com/questions/8811909/getting-the-word-touched-in-a-abelabel-uitextview/21577829#21577829 Prova anche questo: http://stackoverflow.com/questions/15293426/how -di-creare-uilabel-con-cliccabile-prima parola – iOSAaronDavid

+1

Perché duplicare: http://stackoverflow.com/questions/28018707/add-a-pag-gesture-to-a-part-of-a-uilabel? – Larme

risposta

7

Cosa succede se si è utilizzato il campo del valore per passare nella destinazione?

[attributedString addAttribute:NSLinkAttributeName 
         value:[@"destinationController1" stringByAppendingString:username] 
         range:range]; 

Quindi l'override del metodo delegato:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange 
{ 
    if ([URL.scheme isEqualToString:@"destinationController1"]) { 
     // Launch View controller 
     return NO; 
    } 
    return YES; 
} 
+1

La parte importante qui è usare un 'UITextView' piuttosto che un 'UILabel' .. E si potrebbe voler regolare alcune proprietà del textview per farlo comportare più come un'etichetta semplice, come disabilitare la modifica, selezionare e scorrere. –

+0

Entrambi questi file sono nel mio file .m corretto? – cdub

+0

Sì entrambi nel file .m, ma assicurati di iscriverti a UITextViewDelegate nel tuo file .h, in modo che il metodo venga chiamato in primo luogo. – scott

3

La mia soluzione richiede l'utilizzo di un UITextView (che è molto più semplice, e vi esorto che lo si utilizza, invece).

Swift

class ViewController: UIViewController { 
    @IBOutlet weak var textView:UITextView!; 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 
     let gestureRecognizer = UITapGestureRecognizer(target: self, action: "textViewTapped:"); 
     gestureRecognizer.numberOfTapsRequired = 1; 
     gestureRecognizer.numberOfTouchesRequired = 1; 
     self.textView.addGestureRecognizer(gestureRecognizer); 
    } 

    func textViewTapped(sender: UITapGestureRecognizer) { 
     let wordTarget = "here"; 

     let word = UITextView.getWordAtPosition(sender.locationInView(self.textView), textView: self.textView); 
     if word == wordTarget { 
      let plainString = self.textView.attributedText.string; 
      let substrings = NSMutableArray(); 
      let scanner = NSScanner(string: plainString); 
      scanner.scanUpToString("#", intoString: nil); 
      while !scanner.atEnd { 
       var substring:NSString? = nil; 
       scanner.scanString("#", intoString: nil); 
       let space = " "; 
       if scanner.scanUpToString(space, intoString: &substring) { 
        // If the space immediately followed the #, this will be skipped 
        substrings.addObject(substring!); 
       } 
       scanner.scanUpToString("#", intoString: nil); 
       //Scan all characters before next # 
      } 
      println(substrings.description); 
      //Now you got your substrings in an array, so use those for your data passing (in a segue maybe?) 
      ... 

     } 
    } 

} 

extension UITextView { 
    class func getWordAtPosition(position: CGPoint!, textView: UITextView!) -> String? { 
     //Remove scrolloffset 
     let correctedPoint = CGPointMake(position.x, textView.contentOffset.y + position.y); 
     //Get location in text from uitextposition at a certian point 
     let tapPosition = textView.closestPositionToPoint(correctedPoint); 
     //Get word at the position, will return nil if its empty. 
     let wordRange = textView.tokenizer.rangeEnclosingPosition(tapPosition, withGranularity: UITextGranularity.Word, inDirection: UITextLayoutDirection.Right.rawValue); 
     return textView.textInRange(wordRange!); 
    } 
} 

Objective-C

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view. 
    UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(textViewTapped:)]; 
    gestureRecognizer.numberOfTouchesRequired = 1; 
    gestureRecognizer.numberOfTapsRequired = 1; 
    [self.textView addGestureRecognizer:gestureRecognizer]; 
} 

- (void)textViewTapped:(UITapGestureRecognizer *)sender { 
    NSString *wordTarget = @"here"; 

    NSString* word = [self getWordAtPosition:[sender locationInView:self.textView] textView:self.textView]; 
    if ([word isEqualToString:wordTarget]) { 
     NSString *plainString = self.textView.attributedText.string; 
     NSMutableArray* substrings = [[NSMutableArray alloc]init]; 
     NSScanner *scanner = [[NSScanner alloc]initWithString:plainString]; 
     [scanner scanUpToString:@"#" intoString:nil]; 
     while (![scanner isAtEnd]) { 
      NSString* substring = nil; 
      [scanner scanString:@"#" intoString:nil]; 
      NSString* space = @" "; 
      if ([scanner scanUpToString:space intoString:&substring]) { 
       [substrings addObject:substring]; 
      } 
      [scanner scanUpToString:@"#" intoString:nil]; 
     } 

     //Now you got your substrings in an array, so use those for your data passing (in a segue maybe?) 
     ... 

    } 
} 

- (NSString*)getWordAtPosition:(CGPoint)position textView:(UITextView *)textView { 
    //remove scrollOffset 
    CGPoint correctedPoint = CGPointMake(position.x, textView.contentOffset.y + position.y); 
    UITextPosition *tapPosition = [textView closestPositionToPoint:correctedPoint]; 
    UITextRange *wordRange = [textView.tokenizer rangeEnclosingPosition:tapPosition withGranularity:UITextGranularityWord inDirection:UITextLayoutDirectionRight]; 
    return [textView textInRange:wordRange]; 
} 

Fondamentalmente è necessario aggiungere un sistema di riconoscimento gesto per ottenere il punto rubinetto di TextView. Quindi, ottieni la parola usando il metodo di categoria fornito nell'area di estensione. Dopo, verifichi quale parola è (dove vogliamo la parola "qui"). Quindi, raccogliamo gli hashtag che hai fornito.

Tutto ciò che dovete fare è aggiungere un metodo performSegueWithIdentifier e passarlo di conseguenza.

+0

c'è un modo per fare ciò ma ottenere l'intera riga invece della sola parola che si fa clic? – saboehnke

+0

Credo di sì sostituire il 'qui' in' let wordTarget = "qui"; 'invece con una frase. –

+0

Ho dato un colpo e non funziona. Raccoglie solo una parola quindi se dovessi avere la stessa parola nel testo, allora non sarà in grado di distinguere. – saboehnke

0

Swift 3:

Non controllare l'attributo URL.scheme. Restituito zero per me.

fare questo:

attributedString.addAttribute(NSLinkAttributeName, value: "openToViewController", range: range)

Quindi utilizzare l'attributo absoluteString sull'URL per verificare che il valore per la visualizzazione di scelta:

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool{ 
if (URL.absoluteString == "openToViewController") { 
    let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as! UIViewController 
    self.present(viewController, animated: true, completion: nil) 
    return false 
} 
return true 
} 
1

Oltre a @Nate Lee risposta, aggiornato l'estensione per la versione Swift 4.0:

extension UITextView { 
    class func getWordAtPosition(position: CGPoint!, textView: UITextView!) -> String? { 
    //Remove scrolloffset 
    let correctedPoint = CGPoint(x: position.x, y: (textView.contentOffset.y + position.y)) 
    //Get location in text from uitextposition at a certian point 
    let tapPosition = textView.closestPosition(to: correctedPoint) 
    //Get word at the position, will return nil if its empty. 
    let wordRange = textView.tokenizer.rangeEnclosingPosition(tapPosition!, with: .word, inDirection: UITextLayoutDirection.right.rawValue) 
    return textView.text(in: wordRange!) 
    } 
}