質問
属性付きテキストを描画したビューのタップに応答するタッチハンドラーにいくつかあります。これを通じて、私は CTRunRef
(および関連する行)、およびその実行内のグリフの数。
私が簡単に理解できないのは、その一連のグリフを取得し、属性付きの文字列を指定して、それを文字列内の文字にマッピングする方法です。
具体的には、ユーザーがビュー内でどの単語をタップしたかを知りたいので、その単語が URL であるかどうかを処理し、カスタムのデリゲート メソッドを起動して、それを使用して Web ビューを開くことができるようにする必要があります。考えられるすべての部分文字列はありますが、ユーザーがタップした場所を特定の部分文字列にマッピングする方法がわかりません。
ご協力をいただければ幸いです。
アップデート:私は実際に、スタックオーバーフローの別の人からの提案を受けて、別の方法でそれを実行しました。基本的に私がやったことはカスタム属性を設定することです。 @"MyAppLinkAddress"
文字列を属性付き文字列に変換するときに見つけた URL の値を使用します。これは文字列を描画する前に起こります。したがって、タップ イベントが発生したときは、その属性が存在するかどうかを確認し、存在する場合はデリゲート メソッドを呼び出します。存在しない場合は無視します。現在は希望どおりに機能していますが、この質問はもう数日間オープンのままにしておくつもりです。誰かが答えを思い付いたら、それが有効な解決策であれば喜んで受け入れます。将来のある時点で、この情報が役立つ可能性があります。
解決
そこで、アップデートで述べたように、私は別の道を歩むことにしました。代わりに、作成時にカスタム属性を持っていたので、属性付き文字列のカスタム属性を使用してリンクを指定するというアイデアを思いつきました。それで私はそうしました。次に、タッチ ハンドラーで、実行がタップされると、その実行にその属性があるかどうかを確認し、属性がある場合は、その属性を使用してデリゲートを呼び出します。そこから、その URL を使用して Web ビューを喜んでロードします。
編集:以下は、この回答で私が行ったことを説明するコードのスニペットです。楽しむ。
// When creating the attribute on your text store. Assumes you have the URL already.
// Filled in for convenience
NSRange urlRange = [tmpString rangeOfString:@"http://www.foo.com/"];
[self.textStore addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)[UIColor blueColor].CGColor range:urlRange];
[self.textStore addAttribute:@"CustomLinkAddress" value:urlString range:urlRange];
それから...
// Touch handling code — Uses gesture recognizers, not old school touch handling.
// This is just a dump of code actually in use, read through it, ask questions if you
// don't understand it. I'll do my best to put it in context.
- (void)receivedTap:(UITapGestureRecognizer*)tapRecognizer
{
CGPoint point = [tapRecognizer locationInView:self];
if(CGRectContainsPoint(textRect, point))
{
CGContextRef context = UIGraphicsGetCurrentContext();
point.y = CGRectGetHeight(self.contentView.bounds) - kCellNameLabelHeight - point.y;
CFArrayRef lines = CTFrameGetLines(ctframe);
CFIndex lineCount = CFArrayGetCount(lines);
CGPoint origins[lineCount];
CTFrameGetLineOrigins(ctframe, 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);
NSString* urlString = [attributes objectForKey:@"CustomLinkAddress"];
if(urlString && ![urlString isEqualToString:@""])
{
[self.delegate didReceiveURL:[NSURL URLWithString:urlString]];
UIGraphicsPopContext();
return;
}
}
}
}
UIGraphicsPopContext();
}
}
他のヒント
タップされた行を見つけたら、呼び出して文字列内のインデックスを要求できます。 CTLineGetStringIndexForPosition()
. 。個々の実行にアクセスする必要はありません。