2010-09-27 10 views
9

मेरे पास कुछ कोड है जो CoreText का उपयोग करके कुछ जिम्मेदार टेक्स्ट खींचता है। इसमें, मैं यूआरएल खोज रहा हूं और उन्हें नीला बना रहा हूं। विचार क्लिक करने योग्य लिंक प्राप्त करने के लिए UIWebView के सभी ओवरहेड में नहीं लाने का विचार है। एक बार जब उपयोगकर्ता उस लिंक पर टैप करता है (पूरे टेबल व्यू सेल नहीं), तो मैं एक प्रतिनिधि विधि को आग लगाना चाहता हूं जिसका उपयोग तब एक मोडल व्यू पेश करने के लिए किया जाएगा जिसमें उस यूआरएल पर एक वेब व्यू होगा।कोरटेक्स्ट का उपयोग करना और क्लिक करने योग्य क्रिया बनाने के लिए स्पर्श

मैं पथ और स्ट्रिंग को दृश्य के उदाहरण चर के रूप में सहेज रहा हूं, और ड्राइंग कोड -drawRect: में होता है (मैंने इसे ब्रेवटी के लिए छोड़ दिया है)।

मेरा स्पर्श हैंडलर हालांकि, अधूरा है, प्रिंटिंग नहीं कर रहा है, जिसे मैं उम्मीद करता हूं। यह नीचे है:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [touches anyObject]; 
    CGPoint point = [touch locationInView:self]; 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    NSLog(@"attribString = %@", self.attribString); 
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.attribString); 
    CTFrameRef ctframe = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, self.attribString.length), attribPath, NULL); 

    CFArrayRef lines = CTFrameGetLines(ctframe); 
    for(CFIndex i = 0; i < CFArrayGetCount(lines); i++) 
    { 
     CTLineRef line = CFArrayGetValueAtIndex(lines, i); 
     CGRect lineBounds = CTLineGetImageBounds(line, context); 

     // Check if tap was on our line 
     if(CGRectContainsPoint(lineBounds, point)) 
     { 
      NSLog(@"Tapped line"); 
      CFArrayRef runs = CTLineGetGlyphRuns(line); 
      for(CFIndex j = 0; j < CFArrayGetCount(runs); j++) 
      { 
       CTRunRef run = CFArrayGetValueAtIndex(runs, j); 
       CFRange urlStringRange = CTRunGetStringRange(run); 
       CGRect runBounds = CTRunGetImageBounds(run, context, urlStringRange); 

       if(CGRectContainsPoint(runBounds, point)) 
       { 
        NSLog(@"Tapped run"); 
        CFIndex* buffer = malloc(sizeof(CFIndex) * urlStringRange.length); 
        CTRunGetStringIndices(run, urlStringRange, buffer); 
        // TODO: Map the glyph indices to indexes in the string & Fire the delegate 
       } 
      } 
     } 
    } 
} 

यह इस समय सबसे सुंदर कोड, मैं अभी भी सिर्फ यह काम है, तो कोड गुणवत्ता माफ करने के लिए कोशिश कर रहा हूँ नहीं है।

मेरी समस्या यह है कि जब मैं लिंक के बाहर टैप करता हूं, तो मुझे क्या उम्मीद है, ऐसा होता है: कुछ भी नहीं निकाल दिया जाता है।

हालांकि, मैं अगर मैं एक ही पंक्ति लिंक पर है, जो नहीं होता है नल "Tapped line" मुद्रित करने के लिए उम्मीद करेंगे, और मैं दोनों "Tapped line" और "Tapped run" अगर मैं यूआरएल पर नल मुद्रित करने के लिए उम्मीद करेंगे।

मुझे यह पता नहीं है कि यह कहां लेना है, संसाधनों को मैंने इस मुद्दे के समाधान के लिए देखा है कोको विशिष्ट (जो लगभग पूरी तरह से लागू नहीं है), या इस विशिष्ट मामले पर जानकारी की कमी है।

मैं खुशी से पॉइंटर्स को दस्तावेजों पर ले जाऊंगा जो विस्तार से पता लगाएंगे कि कोड पर कोर टेक्स्ट ड्राइंग की सीमाओं के भीतर कोई स्पर्श हुआ है, लेकिन इस बिंदु पर, मैं बस इस समस्या को हल करना चाहता हूं, इसलिए कोई भी मदद की बहुत सराहना की जाएगी।

अद्यतन: मैंने अपनी समस्या को समन्वय मुद्दे पर सीमित कर दिया है। मैंने समन्वय (और ऊपर दिखाए गए अनुसार नहीं) को फिसल दिया है और मुझे जो समस्या मिल रही है वह है कि मैं उम्मीद करता हूं कि रजिस्टर को छूता है, लेकिन समन्वय स्थान फ़्लिप हो जाता है, और मैं इसे वापस फ्लिप नहीं कर सकता।

+0

आप को ध्यान में रखा है तथ्य यह है कि CoreText एक फ़्लिप समन्वय प्रणाली का उपयोग करता है? अभी यह मुझे लगता है जैसे आप दो अलग समन्वय प्रणालियों में चीजों की तुलना कर रहे हैं। – Jacques

+0

इसके अलावा, इस तरह के हर स्पर्श पर फ्रेमसेटर को फिर से बनाना एक बुरा विचार है। फ़्रेमसेटर बनाना बहुत महंगा है, इसलिए टेक्स्ट को पहली बार चित्रित या सेट करते समय आपको इसे कैश करना चाहिए। – Jacques

+0

मेरी विकास पद्धति बस है: 1) इसे काम करें; 2) इसे सही बनाओ; 3) इसे तेज/साफ करें। चलो # 2 के साथ सौदा करते हैं जब हम # 1 जा रहे हैं :) समन्वय प्रणाली के संबंध में भी, हाँ मुझे एहसास है, और थोड़ी देर के लिए मैं इसे संभालने में कामयाब नहीं था।कोड में अब, एक सहयोगी से परामर्श करने के बाद, उसने मुझे सीधे इस पर सेट किया, और कम से कम रनों पर यह कम से कम लाइनों पर नल का पता लगा रहा है। अभी भी एक को समझने की कोशिश कर रहा है। – jer

उत्तर

8

मैंने स्पर्श स्थिति से स्ट्रिंग कैरेक्टर इंडेक्स प्राप्त करने के लिए अभी यह किया है। लाइन नंबर इस मामले में मैं होगा:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    NSLog(@"touch ended"); 

    UITouch* touch = [touches anyObject]; 

    CGPoint pnt = [touch locationInView:self]; 

    CGPoint reversePoint = CGPointMake(pnt.x, self.frame.size.height-pnt.y); 

    CFArrayRef lines = CTFrameGetLines(ctFrame); 

    CGPoint* lineOrigins = malloc(sizeof(CGPoint)*CFArrayGetCount(lines)); 

    CTFrameGetLineOrigins(ctFrame, CFRangeMake(0,0), lineOrigins); 

    for(CFIndex i = 0; i < CFArrayGetCount(lines); i++) 
    { 
     CTLineRef line = CFArrayGetValueAtIndex(lines, i); 

     CGPoint origin = lineOrigins[i]; 
     if (reversePoint.y > origin.y) { 
      NSInteger index = CTLineGetStringIndexForPosition(line, reversePoint); 
      NSLog(@"index %d", index); 
      break; 
     } 
    } 
    free(lineOrigins); 
} 
+0

धन्यवाद निक आपने मुझे बचाया! :) – stefanosn

+0

यह बहुत अच्छा काम करता है, मैं इसकी तुलना उन श्रेणियों के सेट से कर सकता हूं जिन्हें मैंने टापेबल शब्दों के लिए संग्रहीत किया है। यह मेरे पुराने दृष्टिकोण से बहुत तेज है - धन्यवाद :) –

+0

मैं सीटीफ़्रेम कैसे प्राप्त कर सकता हूं? –

0

आप अपने टेक्स्ट ड्राइंग को कैलियर में जोड़ने का प्रयास कर सकते हैं, इस नई परत को अपनी दृश्य परत के सब्लेयर के रूप में जोड़ें और अपने स्पर्शों में इसके खिलाफ हिट करें? यदि आप ऐसा करते हैं, तो आप खींचे गए पाठ से अधिक परत बनाकर एक बड़ा स्पर्श करने योग्य क्षेत्र बनाने में सक्षम होना चाहिए।

// hittesting 
UITouch *touch = [[event allTouches] anyObject]; 
touchedLayer = (CALayer *)[self.layer hitTest:[touch locationInView:self]]; 
+0

तब मुझे अपने पाठ को दो अलग-अलग परतों में विभाजित करने की एक और समस्या होगी - वह जिसे मैं प्रतिनिधि को ट्रिगर करना चाहता हूं, और बाकी बाकी। समस्या जो मैं वहां दौड़ूंगा, क्या होता है यदि यूआरएल लाइन के बीच में है और इसके पहले और उसके बाद पाठ है? तो मुझे कई अलग-अलग परतों में विभाजित करना होगा। यदि टेक्स्ट I प्रस्तुत करने वाले समूह में कुछ यूआरएल हैं तो यह बालों वाली हो सकती है। मैं केवल अटारी स्ट्रिंग में सभी वस्तुओं की एक सूची प्राप्त करना पसंद करूंगा जिसमें मैंने रंगीन नीला रंग लिया है, और उनके बाउंडिंग बॉक्स प्राप्त करें, देखें कि उपयोगकर्ता वहां अंदर टैप किया गया है और उस यूआरएल के साथ प्रतिनिधि को कॉल करें। – jer

+0

सच है, यह एक समस्या हो सकती है। शायद मैं आपकी समस्या को सही नहीं समझ पाया। इस स्पर्श को पकड़ने के लिए पाठ को रखने के बारे में कैसे एक हिट करने योग्य परत है? – msg

+0

मुझे अभी भी यह जानने की ज़रूरत है कि इसे कहां रखा जाए - जिसका अर्थ है कि मुझे अभी भी यूआरएल का आय प्राप्त करने की आवश्यकता है। यह मुझे वापस वर्ग में रखता है। :) – jer

0

स्विफ्ट 3 निक H247 के जवाब के संस्करण:

var ctFrame: CTFrame? 

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { 
    guard let touch = touches.first, let ctFrame = self.ctFrame else { return } 

    let pnt = touch.location(in: self.view) 
    let reversePoint = CGPoint(x: pnt.x, y: self.frame.height - pnt.y) 
    let lines = CTFrameGetLines(ctFrame) as [AnyObject] as! [CTLine] 

    var lineOrigins = [CGPoint](repeating: .zero, count: lines.count) 
    CTFrameGetLineOrigins(ctFrame, CFRange(location: 0, length: 0), &lineOrigins) 

    for (i, line) in lines.enumerated() { 
     let origin = lineOrigins[i] 

     if reversePoint.y > origin.y { 
      let index = CTLineGetStringIndexForPosition(line, reversePoint) 
      print("index \(index)") 
      break 
     } 
    } 
} 
संबंधित मुद्दे