2010-10-13 8 views
6

मैं आईपैड के लिए एक साधारण लेखन ऐप विकसित कर रहा हूं।UITextView में एक कर्सर का पिक्सेल-पॉजिटन कैसे ढूंढें?

मैं UITextView में कर्सर की पिक्सेल-स्थिति की गणना करने की कोशिश कर रहा हूं। मैं इसे डिजाइन करने के लिए कुछ हफ्तों बिताता हूं, लेकिन मैं अभी भी इसे करने के लिए नहीं समझ पाया।

स्टैक ओवरफ्लो में, टोनी ने कर्सर की पिक्सेल-स्थिति खोजने के लिए एक अच्छा एल्गोरिदम लिखा था।

Pixel-Position of Cursor in UITextView

मैं एक छोटे संशोधन के साथ इस लागू किया, और यह लगभग काम करता है यह कर्सर का सही पिक्सेल स्थिति देता है कि। हालांकि, यह केवल अंग्रेजी अक्षरों के साथ काम करता है।

यदि लाइन के अंत में चीनी या जापानी चरित्र है, तो UITextView शब्द-रैपिंग के बजाय चरित्र-रैपिंग करता है, भले ही चीनी वर्णों के बीच कोई जगह न हो। मुझे लगता है कि टोनी का एल्गोरिदम काम करता है जब UITextView केवल शब्द-रैपिंग (अंग्रेजी वर्णमाला के साथ) करता है।

क्या UITextView में कर्सर की पिक्सेल-स्थिति खोजने का कोई अन्य तरीका है?

या यह निर्धारित करने का कोई तरीका है कि कोई विशेष वर्ण चीनी वर्णों या अंग्रेजी-शब्द-लपेटने जैसी अंग्रेजी-रैपिंग का पालन करता है या नहीं?

अलावा:

यहाँ मेरी कार्यान्वयन टोनी एल्गोरिथ्म पर आधारित है। मैंने एक लैंडस्केप मोड में एक UITextView रखा है, इसलिए इसकी चौड़ाई 1024 है, और मैंने आकार 21 के साथ कस्टम फ़ॉन्ट का उपयोग किया। आपको sizeOfContentWidth और sizeOfContentLine उचित रूप से बदलना चाहिए। sizeOfContentWidth वास्तविक चौड़ाई से छोटा है, और 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

+0

हाय, मैंने टोनी के एल्गोरिदम के आधार पर अपना कार्यान्वयन जोड़ा। टोनी के एल्गोरिदम के लिए एक जोड़ा यह है कि शुरुआत में, मैंने वर्तमान कर्सर को शब्द के अंत में ले जाया। – pnmn

+0

यह एल्गोरिदम इस धारणा पर आधारित है कि UITextView केवल शब्द-रैपिंग कर रहा है। मुझे लगता है कि कर्सर की सही पिक्सेल-स्थिति की गणना करने के लिए हमें किसी भी प्रकार के चरित्र के साथ काम करने के लिए एक अलग दृष्टिकोण की आवश्यकता है।एक समाधान यह है कि हम स्क्रैच से CoreText, UITextInput, और UIKeyInput का उपयोग करके पूरी तरह से नया कस्टम टेक्स्ट व्यू बना सकते हैं, लेकिन मैं इसे केवल कर्सर स्थिति के लिए नहीं करना चाहता हूं। – pnmn

उत्तर

0

यह शायद नहीं बल्कि अक्षम है, लेकिन आप प्रत्येक व्यक्ति के चरित्र के माध्यम से कोड आप पोस्ट और पाठ कर्सर पर है की लाइन ले लिया है की एक ही मूल प्रिंसिपल, और पाश लेने के लिए और [NSString sizeWithFont:forWidth:lineBreakMode:] करना प्रत्येक गणना करने के लिए कर सकता है चरित्र की चौड़ाई, और आप उन सभी को अपनी एक्स स्थिति के लिए जोड़ सकते हैं? बस एक विचार है, लेकिन शब्द रैपिंग के साथ इस मुद्दे को ठीक करने में मदद कर सकता है।

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 
संबंधित मुद्दे