Domanda

Ho qualche codice in una visione che attira un testo attribuito utilizzando CoreText. In questo, sto cercando gli URL e renderli blu. L'idea è di non portare in tutto il sovraccarico di un UIWebView solo per ottenere link cliccabili. Una volta che un utente tocca su questo link (non l'intero cella di visualizzazione della tabella), voglio il fuoco fuori di un metodo delegato che sarà poi utilizzato per presentare una vista modale che contiene una vista web andando a questo URL.

sto risparmiando il percorso e la stringa stessa come variabili della vista istanza e il codice di disegno accade in -drawRect: (ho lasciato fuori per brevità).

Il mio gestore tocco tuttavia, pur incompleta, non è stampa quello che mi aspettavo che. Si tratta qui di seguito:

- (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
                }
            }
        }
    }
}

Non è il codice più bella in questo momento, sto ancora cercando di fare proprio questo lavoro, così perdonare la qualità del codice.

Il problema che sto avendo è che quando si tocca il link di fuori, quello che mi aspetto sarebbe accaduto, accade:. Nulla viene licenziato

Tuttavia, mi aspetterei "Tapped line" per ottenere stampata se si tocca la stessa linea il collegamento è attivo, cosa che non accade, e mi aspetto sia "Tapped line" e "Tapped run" per ottenere stampati se mi toccare l'URL.

Sono sicuri di dove prendere questo ulteriore, le risorse che ho guardato per la risoluzione di questo problema sono cacao specifico (che è quasi del tutto inapplicabili), o le informazioni carenti su questo caso specifico.

sarò contento di prendere puntatori a documentazione dettagliatamente come fare correttamente sul rilevamento se un tocco si è verificata entro i limiti di un testo di base di disegno sopra il codice, ma a questo punto, voglio solo risolvere questo problema, in modo che qualsiasi aiuto sarebbe molto apprezzato.

Aggiorna : Ho ristretto il mio problema a un problema di coordinate. Ho capovolto le coordinate (e non come indicato sopra) e il problema che sto ricevendo è che tocchi registrarsi come mi aspetto, ma lo spazio di coordinate è capovolto, e io non riesco a capovolgere di nuovo.

È stato utile?

Soluzione

Ho appena fatto questo per ottenere l'indice di carattere stringa dalla posizione di tocco. Il numero di riga sarebbe ho in questo caso:

- (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);
}

Altri suggerimenti

Si potrebbe provare ad aggiungere il disegno di testo in un CALayer, aggiungere questo nuovo livello come sottolivello della vostra vista layer e hitTest contro di essa nella vostra touchesEnded? In tal caso, si dovrebbe essere in grado di creare una zona toccabile più grande, rendendo lo strato più grande del testo elaborato.

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

Versione Swift 3 della risposta di Nick 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
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top