LoginSignup
45
46

More than 5 years have passed since last update.

TextViewに埋め込んだUrlリンクをタップした時の動作を置き換える

Last updated at Posted at 2012-07-24

TextViewにはHtml#fromHtmlを利用して、AタグでUrlリンクを埋め込むことができるが、動作を置き換えられないため、次のような場面で不便。

  • TabやActivityGroupの子画面内で設定すると例外が起きて強制停止する

  • 標準ブラウザでなくアプリ内のWebViewで遷移したい

TextViewに埋め込んだAタグタップでUrl遷移を動作させるには、次のようなコードが必要だが、

text.setMovementMethod(LinkMovementMethod.getInstance());

このLinkMovementMethodクラスを次のように拡張することで、リンクタップ時の動作を置き換えられるようになった。

MutableLinkMovementMethod.java
package jp.sample.samplehtml;

import android.net.Uri;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.view.MotionEvent;
import android.widget.TextView;

/**
 * Htmlテキストのリンククリックアクションをオーバーライドするためのクラス。<br>
 *
 * original source is android.text.method.LinkMovementMethod.java
 *
 * @author S.Kamba
 *
 */
public class MutableLinkMovementMethod extends LinkMovementMethod {

    /**
     * Urlのリンクをタップした時のイベントを受け取るリスナー
     *
     */
    public interface OnUrlClickListener{
        public abstract void onUrlClick(TextView widget, Uri uri);
    }

    /** Urlクリックリスナー */
    OnUrlClickListener listener = null;

    /*
     * Urlクリックリスナーを登録
     */
    public void setOnUrlClickListener(OnUrlClickListener l){
        listener = l;
    }

    @Override
    public boolean onTouchEvent(TextView widget, Spannable buffer,
            MotionEvent event) {

        // LinkMovementMethod#onTouchEventそのまんま

        int action = event.getAction();

        if (action == MotionEvent.ACTION_UP ||
            action == MotionEvent.ACTION_DOWN) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            x -= widget.getTotalPaddingLeft();
            y -= widget.getTotalPaddingTop();

            x += widget.getScrollX();
            y += widget.getScrollY();

            Layout layout = widget.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);

            ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    // リスナーがあればそちらを呼び出し
                    if(link[0] instanceof URLSpan && listener!=null){
                        Uri uri = Uri.parse( ((URLSpan)link[0]).getURL() );
                        listener.onUrlClick(widget, uri);
                    }else{
                        link[0].onClick(widget);
                    }
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer,
                                           buffer.getSpanStart(link[0]),
                                           buffer.getSpanEnd(link[0]));
                }

                return true;
            } else {
                Selection.removeSelection(buffer);
            }
        }

        return super.onTouchEvent(widget, buffer, event);
    }
}

#それにしても、LinkMovementMethodはシングルトンにしたかったっぽいのになんでコンストラクタがpublicなんだろう?^^;

45
46
0

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
45
46