SwiftUI: Text()の文中URLをクリッカブルにする
SwiftUIのアプリで、メモ欄かなんかを作っていて、URLがそこに含まれていたらその部分をクリッカブル(クリックしたらSafariでそのページが開く)ようにしたいときがあります。
struct ContentView: View {
var body: some View {
VStack {
let text = "こんなページがあった! https://zenn.dev"
Text("\(text)")
Text(text)
Text(LocalizedStringKey("\(text)"))
Text(LocalizedStringKey(text))
Divider()
let markdown = "[こんなページがあった!](https://zenn.dev)"
Text("\(markdown)")
Text(markdown)
Text(LocalizedStringKey("\(markdown)"))
Text(LocalizedStringKey(markdown))
Divider()
Text(getMarkdownString(text))
Text(getMarkdownString(markdown))
}
.padding()
}
func getMarkdownString(_ text: String) -> AttributedString {
do {
return try AttributedString(markdown: text)
}
catch {
return AttributedString(text)
}
}
}
まず、Text
+LocalizedStringKey
がマークダウン記法を解釈します。
上記の例を見ると、Text
だけとかLocalizedStringKey
に埋め込み文字列を渡すとかするとうまく行かないということが分かります。
埋め込み文字列("\(markdown)"
みたいなの)は、String
ではなくて、StringInterpolation
です。
StringInterpolation
は、書く側はシンプルに書いてますが、実行時には変数の型に合わせて文字列にフォーマットする呼び出しが行われます。なのでそれの呼び出しと、マークダウン記法の解析処理が併用されないのではないかと想像します。
マークダウン記法で[表示文字列](URL)
のように書くと表示文字列だけが表示されるのですが、マークダウン記法がなくても、URL文字列は勝手にクリッカブルになるということも分かります。
ただし使うのがLocalizedStringKey
なので、入力した文字列が普通に翻訳リソースとバッティングしてしまうとおかしなことになります。
そこで、サンプルコードの最後の2個のAttributedString
を使う方法が良いのではないかと思います。
ちなみにいずれにしても、使用可能なマークダウン記法について公式ドキュメントが見当たらない(探せてない)のが難点です。
↓のものがある程度合致してるんじゃないかと思ってはいますが。
AttributedString
を使う場合
let options: AttributedString.MarkdownParsingOptions = .init(allowsExtendedAttributes: true, interpretedSyntax: .inlineOnlyPreservingWhitespace, appliesSourcePositionAttributes: true)
return try AttributedString(markdown: markdown, options: options)
のように明示的にオプションを指定しないと、改行とかなくなってしまうようですね。