2014-12-09 60 views
3

我想要輸入UITextView中的當前輸入單詞。可以在這裏找到一個獲得完整類型單詞的方法UITEXTVIEW: Get the recent word typed in uitextview,但是,我希望在輸入時輸入該單詞(不管它在哪裏輸入,UITextView的開頭,中間和結尾)。在UITextView中獲取當前輸入的單詞

我猜什麼定義正在鍵入一個單詞是一個空白字符後面的字母數字字符,或者如果當前位置(以某種方式與range.location弄清楚)是UITextView年初那麼無論採取後續行動應被視爲字作爲好。當另一個空格字符出現時,一個單詞完成輸入。

我試着用:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text` 

但我有一個問題,找到正確的範圍內。

總之:我需要在UITextView找到子字符串,其中子字符串是當前輸入的字。

編輯:因爲問題出現了。我使用NSLayoutManager並將NSTextContainer綁定到它,然後將其作爲layoutManager傳遞到NSTextStorage

EDIT2:與(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text的主要問題是,range.location是不一樣的指示燈,但總是1以下。如果光標位於位置1,輸入一個字母后,range.location將返回0.任何方式?此外,UITextViewtext屬性似乎也被關閉了1。當文本是foobar和我輸出UITextView.text時,我改爲fooba。因此range.location+1返回異常Range {0, 1} out of bounds; string length 0'

EDIT3: 也許更容易讓我與NSTextStorage代替UITextView通緝的結果?

+2

' - (BOOL)的TextView :(UITextView *)textView shouldChangeTextInRange:(NSRange)範圍replacementText:(NSString *)text'方法將一次給你單個字符的範圍,你必須一個接一個地做出最新的單詞 – 2014-12-09 13:13:03

+0

你想在哪裏顯示它?在標籤或?這將幫助我 – 2014-12-09 13:33:05

+0

你應該看看'UITextInputProtocol'。如果您在實施代碼時遇到任何問題,請告訴我。 – n00bProgrammer 2014-12-09 13:55:07

回答

1

UITextView委託方法:-textView:textView shouldChangeTextInRange:range replacementText:text有效的做法是詢問指定的文本是否應該在指定範圍textView.text的文本視圖中被替換。

每次我們在將文本更新到文本視圖前鍵入一個字符,都會調用此方法。這就是爲什麼當您輸入textView中的第一個字符時,您將range.location設置爲0。

只有當此方法的返回值爲真時,textView纔會更新,我們在textView中輸入的內容已更新。

這是由蘋果公司提供的-textView:textView shouldChangeTextInRange:range replacementText:text方法的參數的定義:

範圍: - 當前選擇範圍。如果範圍的長度爲0,則範圍反映當前插入點。如果用戶按下Delete鍵,則範圍的長度爲1,空字符串對象將替換該單個字符。
text: - 要插入的文本。

所以這是做什麼用的方法和您的要求的解釋可以像如下滿足:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text 
{ 
     //Un-commend this check below :If you want to detect the word only while new line or white space charactor input 
     //if ([text isEqualToString:@" "] || [text isEqualToString:@"\n"]) 
     //{ 
      // Getting the textView text upto the current editing location 
      NSString * stringToRange = [textView.text substringWithRange:NSMakeRange(0,range.location)]; 

      // Appending the currently typed charactor 
      stringToRange = [stringToRange stringByAppendingString:text]; 

      // Processing the last typed word 
      NSArray *wordArray  = [stringToRange componentsSeparatedByString:@" "]; 
      NSString * wordTyped  = [wordArray lastObject]; 

      // wordTyped will give you the last typed object 
      NSLog(@"\nWordTyped : %@",wordTyped); 
     //} 
     return YES; 
} 
+0

我以前見過這個解決方案,但不幸的是,它不太合適。當你輸出'wordTyped'時,你得到的單詞總是一個字符。所以,假設你只是輸入'foobar','NSLog'會輸出'foob'作爲'wordTyped'。 – user3607973 2014-12-09 18:30:41

+0

這就是我在開始時的想法,但這根本不起作用,並且在'UITextView'空白之前崩潰了應用程序,並且出現了越界異常 – user3607973 2014-12-09 18:47:42

+0

檢查更新的ans – Alexi 2014-12-09 19:01:30

0

您的range參數來自- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text委託方法指向您更改UITextView字符串值的確切位置。

該結構的location屬性指向不斷變化的字符串索引,這很簡單。 length通常不等於text.length,請注意,用戶可以從字符串中選擇字符以將其替換爲另一個字符串。

1
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text 
{ 
    NSString *string = [textView.text stringByReplacingCharactersInRange:range withString:text]; 

    if ([text isEqualToString:@"\n"] || [text isEqualToString:@" "]) 
    { 
     NSString *currentString = [string stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; 

     NSLog(@"currentWord==> %@",currentString); 
    } 

    return YES; 
} 
+0

我已經有了這個解決方案。然而,問題在於,在檢測到空白或換行符後,您會返回整個字符串。您不會找回當前鍵入的單詞,而是返回「NSTextContainer」中的整個字符串。 – user3607973 2014-12-09 17:15:29

7

下面是使用UITextInputUITextInputTokenizer給予字骨架結構的例子目前正在鍵入/編輯。

- (void) textViewDidChange:(UITextView *)textView { 

    NSRange selectedRange = textView.selectedRange; 

    UITextPosition *beginning = textView.beginningOfDocument; 
    UITextPosition *start = [textView positionFromPosition:beginning offset:selectedRange.location]; 
    UITextPosition *end = [textView positionFromPosition:start offset:selectedRange.length]; 

    UITextRange* textRange = [textView.tokenizer rangeEnclosingPosition:end withGranularity:UITextGranularityWord inDirection:UITextLayoutDirectionLeft]; 

    NSLog(@"Word that is currently being edited is : %@", [textView textInRange:textRange]); 
} 

這會給你整個當前正在鍵入。

例如,如果你打字輸入並鍵入INP它會給你INP。另外,如果你是在單詞中間的中間,將其更改爲midddle,它會給你midddle。這裏的技巧是標記化

我已將代碼放在textViewDidChange:的內部,以便您在之後得到這個單詞,它已被輸入/編輯。如果您希望之前最後一個字符發生變化(即即將更改的字),請將代碼放入textView:shouldChangeTextInRange:replacementText:

PS:您將不得不處理粘貼/刪除的句子和段落等邊緣案例。您可以修改此代碼以獲取字符/句子/段落等,而不是通過更改粒度來改變單詞。考慮的UITextGranularityENUM的聲明更多的選擇:

typedef NS_ENUM(NSInteger, UITextGranularity) { 
    UITextGranularityCharacter, 
    UITextGranularityWord, 
    UITextGranularitySentence, 
    UITextGranularityParagraph, 
    UITextGranularityLine, 
    UITextGranularityDocument 
}; 
+0

太好了,但它不適用於_UITextGranularityWord_和特殊字符:例如:「blabla **#myCurrentlyEditedWord ** blabla」,即返回「myCurrentlyEditedWord」而不帶**「#」**。 – Ded77 2016-01-13 17:32:41

+0

@ Ded77你是對的。這是因爲粒度適用於語言(我認爲,但我不確定)。 **#**,這裏是一個特殊字符。正如答案中的** PS **部分所述,您將不得不處理邊緣案例,這是一個邊緣案例。你可以做的一件事就是保持對最後一個字的範圍的引用,並將其**位置+範圍**與檢測到的當前字的**位置**進行比較。如果它們是相同的,那意味着它是一個單詞(hashtag,句柄等)。更簡單的方法是從主字符串中提取檢測到的單詞,並檢查它是否以**#/ @ **開頭。 – n00bProgrammer 2016-01-13 18:06:00

1

您可以簡單地擴展UITextView和使用下面的方法,它返回圍繞當前光標位置的字:

extension UITextView { 

    func editedWord() -> String { 

     let cursorPosition = selectedRange.location 
     let separationCharacters = NSCharacterSet(charactersInString: " ") 

     // Count how many actual characters there are before the cursor. 
     // Emojis/special characters can each increase selectedRange.location 
     // by 2 instead of 1 

     var unitCount = 0 
     var characters = 0 
     while unitCount < cursorPosition { 

      let char = text.startIndex.advancedBy(characters) 
      let int = text.rangeOfComposedCharacterSequenceAtIndex(char) 
      unitCount = Int(String(int.endIndex))! 
      characters += 1 
     } 


     let beginRange = Range(start: text.startIndex.advancedBy(0), end: text.startIndex.advancedBy(characters)) 
     let endRange = Range(start: text.startIndex.advancedBy(characters), end: text.startIndex.advancedBy(text.characters.count)) 

     let beginPhrase = text.substringWithRange(beginRange) 
     let endPhrase = text.substringWithRange(endRange) 

     let beginWords = beginPhrase.componentsSeparatedByCharactersInSet(separationCharacters) 
     let endWords = endPhrase.componentsSeparatedByCharactersInSet(separationCharacters) 

     return beginWords.last! + endWords.first! 
    } 
} 
+0

這與emojis崩潰,如何解決? – Tometoyou 2016-09-25 10:43:30

+0

不錯的解決方案。涵蓋用戶輸入下劃線/點時的情況。謝謝! – rkyr 2017-09-19 13:41:47