我有一些代碼在視圖中使用CoreText繪製一些屬性文本。在這裏,我正在尋找網址並將它們變成藍色。這個想法是爲了獲得可點擊的鏈接而不是引入UIWebView
的所有開銷。一旦用戶點擊該鏈接(而不是整個表格視圖單元格),我想要引發一個委託方法,然後用它來呈現一個模式視圖,其中包含一個到該URL的Web視圖。使用CoreText和觸摸創建一個可點擊的動作
我將路徑和字符串本身保存爲視圖的實例變量,並且繪圖代碼發生在-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"
如果我的網址點擊來獲得打印。
我不確定在哪裏採取這一進一步,我已經看到解決這個問題的資源是可可特定的(這幾乎完全不適用),或缺乏關於此特定情況的信息。
我很樂意指出文檔,詳細說明如何正確地檢測觸摸是否發生在代碼的核心文本繪圖的邊界內,但此時,我只是想解決這個問題,所以任何幫助將不勝感激。
UPDATE:我已經將我的問題縮小到一個座標問題。我翻轉了座標(而不是如上所示),我得到的問題是觸摸按我的預期註冊,但座標空間翻轉,我似乎無法將其翻轉。
你有沒有考慮到,CoreText使用翻轉座標系中的事實呢?現在看起來像你在比較兩個不同座標系中的東西。 – Jacques 2010-09-27 13:39:02
此外,在每次觸摸時重新創建framesetter是一個壞主意。創建一個framesetter是非常昂貴的,所以你應該在第一次繪圖或設置文本時進行緩存。 – Jacques 2010-09-27 13:41:18
我的開發方法很簡單:1)讓它工作; 2)做對; 3)快速/清潔。讓我們來處理#2當我們得到#1去:)也是關於座標系,是的,我意識到這一點,並且有一段時間我沒有處理它。在現在的代碼中,在與一位同事協商之後,他讓我直截了當地說,至少現在檢測線上的點擊,而不是跑步。仍試圖找出那一個。 – jer 2010-09-27 14:07:49