दिलचस्प पोस्ट
"डाउनस्ट्रीम" और "अपस्ट्रीम" की परिभाषा मैं PHP में एक अनाम फ़ंक्शन को तुरंत कैसे निष्पादित करूं? GitHub रेपो से एक फ़ोल्डर या निर्देशिका डाउनलोड करें फ़ॉर्मेट नंबर जैसे स्टैक ओवरफ़्लो (हजारों लोगों के लिए किफ़ास्ट के साथ गोल) एंड्रॉइड में एचटीएमएल टैग्स को पट्टी या पलायन कैसे करें मुझे क्यों + + वीआईएस में टाइप करेंइफ़ टाइपनाम का उपयोग करने की आवश्यकता है? जावास्क्रिप्ट का उपयोग करने के लिए मैं जेसनसन को बहुत प्रिंट कैसे कर सकता हूं? 'प्रवेश-नियंत्रण-अनुमति-उत्पत्ति' शीर्षलेख में कई मूल्य शामिल हैं एक सामान्य संपत्ति बनाना न्यूएर फ्लेक्सबॉक्स एपीआई का उपयोग कर फ्लेक्सबॉक्स और ऊर्ध्वाधर स्क्रॉल एक पूर्ण-ऊंचाई वाले ऐप में सेटकुकी, हेडर सूचना को संशोधित नहीं किया जा सकता है – हेडर पहले ही भेजे गए हैं इनलाइन मित्र कार्यों का दायरा क्या है? इनो सेटअप का उपयोग करके फ़ाइल पर 'व्यवस्थापक के रूप में चलाएं' को कैसे सेट करें Entity Framework 6 का उपयोग कर रिकॉर्ड कैसे अपडेट करें? लंगर लिंक पर क्लिक करते समय चिकना स्क्रॉल करना

मैं यूआईएलबल में टेक्स्ट के उपस्ट्रिंग के लिए CGRect कैसे खोजूं?

किसी दिए गए NSRange , मैं एक UILabel उस CGRect में खोजना चाहूंगा जो उस NSRange के ग्लिफ़ से मेल खाती है। उदाहरण के लिए, मैं CGRect को ढूंढना चाहूंगा जिसमें वाक्य में "कुत्ते" शब्द होता है " CGRect कुत्ते पर त्वरित ब्राउन फॉक्स कूदता है।"

समस्या का दृश्य वर्णन

चाल है, UILabel में कई लाइनें हैं, और पाठ को वास्तव में attributedText , इसलिए, स्ट्रिंग की सटीक स्थिति को खोजने के लिए थोड़ा कठिन है।

जिस पद्धति पर मैं अपने UILabel उप-वर्ग पर लिखना चाहूंगा वह इस तरह कुछ दिखाई देगी:

  - (CGRect)rectForSubstringWithRange:(NSRange)range; 

जो रुचि रखते हैं, उनके लिए विवरण:

इसके साथ मेरा लक्ष्य सटीक रूप और यूआईएलएबल की स्थिति के साथ एक नया यूआईएलएबल बनाने में सक्षम होना है , जिससे मैं सजीव कर सकूं। मुझे बाकी का पता चल गया है, लेकिन यह विशेष रूप से यह कदम है कि इस समय मुझे वापस पकड़ रहे हैं।

मैंने अभी तक इस मुद्दे को हल करने और हल करने के लिए क्या किया है:

  • मुझे उम्मीद थी कि आईओएस 7 के साथ, इस समस्या का समाधान करने वाला पाठ किट का थोड़ा सा होगा, लेकिन पाठ किट के साथ मैंने जो कुछ भी उदाहरण देखा है, वह UITextField के बजाय UITextView और UITextField पर केंद्रित है।
  • मैंने स्टैक ओवरफ्लो पर एक और सवाल देखा है जो इस समस्या को हल करने का वादा करता है, लेकिन स्वीकार किए जाते हैं जवाब दो साल से पुराना है, और कोड का श्रेय अच्छी तरह से नहीं किया गया है।

मुझे यह शर्त थी कि इसका सही जवाब निम्न में से एक है:

  • कोड की एक पंक्ति में इस समस्या को हल करने के लिए एक मानक टेक्स्ट किट विधि का उपयोग करना। मुझे यकीन है कि इसमें NSLayoutManager और textContainerForGlyphAtIndex:effectiveRange NSLayoutManager शामिल होगा textContainerForGlyphAtIndex:effectiveRange
  • एक जटिल विधि लिखना जो लाइनों में यूआईएलएबल को तोड़ देती है, और कोर टेक्स्ट विधियों का इस्तेमाल करते हुए, एक पंक्ति के भीतर एक ग्लिफ़ के रीसेट को पाता है। मेरी सबसे अच्छी बात यह है कि मैट के उत्कृष्ट टीटीटीएटीवीटेड लेबेल को अलग-अलग लेना है, जिसमें एक ऐसा तरीका है जो एक बिंदु पर एक ग्लिफ़ मिल जाता है – अगर मैं इसे उलटा करता हूं, और एक ग्लिफ़ के लिए बिंदु ढूंढता हूं , जो काम कर सकता है

अद्यतन: यहां तीन चीजें हैं जो मैंने अभी तक इस समस्या को सुलझाने की कोशिश की है के साथ एक गिथूब सार है: https://gist.github.com/bryanjclark/7036101

वेब के समाधान से एकत्रित समाधान "मैं यूआईएलबल में टेक्स्ट के उपस्ट्रिंग के लिए CGRect कैसे खोजूं?"

कोड में यहोशू के उत्तर के बाद, मैं निम्नलिखित के साथ आया जो अच्छी तरह से काम करने लगता है:

 - (CGRect)boundingRectForCharacterRange:(NSRange)range { NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:[self attributedText]]; NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; [textStorage addLayoutManager:layoutManager]; NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:[self bounds].size]; textContainer.lineFragmentPadding = 0; [layoutManager addTextContainer:textContainer]; NSRange glyphRange; // Convert the range for glyphs. [layoutManager characterRangeForGlyphRange:range actualGlyphRange:&glyphRange]; return [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer]; } 

ल्यूक रोजर्स के उत्तर का निर्माण करना लेकिन तेजी से लिखा हुआ है:

 extension UILabel { func boundingRectForCharacterRange(range: NSRange) -> CGRect? { guard let attributedText = attributedText else { return nil } let textStorage = NSTextStorage(attributedString: attributedText) let layoutManager = NSLayoutManager() textStorage.addLayoutManager(layoutManager) let textContainer = NSTextContainer(size: bounds.size) textContainer.lineFragmentPadding = 0.0 layoutManager.addTextContainer(textContainer) var glyphRange = NSRange() // Convert the range for glyphs. layoutManager.characterRangeForGlyphRange(range, actualGlyphRange: &glyphRange) return layoutManager.boundingRectForGlyphRange(glyphRange, inTextContainer: textContainer) } } 

स्विफ्ट 3

 extension UILabel { func boundingRectForCharacterRange(range: NSRange) -> CGRect? { guard let attributedText = attributedText else { return nil } let textStorage = NSTextStorage(attributedString: attributedText) let layoutManager = NSLayoutManager() textStorage.addLayoutManager(layoutManager) let textContainer = NSTextContainer(size: bounds.size) textContainer.lineFragmentPadding = 0.0 layoutManager.addTextContainer(textContainer) var glyphRange = NSRange() // Convert the range for glyphs. layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) } } 

मेरा सुझाव पाठ किट का उपयोग करना होगा दुर्भाग्य से हमारे पास लेआउट मैनेजर तक पहुंच नहीं है, जो कि UILabel का उपयोग करता है, लेकिन इसका एक प्रतिकृति बनाना संभव है और एक सीमा के लिए रीसेट प्राप्त करने के लिए इसका उपयोग करना संभव है।

मेरा सुझाव एक NSTextStorage ऑब्जेक्ट बनाने के लिए होता है जिसमें आपके लेबल में सटीक वही NSTextStorage पाठ होता है। अगला एक NSLayoutManager बनाएँ और पाठ संग्रहण ऑब्जेक्ट में जोड़ें। अंत में लेबल के समान आकार के साथ एक NSTextContainer बनाएं और लेआउट मैनेजर को जोड़ें।

अब टेक्स्ट मेमोरी में एक ही पाठ के रूप में लेबल और टेक्स्ट कंटेनर लेबल के समान आकार है, इसलिए हमें लेआउट मैनेजर से पूछने में सक्षम होना चाहिए जो कि हमने सीमा के लिए बनाई गई सीमा के लिए बनाया है। boundingRectForGlyphRange:inTextContainer: :। सुनिश्चित करें कि आप पहले अपने glyphRangeForCharacterRange:actualCharacterRange: रेंज में glyphRangeForCharacterRange:actualCharacterRange: रेंज का उपयोग करके अपने चरित्र की श्रेणी को परिवर्तित करते हैं glyphRangeForCharacterRange:actualCharacterRange: लेआउट प्रबंधक ऑब्जेक्ट पर।

सभी अच्छी तरह से चल रहे हैं कि आपको लेबल के भीतर निर्दिष्ट सीमा के एक सीमाबद्ध CGRect देना चाहिए।

मैंने इसका परीक्षण नहीं किया है, लेकिन यह मेरा दृष्टिकोण होगा और UILabel स्वयं के कामों की नकल करने की सोच में सफल होने का अच्छा मौका होना चाहिए।

क्या आप इसके बजाय UITextView पर अपने वर्ग का आधार कर सकते हैं? यदि हां, तो UiTextInput प्रोटोकॉल विधियां देखें। विशेष रूप से ज्यामिति देखें और आराम करने वाले तरीकों को दबाएं।

दुर्भाग्य से यूआईएलबल में कोई सीधी एपीआई नहीं है और इस सुविधा को सही ढंग से समर्थन देने के लिए आपको अलग-अलग पात्रों के आकार को ध्यान में रखते हुए बहुत सारे काम करने होंगे। हालांकि, किसी ने पहले ही यह पता लगाने में समय बिताया है कृपया नीचे दिए गए कोड के कोड पर एक नज़र डालें और देखें कि यह आपके लिए क्या काम करता है:

यूआईएलबल टेक्स्ट के उपस्ट्रिंग के लिए सीजीआरएक्ट प्राप्त करते हैं

स्विफ्ट 3 के लिए अनुवादित

 func boundingRectForCharacterRange(_ range: NSRange) -> CGRect { let textStorage = NSTextStorage(attributedString: self.attributedText!) let layoutManager = NSLayoutManager() textStorage.addLayoutManager(layoutManager) let textContainer = NSTextContainer(size: self.bounds.size) textContainer.lineFragmentPadding = 0 layoutManager.addTextContainer(textContainer) var glyphRange = NSRange() layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) } 

ऐसा करने का एक और तरीका, यदि आपके पास स्वचालित फ़ॉन्ट आकार समायोजन सक्षम है, तो ऐसा होगा:

 let stringLength: Int = countElements(self.attributedText!.string) let substring = (self.attributedText!.string as NSString).substringWithRange(substringRange) //First, confirm that the range is within the size of the attributed label if (substringRange.location + substringRange.length > stringLength) { return CGRectZero } //Second, get the rect of the label as a whole. let textRect: CGRect = self.textRectForBounds(self.bounds, limitedToNumberOfLines: self.numberOfLines) let path: CGMutablePathRef = CGPathCreateMutable() CGPathAddRect(path, nil, textRect) let framesetter = CTFramesetterCreateWithAttributedString(self.attributedText) let tempFrame: CTFrameRef = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, stringLength), path, nil) if (CFArrayGetCount(CTFrameGetLines(tempFrame)) == 0) { return CGRectZero } let lines: CFArrayRef = CTFrameGetLines(tempFrame) let numberOfLines: Int = self.numberOfLines > 0 ? min(self.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines) if (numberOfLines == 0) { return CGRectZero } var returnRect: CGRect = CGRectZero let nsLinesArray: NSArray = CTFrameGetLines(tempFrame) // Use NSArray to bridge to Array let ctLinesArray = nsLinesArray as Array var lineOriginsArray = [CGPoint](count:ctLinesArray.count, repeatedValue: CGPointZero) CTFrameGetLineOrigins(tempFrame, CFRangeMake(0, numberOfLines), &lineOriginsArray) for (var lineIndex: CFIndex = 0; lineIndex < numberOfLines; lineIndex++) { let lineOrigin: CGPoint = lineOriginsArray[lineIndex] let line: CTLineRef = unsafeBitCast(CFArrayGetValueAtIndex(lines, lineIndex), CTLineRef.self) //CFArrayGetValueAtIndex(lines, lineIndex) let lineRange: CFRange = CTLineGetStringRange(line) if ((lineRange.location <= substringRange.location) && (lineRange.location + lineRange.length >= substringRange.location + substringRange.length)) { var charIndex: CFIndex = substringRange.location - lineRange.location; // That's the relative location of the line var secondary: CGFloat = 0.0 let xOffset: CGFloat = CTLineGetOffsetForStringIndex(line, charIndex, &secondary); // Get bounding information of line var ascent: CGFloat = 0.0 var descent: CGFloat = 0.0 var leading: CGFloat = 0.0 let width: Double = CTLineGetTypographicBounds(line, &ascent, &descent, &leading) let yMin: CGFloat = floor(lineOrigin.y - descent); let yMax: CGFloat = ceil(lineOrigin.y + ascent); let yOffset: CGFloat = ((yMax - yMin) * CGFloat(lineIndex)) returnRect = CalculationHelper.sizeOfString(substring, font: self.font, width: DBL_MAX, height: DBL_MAX) returnRect.origin.x = xOffset + self.frame.origin.x returnRect.origin.y = yOffset + self.frame.origin.y + ((self.frame.size.height - textRect.size.height) / 2) break } } return returnRect