コピペでできる一部の文字列でクリックイベントを取得する方法(android)

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367893/f31ff071-407e-6046-16b6-1a5b43ffbf03.gif)



androidで長いTextViewがあって、一部だけハイパーリンクにするのめちゃくちゃめんどくさいですよね。
ハイパーリンクというか、クリックイベントをとりたかったのですがだいぶめんどくさかったです。

なのでコピペでできるようにしました。
ついでにHTMLタグにも対応できるカスタムtextviewを作りました。

まずはそれを表示するクラスから

```kotlin:HtmlTextActivity.kt

class HtmlTextActivity: AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_html_text)

        setHtmlTextView()
    }

    private fun setHtmlTextView() {
        //　クリックを検知したいワードをセット
        val targets = mutableListOf("ここ", "こっち")
        html_textview.setPartialStringClickListener(targets, object: HtmlTextView.Callback {
            override fun onClick(tappedText: String) {
                when (tappedText) {
                    "ここ" -> finish()
                    "こっち" -> {
                        AlertDialog.Builder(this@HtmlTextActivity)
                            .setTitle("tapされました")
                            .setMessage("")
                            .setPositiveButton("OK"){ _, _ -> }
                            .show()
                    }
                }
            }
        })
    }
}

```

setHtmlTextView()くらいしか特筆すべき点はないです。
クリックイベントをとりたいtargetの文字列を指定して、mutableListに入れて、タップされた文字列がコールバックされるように組みました。


次に、肝心なHtmlに対応したTextViewです（今回は改行くらいしかタグを使っていませんがｗｗｗ）


```kotlin:HtmlTextView.kt


class HtmlTextView: TextView {
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}

    private var listener: Callback? = null

    init {
        // htmlに対応させてます。プレビューでもhtmlが有効になるのでとても見やすいです。
        this.text = HtmlCompat.fromHtml(this.text.toString(), FROM_HTML_MODE_COMPACT)
    }

    fun setPartialStringClickListener(targets: MutableList<String>, listener: Callback) {
        this.listener = listener

        val ss = SpannableString(this.text)

        for (target in targets) {
            var start = 0
            var end = 0

            // リンク化対象の文字列の start, end を算出する
            val pattern = Pattern.compile(target)
            val matcher = pattern.matcher(this.text)
            while (matcher.find()) {
                start = matcher.start()
                end = matcher.end()
                break
            }
            ss.setSpan(object: ClickableSpan() {
                override fun onClick(textView: View) {
                    listener.onClick(target)
                }
            }, start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
        }

        this.text = ss
        this.movementMethod = LinkMovementMethod.getInstance()
        this.highlightColor = Color.TRANSPARENT
    }
    interface Callback {
        fun onClick(clickedStr: String)
    }
}

```

コメントにも書いていますが、プレビューでもhtmlが有効になるのでとても見やすいです（gifはめちゃくちゃめんどくさいのでもう載せませんがｗｗ）

一応、HtmlTextViewを使ったときのxmlも載せておきます。




```xml:activity_html_text.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.free.myapplication.extension.HtmlTextView
        android:id="@+id/html_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="32dp"
        android:layout_centerInParent="true"
        android:textColorLink="@android:color/holo_orange_light"
        android:text="@string/test_html"/>

</RelativeLayout>

```

android:textColorLinkってところで色を指定しないとわけわからん色をつけられちゃうので注意です。