2010-10-13 45 views
6

我正在爲iPad開發一個簡單的書寫應用程序。如何在UITextView中查找遊標的像素位置?

我在計算UITextView中游標的像素位置。我花了幾個星期的時間來設計這個,但我仍然無法想象要做到這一點。

在stackoverflow中,Tony寫了一個很好的算法來找到遊標的像素位置。

Pixel-Position of Cursor in UITextView

我實現了這個帶着些許的修改,它幾乎工程,它給光標的正確的像素位置。但是,它只適用於英文字母。

如果在行尾有中文或日文字符,則UITextView執行字符換行而不是換行,即使中文字符之間沒有空格。我認爲當UITextView只執行文字換行(用英文字母表示)時,Tony的算法才起作用。

有沒有其他方法可以在UITextView中找到光標的像素位置?

還是有一種方法來確定一個特定的字符是否如下字符的包裝像中國的文字或文字環繞喜歡英語嗎?

增加:

這是我的實現基於託尼的算法。我以橫向模式放置了一個UITextView,因此其寬度爲1024,我使用大小爲21的自定義字體。您應該適當更改sizeOfContentWidthsizeOfContentLinesizeOfContentWidth小於實際寬度,並且sizeOfContentLine大於實際字體大小(行高>字體大小)。

對不起,關於凌亂的代碼和意見!還有一些小錯誤,如果你在行尾輸入中文字符(沒有文字換行),它會給出錯誤的位置。

#define sizeOfContentWidth 1010 
#define sizeOfContentHeight 1000 
#define sizeOfContentLine 25 

    // Stores the original position of the cursor 
NSRange originalPosition = textView.selectedRange;  

// Computes textView's origin 
CGPoint origin = textView.frame.origin; 

// Checks whether a character right to the current cursor is a non-space character 
unichar c = ' '; 

if(textView.selectedRange.location != [textView.text length]) 
    c = [textView.text characterAtIndex:textView.selectedRange.location]; 

// If it's a non-space or newline character, then the current cursor moves to the end of that word 
if(c != 32 && c != 10){ 
    NSRange delimiter = [textView.text rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] 
                 options:NSLiteralSearch 
                 range:NSMakeRange(textView.selectedRange.location, [textView.text length] - textView.selectedRange.location)]; 

    if(delimiter.location == NSNotFound){ 
     delimiter.location = [textView.text length]; 
    } 

    textView.selectedRange = delimiter; 
} 

// Deviation between the original cursor location and moved location 
int deviationLocation = textView.selectedRange .location - originalPosition.location; 

// Substrings the part before the cursor position 
NSString* head = [textView.text substringToIndex:textView.selectedRange.location]; 

// Gets the size of this part 
CGSize initialSize = [head sizeWithFont:textView.font constrainedToSize:CGSizeMake(sizeOfContentWidth, sizeOfContentHeight)]; 

// Gets the length of the head 
NSUInteger startOfLine = [head length]; 

// The first line 
BOOL isFirstLine = NO; 

if(initialSize.height/sizeOfContentLine == 1){ 
    isFirstLine = YES; 
} 

while (startOfLine > 0 && isFirstLine == NO) { 
    // 1. Adjusts startOfLine to the beginning of the first word before startOfLine 
    NSRange delimiter = [head rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] options:NSBackwardsSearch range:NSMakeRange(0, startOfLine)]; 

    // Updates startsOfLine 
    startOfLine = delimiter.location; 

    // 2. Check if drawing the substring of head up to startOfLine causes a reduction in height compared to initialSize. 
    NSString *tempHead = [head substringToIndex:startOfLine]; 

    // Gets the size of this temp head 
    CGSize tempHeadSize = [tempHead sizeWithFont:textView.font constrainedToSize:CGSizeMake(sizeOfContentWidth, sizeOfContentHeight)]; 

    // Counts the line of the original 
    int beforeLine = initialSize.height/sizeOfContentLine; 

    // Counts the line of the one after processing 
    int afterLine = tempHeadSize.height/sizeOfContentLine; 

    // 3. If so, then you've identified the start of the line containing the cursor, otherwise keep going. 
    if(beforeLine != afterLine) 
     break; 
} 

// Substrings the part after the cursor position 
NSString* tail; 

if(isFirstLine == NO) 
    tail = [head substringFromIndex:(startOfLine + deviationLocation)]; 
else { 
    tail = [head substringToIndex:(startOfLine - deviationLocation)]; 
} 

// Gets the size of this part 
CGSize lineSize = [tail sizeWithFont:textView.font forWidth:sizeOfContentWidth lineBreakMode:UILineBreakModeWordWrap]; 

// Gets the cursor position in coordinate 
CGPoint cursor = origin;  
cursor.x += lineSize.width; 
cursor.y += initialSize.height - lineSize.height; 

// Back to the original position 
textView.selectedRange = originalPosition; 

// Debug 
printf("x: %f, y: %f\n", cursor.x, cursor.y); 
+1

你能分享你對託尼的進行的修改,因爲我敢肯定,許多人正在尋找如何找到光標/光標的像素位置的答案。謝謝。 – Joshua 2010-10-13 06:08:39

+0

嗨,我添加了基於Tony算法的實現。 Tony算法的一個補充是,在開始時,我將當前光標移動到單詞的末尾。 – pnmn 2010-10-13 06:57:25

+0

該算法基於UITextView僅進行單詞換行的假設。我認爲我們需要一種不同的方法來計算光標的正確像素位置,以使其適用於任何類型的角色。一種解決方案是,我們可以從頭開始使用CoreText,UITextInput和UIKeyInput來創建全新的自定義文本視圖,但我不想僅爲光標位置執行此操作。 – pnmn 2010-10-13 07:20:19

回答

0

這可能是相當低效的,但你可以採取通過每個個性,你已經張貼,並採取文本光標在的行的代碼相同的基本原理和循環做[NSString sizeWithFont:forWidth:lineBreakMode:]計算每個角色的寬度,你可以添加所有這些爲你的X位置?只是一個想法,但可能有助於解決與字換行問題。

2

如果定位到IOS7只有你可以使用 UITextView的方法:

- (CGRect)caretRectForPosition:(UITextPosition *)position; 

短採樣:

NSRange range; // target location in text that you should get from somewhere, e.g. textview.selectedRange 
UITextView textview; // the text view 

UITextPosition *start = [textview positionFromPosition:textview.beginningOfDocument offset:range.location]; 
CGRect caretRect = [self caretRectForPosition:start]; // caret rect in UITextView 
相關問題