CoreText绘图、接收触摸、触摸坐标混乱

发布于 2024-10-10 08:25:35 字数 3674 浏览 3 评论 0原文

我有一个使用 coretext 绘制一些文本的视图。一切正常,文本显示右侧向上,翻转坐标。但是,我还必须响应特定运行的触摸,因此我有以下代码,当点击手势识别器触发时,该代码会被调用:

- (void)receivedTap:(UITapGestureRecognizer*)recognizer
{
    CGPoint point = [recognizer locationInView:self];
    NSLog(@"point = %@", NSStringFromCGPoint(point));
    CGContextRef context = UIGraphicsGetCurrentContext();

    CFArrayRef lines = CTFrameGetLines(textFrame);
    CFIndex lineCount = CFArrayGetCount(lines);
    CGPoint origins[lineCount];

    CTFrameGetLineOrigins(textFrame, CFRangeMake(0, 0), origins);
    for(CFIndex idx = 0; idx < lineCount; idx++)
    {
        CTLineRef line = CFArrayGetValueAtIndex(lines, idx);
        CGRect lineBounds = CTLineGetImageBounds(line, context);
        lineBounds.origin.y += origins[idx].y;

        if(CGRectContainsPoint(lineBounds, point))
        {
            CFArrayRef runs = CTLineGetGlyphRuns(line);
            for(CFIndex j = 0; j < CFArrayGetCount(runs); j++)
            {
                CTRunRef run = CFArrayGetValueAtIndex(runs, j);
                NSDictionary* attributes = (NSDictionary*)CTRunGetAttributes(run);
                BOOL result = NO;
                NSURL* url = [attributes objectForKey:kJTextViewDataDetectorLinkKey];
                NSString* phoneNumber = [attributes objectForKey:kJTextViewDataDetectorPhoneNumberKey];
                NSDictionary* addressComponents = [attributes objectForKey:kJTextViewDataDetectorPhoneNumberKey];
                if(url)
                {
                    result = [[UIApplication sharedApplication] openURL:url];
                    return;
                }
                else if(phoneNumber)
                {
                    NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@", phoneNumber]];
                    result = [[UIApplication sharedApplication] openURL:url];
                    return;
                }
                else if(addressComponents)
                {
                    NSMutableString* address = [NSMutableString string];
                    NSString* temp = nil;
                    if((temp = [addressComponents objectForKey:NSTextCheckingStreetKey]))
                        [address appendString:temp];
                    if((temp = [addressComponents objectForKey:NSTextCheckingCityKey]))
                        [address appendString:[NSString stringWithFormat:@"%@%@", ([address length] > 0) ? @", " : @"", temp]];
                    if((temp = [addressComponents objectForKey:NSTextCheckingStateKey]))
                        [address appendString:[NSString stringWithFormat:@"%@%@", ([address length] > 0) ? @", " : @"", temp]];
                    if((temp = [addressComponents objectForKey:NSTextCheckingZIPKey]))
                        [address appendString:[NSString stringWithFormat:@" %@", temp]];
                    if((temp = [addressComponents objectForKey:NSTextCheckingCountryKey]))
                        [address appendString:[NSString stringWithFormat:@"%@%@", ([address length] > 0) ? @", " : @"", temp]];
                    NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps?q=%@", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
                    result = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
                    return;
                }
            }
        }
    }
}

适用于第一行,例如,我正在执行一些数据检测的 Web url超过。我点击它,Mobile Safari 就会按我的预期启动。但是,这仅当该项目位于第一行时才有效。我在其他行上看到彩色和下划线的文本(对于地址和电话号码之类的内容),并且我已经验证了适当的数据已附加到字符串中的自定义属性,但是当我点击它们时,没有任何反应。

我知道我必须以某种方式翻转矩形 lineBounds,但我不知道如何去做。任何帮助将不胜感激。

I have a view which draws some text using coretext. Everything works fine, text shows right side up, flipping the coordinates. However, I must also respond to touches on specific runs, so I have the following code which gets called when a tap gesture recognizer fires:

- (void)receivedTap:(UITapGestureRecognizer*)recognizer
{
    CGPoint point = [recognizer locationInView:self];
    NSLog(@"point = %@", NSStringFromCGPoint(point));
    CGContextRef context = UIGraphicsGetCurrentContext();

    CFArrayRef lines = CTFrameGetLines(textFrame);
    CFIndex lineCount = CFArrayGetCount(lines);
    CGPoint origins[lineCount];

    CTFrameGetLineOrigins(textFrame, CFRangeMake(0, 0), origins);
    for(CFIndex idx = 0; idx < lineCount; idx++)
    {
        CTLineRef line = CFArrayGetValueAtIndex(lines, idx);
        CGRect lineBounds = CTLineGetImageBounds(line, context);
        lineBounds.origin.y += origins[idx].y;

        if(CGRectContainsPoint(lineBounds, point))
        {
            CFArrayRef runs = CTLineGetGlyphRuns(line);
            for(CFIndex j = 0; j < CFArrayGetCount(runs); j++)
            {
                CTRunRef run = CFArrayGetValueAtIndex(runs, j);
                NSDictionary* attributes = (NSDictionary*)CTRunGetAttributes(run);
                BOOL result = NO;
                NSURL* url = [attributes objectForKey:kJTextViewDataDetectorLinkKey];
                NSString* phoneNumber = [attributes objectForKey:kJTextViewDataDetectorPhoneNumberKey];
                NSDictionary* addressComponents = [attributes objectForKey:kJTextViewDataDetectorPhoneNumberKey];
                if(url)
                {
                    result = [[UIApplication sharedApplication] openURL:url];
                    return;
                }
                else if(phoneNumber)
                {
                    NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@", phoneNumber]];
                    result = [[UIApplication sharedApplication] openURL:url];
                    return;
                }
                else if(addressComponents)
                {
                    NSMutableString* address = [NSMutableString string];
                    NSString* temp = nil;
                    if((temp = [addressComponents objectForKey:NSTextCheckingStreetKey]))
                        [address appendString:temp];
                    if((temp = [addressComponents objectForKey:NSTextCheckingCityKey]))
                        [address appendString:[NSString stringWithFormat:@"%@%@", ([address length] > 0) ? @", " : @"", temp]];
                    if((temp = [addressComponents objectForKey:NSTextCheckingStateKey]))
                        [address appendString:[NSString stringWithFormat:@"%@%@", ([address length] > 0) ? @", " : @"", temp]];
                    if((temp = [addressComponents objectForKey:NSTextCheckingZIPKey]))
                        [address appendString:[NSString stringWithFormat:@" %@", temp]];
                    if((temp = [addressComponents objectForKey:NSTextCheckingCountryKey]))
                        [address appendString:[NSString stringWithFormat:@"%@%@", ([address length] > 0) ? @", " : @"", temp]];
                    NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps?q=%@", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
                    result = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
                    return;
                }
            }
        }
    }
}

Which works for the first line, if for instance, a web url which I'm doing some data detection over. I tap it, and Mobile Safari launches as I'd expect. However, this only works if the item is on the first line. I see the text coloured and underlined (for things like addresses and telephone numbers) on other lines, and I've verified the appropriate data is attached to my custom attributes in the string, but when I tap them, nothing occurs.

I know I have to somehow flip the rect lineBounds, but I'm not sure how to go about doing it. Any help would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浅笑轻吟梦一曲 2024-10-17 08:25:35

实际上,您需要做的是反向迭代lines。例如,尝试替换以下代码:

NSArray* tempLines = (NSArray*)CTFrameGetLines(textFrame);
CFIndex lineCount = [tempLines count];//CFArrayGetCount(lines);
NSMutableArray* lines = [NSMutableArray arrayWithCapacity:lineCount];
for(id elem in [tempLines reverseObjectEnumerator])
    [lines addObject:elem];
CGPoint origins[lineCount];

Actually what you need to do is iterate over lines in reverse. For instance, try substituting in this code:

NSArray* tempLines = (NSArray*)CTFrameGetLines(textFrame);
CFIndex lineCount = [tempLines count];//CFArrayGetCount(lines);
NSMutableArray* lines = [NSMutableArray arrayWithCapacity:lineCount];
for(id elem in [tempLines reverseObjectEnumerator])
    [lines addObject:elem];
CGPoint origins[lineCount];
奶茶白久 2024-10-17 08:25:35

最简单的反转线的方法

        CFArrayRef lines = (CFArrayRef)[[(NSArray *)CTFrameGetLines(frame) reverseObjectEnumerator] allObjects];

simplest way to reverse lines

        CFArrayRef lines = (CFArrayRef)[[(NSArray *)CTFrameGetLines(frame) reverseObjectEnumerator] allObjects];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文