stringリソースの文字列にリンクを設定する - annotationを添えて
この記事の要約
やりたいこと
- 図のようにTextViewの一部(
こちら
)にリンクを設定する - 文字列の範囲を指定する際にマジックナンバーを使用しない
- タップ時はIntentを投げてブラウザなどに飛ばす
実装
stringリソースの定義
<string name="text_template"> annotationタグのドキュメントは <annotation link="document_link">こちら</annotation> から飛べます </string> <string name="annotation_document"> https://developer.android.com/guide/topics/resources/string-resource </string>
リンクを設定したい文字列を <annotation xxx="yyy">
タグで囲みます
xxx
と yyy
は任意の文字列を設定することが可能で、複数のannotationタグを設定した際にどの文字列かを判断するために使うことができます
リンクの設定
以下の手順でstringリソースからTextViewへセットするためのCharSequence
を生成することができます
- 元となる文字列
R.string.text_template
を取得 text_template
からannotationタグの情報を取り出す<annotation link="document_link">
を表すAnnotationインスタンスを取り出す- 取り出したAnnotationから
ClickableSpan
を作成する - Annotationに含まれている文字列のポジションを使って
ClickableSpan
を適用する範囲を指定する
コード例
private fun getText(): CharSequence { val template = getText(R.string.text_template) if (template !is SpannedString) return template // Annotationの使い方 https://developer.android.com/guide/topics/resources/string-resource#StylingWithAnnotations val annotations = template.getSpans(0, template.length, Annotation::class.java) val spannableString = SpannableString(template) annotations .filter { annotation -> annotation.key == "link" } .filter { linkAnnotation -> linkAnnotation.value == "document_link" } .forEach { annotation -> val linkSpan = object : ClickableSpan() { override fun onClick(widget: View) { val url = getString(R.string.annotation_document) intent = viewIntent(url) startActivity(intent) } } spannableString.setSpan( linkSpan, template.getSpanStart(annotation), template.getSpanEnd(annotation), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) } return spannableString } fun viewIntent(url: String): Intent { return Intent(Intent.ACTION_VIEW).apply { data = Uri.parse(url) } }
メリット
annotationタグを使用すると文字列の範囲を Annotation
インスタンスから取得できるため、文字列の変更を行ってもstringリソースのみの変更で済みます
また、多言語対応する場合にもannotationタグの属性と値を揃えておくことで、コードの変更が不要になるケースが増えます