トップ «前の日記(2012-05-02) 最新 次の日記(2012-05-04)» 編集

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|

2012-05-03 [iOS]ハイパーリンク

Twitterの詳細画面のように。テキスト中のハイパーリンクの文字色等を変更して、選ばれたら、そのURLをブラウザで開くようにするにはどうすればいいのか?詳しく調べていないが、一つはテキストをHTML化して、UIWebViewで表示するという案を思い浮かんだ。

OS Xの場合は、Technical Q&A QA1487「Embedding Hyperlinks in NSTextField and NSTextView」で説明されている。

iOSの場合、NSString関連のメソッドに差がある為、OS Xと同様な方法が適用できるのか分からない為、試行錯誤してみた。

そもそも、OS Xの場合は、どうするのか確認してみる。以下は、QA1487のコードそのままだ。

/* NSAttributedStringを拡張するカテゴリとして実装 */
@interface NSAttributedString (Hyperlink)
    +(id)hyperlinkFromString:(NSString*)inString withURL:(NSURL*)aURL;
@end
 
@implementation NSAttributedString (Hyperlink)
/*
 * NSTextFieldの場合、属性と選択を可能にしておく必要がある。
 * [テキストフィールド setAllowsEditingTextAttributes:YES];
 * [テキストフィールド setSelectable:YES]
 */
+(id)hyperlinkFromString:(NSString*)inString withURL:(NSURL*)aURL
{
    NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString: inString];
    NSRange range = NSMakeRange(0, [attrString length]);
 
    [attrString beginEditing];
 
    /* ハイパーリンクを設定 */
    [attrString addAttribute:NSLinkAttributeName value:[aURL absoluteString] range:range];
 
    // make the text appear in blue
    [attrString addAttribute:NSForegroundColorAttributeName value:[NSColor blueColor] range:range];
 
    // next make the text appear with an underline
    [attrString addAttribute:
            NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSSingleUnderlineStyle] range:range];
 
    [attrString endEditing];
 
    return [attrString autorelease];
}
@end

iOSの場合になるが、iOS 3.2以降、NSRegularExpressionSearchで正規表現が扱えるようになったので、これでURLを見つけて、上記のような方法でハイパーリンクを設定すればいいのか考えてた。

が、iOSの場合、以外と安易な解決策を見つけてしまった。

iOS 3以降、UIDataDetectorTypesのUIDataDetectorTypeLinkを指定すれば、リンクを作成できる。試してみよう。

self.textView.editable = NO;
self.textView.dataDetectorTypes = UIDataDetectorTypeLink;
self.textView.text = @"This is a demonstration.\nhttp://www.bitz.co.jp/\nThank you.";

あっけなかった。簡単だ。

ただ、この場合は、URLを開く流れを制御できない。例えば、ちょっとしたアプリケーション固有の情報を追加するとか、Safariでなく自身のUIWebViewに表示するとか。

URLを開くのは、UIApplicationの- openURL:メソッドの呼び出しによってなので、このメソッドを捕まえて、差し替えれば良いのでは?

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.openURLMethod = class_getInstanceMethod([UIApplication class], @selector(openURL:));
    Method  myOpenURLMethod = class_getInstanceMethod([AppDelegate class], @selector(myOpenURL:));
    method_exchangeImplementations(self.openURLMethod,  myOpenURLMethod);
    return YES;
}
 
- (BOOL)myOpenURL:(NSURL *)url
{
    NSLog(@"%s, url(%@)", __func__, url);
    return YES;
}

うまく捕まえる事はできた。ただ、どうすれば、オリジナルの- openURL:メソッドを呼んでいいのか分からなかったり、出来ても、変数のアクセス等、素直に実装できそうにないので、これは諦める事にした。

結局、UIApplicationのサブクラスを作成して、- opneURL:をオーバーライドすることにした。

@interface MyApplication : UIApplication
@end
    ....
@implementation MyApplication
- (BOOL)openURL:(NSURL *)url
{
    NSLog(@"%s, url(%@)", __func__, url);
    return [super openURL:url];
}
@end

main.mを変更して、この独自のサブクラスが呼ばれるようにする。

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv,
            NSStringFromClass([MyApplication class]),
            NSStringFromClass([AppDelegate class]));
    }
}

UIApplicationMainの第三引数がnilになっていたと思うが、そこにMyApplcationを設定する。

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/Hyperlinks - GitHub

_ 関連情報

Technical Q&A QA1487
Embedding Hyperlinks in NSTextField and NSTextView
Technical Q&A QA1629
Launching the App Store from an iPhone application
Text, Web, and Editing Programming Guide for iOS
Developerサイトの情報。

トップ «前の日記(2012-05-02) 最新 次の日記(2012-05-04)» 編集