LoginSignup
2

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-03-17

ezgif.com-video-to-gif.gif

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

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

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

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です(今回は改行くらいしかタグを使っていませんがwww)

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はめちゃくちゃめんどくさいのでもう載せませんがww)

一応、HtmlTextViewを使ったときの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ってところで色を指定しないとわけわからん色をつけられちゃうので注意です。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2