關於textfield輸入框光標位置的記錄

問題背景:

爲了作特殊字符輸入,作了獲取和設置光標位置的功能,經過selectedTextRange屬性來實現的,在iOS11上測試,一切沒問題,代碼以下c++

- (void)setCursorPosition:(int)position {
    NSRange range = NSMakeRange(position, 0);
    [self setSelectedRange:range];
}

- (int)getCursorPosition {
    NSRange range = [self selectedRange];
    NSUInteger position = range.location + range.length;
    
    return (int)position;
}

- (NSRange) selectedRange
{
    UITextPosition* beginning = self.beginningOfDocument;
    
    UITextRange* selectedRange = self.selectedTextRange;
    UITextPosition* selectionStart = selectedRange.start;
    UITextPosition* selectionEnd = selectedRange.end;
    
    NSInteger location = [self offsetFromPosition:beginning toPosition:selectionStart];
    NSInteger length = [self offsetFromPosition:selectionStart toPosition:selectionEnd];
    
    return NSMakeRange(location, length);
}

- (void) setSelectedRange:(NSRange) range
{
    UITextPosition* beginning = self.beginningOfDocument;
    
    UITextPosition* startPosition = [self positionFromPosition:beginning offset:range.location];
    UITextPosition* endPosition = [self positionFromPosition:beginning offset:range.location + range.length];
    UITextRange* selectionRange = [self textRangeFromPosition:startPosition toPosition:endPosition];
    
    [self setSelectedTextRange:selectionRange];
}

- (void)setText:(NSString *)text {
    if (![text isEqualToString:self.text]) {
        UITextRange *selection = self.selectedTextRange;
        NSInteger oldTextLength = self.text.length;
        [super setText:text];
        if (selection.empty) {
            // maintain cursor position relative to the end of the old text
            NSInteger start = [self offsetFromPosition:self.beginningOfDocument toPosition:selection.start];
            NSInteger offsetFromEnd = oldTextLength - start;
            NSInteger newOffset = text.length - offsetFromEnd;
            UITextPosition *position = [self positionFromPosition:self.beginningOfDocument offset:newOffset];
            [self setSelectedTextRange:[self textRangeFromPosition:position toPosition:position]];
        }
    }
}

後來發如今IOS9和iOS8上面獲取/設置光標位置都有問題,具體表現爲:objective-c

當輸入框處於激活狀態的時候,能夠正常獲取/設置,可是鍵盤消失的時候,無論怎麼設置,selectedTextRange返回的一直是nil,致使光標位置一直爲0。測試

這個問題描述看起來很簡單清晰,但我倒是通過一輪輪排查才總結出來,由於剛開始直觀的懷疑是lua中sdk業務和c++包裝的邏輯裏面有鬼致使, 這也是個血的教訓,之後再遇到相似問題,必定要先寫個簡單Demo進行嘗試。lua

排查過程

剛開始懷疑是上層業務邏輯代碼有鬼,因此在原生打斷點觀察不一樣系統下的執行狀況,而後真的發現了區別:日誌

iOS11:鍵盤消失的時候,什麼也沒發生;code

iOS9/iOS8: 鍵盤消失的時候,會執行setText方法,一頓調查後,發現是iOS系統的處理,調用棧以下:內存

frame #0: 0x000d7ac8 UITest`-[XYTextField setText:](self=0x1659e200, _cmd="setText:", text=0x165d91b0) at XYTextField.m:60
    frame #1: 0x2685ea9a UIKit`-[UITextField _endedEditing] + 170
    frame #2: 0x2685e918 UIKit`-[UITextField willDetachFieldEditor:] + 128
    frame #3: 0x2674172c UIKit`-[UIFieldEditor becomeFieldEditorForView:] + 320
    frame #4: 0x2685e6c0 UIKit`-[UITextField _resignFirstResponder] + 228
    frame #5: 0x26835ff8 UIKit`-[UIResponder _finishResignFirstResponder] + 260
    frame #6: 0x27035532 UIKit`-[UITextField _finishResignFirstResponder] + 42
    frame #7: 0x267d731a UIKit`-[UIResponder resignFirstResponder] + 278
    frame #8: 0x2685e424 UIKit`-[UITextField resignFirstResponder] + 128

到此,直觀判斷,是因爲低版本系統多了一步setText致使光標位置失效;再次,因爲個人粗心,繼續懷疑到這個setText是由業務層引發的,而後作了各類排查和無謂的鬥爭….文檔

最後,才決定寫個簡單Demo進行驗證,才最終肯定setText是系統行爲引發,而且在setText內部實現先後打印日誌,發現執行先後的光標位置都是0,證實和setText沒有關係,對個人直觀判斷進行了啪啪打臉~get

既然和setText無關,那就只能是和輸入框的狀態有關了,爲了證實,我監聽了下面兩個回調:cmd

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    NSLog(@"CursorPosition:%d", [_textField getCursorPosition]);
    return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    NSLog(@"CursorPosition:%d", [_textField getCursorPosition]);
}

在should的回調中輸出正確,在did中輸出爲0,至此我纔有了最終的結論:

低版本系統上,輸入框非激活狀態下,selectedTextRange無效。簡單實驗,發現確實如此。

解決方案

在蘋果文檔沒有看到相關介紹,網上也沒有找到方案,最終決定放棄實時獲取光標位置,換成內存記錄的方式:

在textFieldShouldEndEditing或者輸入內容變化的時候(根據具體需求)獲取光標位置並進行記錄,供後續特殊字符的輸入使用。

總結

本次解決問題雖然時間不是特別長(半天時間),可是整個過程能夠說很是的業餘和不專業; 雖然工做遇到的各類問題愈來愈多,可是基礎分析解決問題的能力,仍是要注意的。

自我安慰,這種狀況跟如今工做涉及技術類型比較雜,業務複雜度高有關係。 之後的工做中,注意方式方法,多總結吧~

相關文章
相關標籤/搜索