Android文本超鏈接實(shí)現(xiàn)及滑動(dòng)沖突處理

我們知道使用SpannableString和ClickableSpan可以實(shí)現(xiàn)部分文字高亮點(diǎn)擊效果祥国,但是設(shè)置了setMovementMethod(LinkMovementMethod.getInstance())會(huì)使文字自帶滑動(dòng)。最近有個(gè)需求是在Dialog中顯示高亮可點(diǎn)擊跳轉(zhuǎn)的文字惜浅,但是受Dialog大小限制,需要添加ScrollView以上下滑動(dòng)祠丝,這樣就會(huì)出現(xiàn)滑動(dòng)沖突橘茉,參考一些資料后琢磨出了解決方案。

ps:setMovementMethod(LinkMovementMethod.getInstance())不是自帶滑動(dòng)效果嗎展鸡?為啥還用ScrollView包一層屿衅?實(shí)際上這個(gè)自帶點(diǎn)擊的滑動(dòng)效果賊垃圾,一碰就觸發(fā)點(diǎn)擊了莹弊,根本不滑傲诵,誰(shuí)用誰(shuí)知道

看下效果


沖突.png

貼出主要代碼

1、高亮文字和點(diǎn)擊跳轉(zhuǎn)——自定義Span

public class CustomSpan extends URLSpan {

    public Context mContext;
    public String mId;

    public CustomSpan(String url) {
        super(url);
    }

    public CustomSpan(String url, Context context, String id) {
        super(url);
        this.mContext = context;
        this.mId = id;
    }

    @Override
    public void updateDrawState(@NonNull TextPaint ds) {
        super.updateDrawState(ds);
        ds.setColor(Color.parseColor("#5F7AB8"));
        ds.setUnderlineText(false);
    }

    @Override
    public void onClick(View widget) {
        if (!TextUtils.isEmpty(mId)) {
            Intent intent = new Intent(mContext, XXX.class);
            intent.putExtra("id", mId);
            mContext.startActivity(intent);
        }
    }

    /**
     *
     * @param context
     * @param spannableContent 要匹配的高亮可點(diǎn)擊內(nèi)容
     * @param content 全文
     * @param id
     * @return
     */
    public static SpannableString getSpannableContent(Context context, SpannableString spannableContent, String content, String id) {
        Pattern pattern = Pattern.compile(content, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(spannableContent);
        while (matcher.find()) {
            URLSpan span = new CustomSpan(content, context, id);
            spannableContent.setSpan(span, matcher.start(0), matcher.end(0), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        return spannableContent;
    }

}

獲取Dialog中要顯示的內(nèi)容箱硕,Conflict對(duì)象中有id和name,具體我就不寫了

private SpannableString getConflictMessage(List<Conflict> conflicts) {
    String str = "與{count}個(gè)計(jì)劃{name}時(shí)間沖突悟衩,確認(rèn)接受剧罩?";
    str = str.replace("{count}", conflicts.size() + "");
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < conflicts.size(); i++) {
        sb.append("【").append(conflicts.get(i).getName()).append("】");
        if (i != conflicts.size() - 1) {
            sb.append("、");
        }
    }
    str = str.replace("{name}", sb);

    SpannableString ss = new SpannableString(str);
    for (int i = 0; i < conflicts.size(); i++) {
        StringBuilder match = new StringBuilder();
        match.append("【").append(conflicts.get(i).getName()).append("】");
        if (i != conflicts.size() - 1) {
            match.append("座泳、");
        }
        ss = CustomSpan.getSpannableContent(mContext, ss, match.toString(), String.valueOf(conflicts.get(i).getId()));
    }
    return ss;
}

再給TextView加上tv.setMovementMethod(LinkMovementMethod.getInstance());就實(shí)現(xiàn)了部分文字高亮點(diǎn)擊跳轉(zhuǎn)

2惠昔、滑動(dòng)沖突處理——自定義MovementMethod

這里就是復(fù)制修改下LinkMovementMethod的源碼,把滑動(dòng)部分去掉就可以了挑势,LinkMovementMethod的源碼就不貼了镇防,用到時(shí)自己對(duì)照查看,這里只貼CustomMovementMethod代碼

public class CustomMovementMethod extends BaseMovementMethod {

    private static CustomMovementMethod customMovementMethod;

    public static CustomMovementMethod getInstance() {
        if (customMovementMethod == null) {
            synchronized (CustomMovementMethod .class) {
                if (customMovementMethod == null) {
                    customMovementMethod = new CustomMovementMethod ();
                }
            }
        }
        return customMovementMethod;
    }

    @Override
    public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
        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) {
                    // 只處理點(diǎn)擊事件
                    link[0].onClick(widget);
                }
                return true;
            }
        }
        return super.onTouchEvent(widget, buffer, event);
    }

    private CustomMovementMethod () {

    }
}

這樣在ScrollView中的TextView就可以滑動(dòng)了

3潮饱、Dialog大小適配——自定義可設(shè)置最大高度的ScrollView

如果Dialog中ScrollView高度寫死来氧,文字多了可視范圍大,效果好香拉,當(dāng)只有一行時(shí)就尷尬了啦扬,于是就設(shè)置個(gè)最大高度吧

public class MaxHeightScrollView extends ScrollView {

    private int maxHeight;

    public MaxHeightScrollView(Context context) {
        super(context);
    }

    public MaxHeightScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
        maxHeight = typedArray.getDimensionPixelSize(R.styleable.MaxHeightScrollView_max_height, 0);
    }

    public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setMaxHeight(int maxHeight) {
        this.maxHeight = maxHeight;
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (maxHeight > 0) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}


attrs.xml中
<declare-styleable name="MaxHeightScrollView">
    <attr name="max_height" format="dimension"/>
</declare-styleable>

以上幾步在Dialog中使用

TextView tv = (TextView) dialog.findViewById(R.id.message);
tv.setText(getConflictMessage(conflicts));
tv.setMovementMethod(CustomMovementMethod.getInstance());

tv.setMovementMethod(CustomMovementMethod.getInstance());是重點(diǎn),漏了這句點(diǎn)擊沒(méi)有效果

如果有更好的實(shí)現(xiàn)方法告訴下凫碌,互相學(xué)習(xí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扑毡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子盛险,更是在濱河造成了極大的恐慌瞄摊,老刑警劉巖勋又,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異换帜,居然都是意外死亡楔壤,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門膜赃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)挺邀,“玉大人,你說(shuō)我怎么就攤上這事跳座《祟酰” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵疲眷,是天一觀的道長(zhǎng)禾蚕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)狂丝,這世上最難降的妖魔是什么换淆? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮几颜,結(jié)果婚禮上倍试,老公的妹妹穿的比我還像新娘。我一直安慰自己蛋哭,他們只是感情好县习,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谆趾,像睡著了一般躁愿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沪蓬,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天彤钟,我揣著相機(jī)與錄音,去河邊找鬼跷叉。 笑死逸雹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的性芬。 我是一名探鬼主播峡眶,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼植锉!你這毒婦竟也來(lái)了辫樱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤俊庇,失蹤者是張志新(化名)和其女友劉穎狮暑,沒(méi)想到半個(gè)月后鸡挠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搬男,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年拣展,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缔逛。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡备埃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出褐奴,到底是詐尸還是另有隱情按脚,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布敦冬,位于F島的核電站辅搬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏脖旱。R本人自食惡果不足惜堪遂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萌庆。 院中可真熱鬧溶褪,春花似錦、人聲如沸践险。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捏境。三九已至,卻和暖如春毁葱,著一層夾襖步出監(jiān)牢的瞬間垫言,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工倾剿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筷频,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓前痘,卻偏偏與公主長(zhǎng)得像凛捏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芹缔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程坯癣,因...
    小菜c閱讀 6,402評(píng)論 0 17
  • 總在想,人總應(yīng)該留下點(diǎn)什么最欠,尤其是在這最無(wú)望的時(shí)候示罗,擁有著最美好的年華惩猫,在向往最快活的生活,用一種最矛盾的姿態(tài)蚜点,有...
    茂茂家的小刺猬閱讀 182評(píng)論 0 0
  • 掙扎一個(gè)月轧房,產(chǎn)品的主體需求算是完善了,目前也進(jìn)入了開發(fā)階段绍绘,需要抽個(gè)時(shí)間來(lái)寫一寫需求的總結(jié)計(jì)劃 不過(guò)在這之前奶镶,我先...
    煎魚說(shuō)閱讀 330評(píng)論 0 0
  • 有一友生病吃中藥,醫(yī)生囑咐不準(zhǔn)喝酒陪拘。禁不住朋友勸和自己的酒癮厂镇,還是一邊吃中藥一邊喝酒。友妻告之藻丢,喝中藥再喝酒傷...
    泳波閱讀 534評(píng)論 0 0