仿微信朋友圈,点击评论,生成自定义超链接,并处理

转载请标明出处  http://blog.csdn.net/xxxiu/article/details/40736057



有个场景: 一段文本,我们想让其中几处成为链接,点击后对应去处理。比如微信的朋友圈中对动态的评论。如图



点人名看资料,点整个弹出软键盘评论。



部分代码:

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
        <com.example.androiddemo.commtrls.TextViewSpannableString
            android:id="@+id/tv"
            android:background="@drawable/textview_bg_selector"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textSize="20sp" />
</LinearLayout>


Activity引用代码

/**
 * 该Demo主要解决的应用场景是: 类似微信朋友圈里, A回复B:xxxx 
 * 点击A或者B看个人资料,点击整个弹出评论。其实关键点是,如何区别这两类点击。因为A与B点击可以看为一类。
 * 最终处理在TextUnderlineClickSpan的onClick()中,可以从结果追整个流程。
 * 
 * 效果查看:
 * 点击AB看LOG输出,点整个看Toast
 * @author xiaoXIU
 *
 */
public class MainActivity extends Activity {

	private TextViewSpannableString mTv;
	private Context mContext;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mContext = this;
		//测试数据
		CarCommend commend = new CarCommend();
		commend.setUserId(1);
		commend.setUserName("小修");
		commend.setTargetuserId(2);
		commend.setTargetuserName("大宝");
		commend.setContent("老婆,我爱你。");
		mTv = (TextViewSpannableString) findViewById(R.id.tv);
		mTv.updateUI(commend);
		mTv.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Toast.makeText(mContext, "打开键盘,回复评论", Toast.LENGTH_SHORT).show();
				
			}
		});
	}
}

自定义TextView  该类里有对内容中存在Emoji表情的处理,但是Demo程序没有做的那么复杂,所以想实现的可以打开注释部分自己再修改下。我的项目中是做处理的。

/**
 * 内容设置,发送消息给链接处理类处理
 * @author xiaoXiu
 *
 */
public class TextViewSpannableString extends TextView {
	private Context mContext;
    private boolean mDontConsumeNonUrlClicks = true;
    private boolean mLinkHit;

    public TextViewSpannableString(Context context) {
        super(context);
        init(context);
    }

    public TextViewSpannableString(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public TextViewSpannableString(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
    }

    @Override
    public boolean hasFocusable() {
        return false;
    }

    @Override
    public boolean performClick() {
        if (mDontConsumeNonUrlClicks) {
            return super.performClick();
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mLinkHit = false;
        boolean res = super.onTouchEvent(event);
        if (!mDontConsumeNonUrlClicks) {// 没有ClickSpan被点击是,处理OnClick事件。
            return mLinkHit;
        }

        return res;
    }

    public void updateUI(CarCommend bean) {
        setText("");
        setTextViewSpan(this, bean.getUserName(), bean.getUserId());

        if (bean.getUserId() != bean.getTargetuserId() && bean.getTargetuserId() != 0 && !TextUtils.isEmpty(bean.getTargetuserName())) {
            append("回复");
            setTextViewSpan(this, bean.getTargetuserName(), bean.getTargetuserId());
        }
        append(":");
        setContent(bean);
    }

    public void updateUIFeedDetails(CarCommend bean) {
        setText("");
        append("");
        if (bean.getUserId() != bean.getTargetuserId() && bean.getTargetuserId() != 0 && !TextUtils.isEmpty(bean.getTargetuserName())) {
            append("回复");
            setTextViewSpan(this, bean.getTargetuserName(), bean.getTargetuserId());
            append(":");
        }
        setContent(bean);
    }

    private void setContent(CarCommend bean) {
    	//这是为了Demo的显示,不带表情
    	 SpannableString sp = new SpannableString(bean.getContent());
    	 Editable editable = getEditableText();
         if (editable != null) {
             editable.insert(length(), sp);
         }
    	
         //注释部分解决了带表情的内容处理
        /*for (TextEmoji e : bean.getCommendBody()) {
            if (TextEmoji.TEXT_TYPE.equals(e.getType()) || e.getEmojiId() == -1) {
                append(e.getContent());
            } else {
                SpannableString sp = getEmojiSpan(e.getEmojiId(), e.getContent());
                if (!TextUtils.isEmpty(sp)) {
                    Editable editable = getEditableText();
                    if (editable != null) {
                        editable.insert(length(), sp);
                    }
                }
            }
        }*/
    }

    private void setTextViewSpan(TextView textView, String text, int tag) {
        Message message = new Message();
        message.what = TextUnderlineClickSpan.FLAG_GO_OTHERS_INFO_ACTIVITY;
        message.arg1 = tag;
        SpannableString spStr = new SpannableString(text);
        ClickableSpan clickSpan = new TextUnderlineClickSpan(mContext, false, message); // 设置超链接
        spStr.setSpan(clickSpan, 0, text.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

        textView.append(spStr);

        setMovementMethod(LocalLinkMovementMethod.getInstance());
    }

    public static class LocalLinkMovementMethod extends LinkMovementMethod {
        static LocalLinkMovementMethod sInstance;

        public static LocalLinkMovementMethod getInstance() {
            if (sInstance == null)
                sInstance = new LocalLinkMovementMethod();

            return sInstance;
        }

        @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) {
                        link[0].onClick(widget);
                    } else if (action == MotionEvent.ACTION_DOWN) {
                        Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]));
                    }

                    if (widget instanceof TextViewSpannableString) {
                        ((TextViewSpannableString) widget).mDontConsumeNonUrlClicks = false;
                        ((TextViewSpannableString) widget).mLinkHit = true;
                    }
//                  Selection.removeSelection(buffer);// 去除选择背景
                    return true;
                } else {
                    if (widget instanceof TextViewSpannableString) {
                        ((TextViewSpannableString) widget).mDontConsumeNonUrlClicks = true;
                    }

                    Selection.removeSelection(buffer);
                    return Touch.onTouchEvent(widget, buffer, event);
                }
            }
            return Touch.onTouchEvent(widget, buffer, event);
        }
    }

    private SpannableString getEmojiSpan(int imgId, String spannableString) {

        if (TextUtils.isEmpty(spannableString) || imgId == -1) {
            return null;
        }

        ImageSpan imageSpan = new ImageSpan(mContext, FaceConversionUtil.getInstace().getEmojiBitmap(mContext, imgId));
        SpannableString spannable = new SpannableString(spannableString);
        spannable.setSpan(imageSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        return spannable;
    }

    public void parseUrl(CharSequence text) {
        if (text instanceof Spannable) {
            Factory spannableFactory = Spannable.Factory.getInstance();
            Spannable sp = spannableFactory.newSpannable(text);

            int end = text.length();
            URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);
            SpannableStringBuilder style = new SpannableStringBuilder(text);
            style.clearSpans();
            for (URLSpan url : urls) {
                int spStart = sp.getSpanStart(url);
                int spEnd = sp.getSpanEnd(url);
                Message message = new Message();
                message.what = TextUnderlineClickSpan.FLAG_URL_CONCLUDE;
                Bundle bundle = new Bundle();
                bundle.putString("title", sp.subSequence(spStart, spEnd).toString());
                bundle.putString("content", url.getURL());
                message.obj = bundle;
                ClickableSpan clickSpan = new TextUnderlineClickSpan(mContext, false, message);
                style.setSpan(clickSpan, spStart, spEnd, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
            }
            setText(style);
        } else {
            setText(text);
        }
    }
}

具体处理控制部分

/**
 * 用于控制链接执行动作
 * 主要方法 onClick()
 * @author xiaoXiu
 *
 */
public class TextUnderlineClickSpan extends ClickableSpan {
    public static final int FLAG_GO_OTHERS_INFO_ACTIVITY = 1;
    public static final int FLAG_URL_CONCLUDE = 2;
    public static final int FLAG_FEED_TO_TOPIC = 3;
    private Context mContext;
    private boolean isShowUnderline = false;
    private int mTextHexColor = 0xff7f93bd;

    private Message mMessage;

    public TextUnderlineClickSpan(Context context, boolean showUnderline, Message message) {
        super();
        this.mContext = context;
        this.mMessage = message;
    }

    public void setTextColor(int hexColor) {
        mTextHexColor = hexColor;
    }

    @Override
    public void onClick(View widget) {
        if (mMessage == null) {
            return;
        }

        switch (mMessage.what) {
        case FLAG_GO_OTHERS_INFO_ACTIVITY:
        	  //看个人资料
        	if(mMessage.arg1==1){
        		Log.e("", "看小修资料");
        	}else if(mMessage.arg1==2){
        		Log.e("", "看大宝资料");
        	}
            break;
        case FLAG_URL_CONCLUDE:
        	//链接
    	    Bundle bundle = (Bundle) mMessage.obj;
    	    externalControls(bundle);
            break;
        case FLAG_FEED_TO_TOPIC:
        	//进入帖子
            break;
        }

    }

    private void externalControls(Bundle bundle) {
        Intent intent = new Intent();
        intent.setAction("android.intent.action.VIEW");
        Uri uri = Uri.parse(bundle.getString("content").trim());
        intent.setData(uri);
        mContext.startActivity(intent);
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setColor(mContext.getResources().getColor(R.drawable.textview_typelink_selector));
        ds.setUnderlineText(isShowUnderline); // 去掉下划线
    }

}

根据上面的方式就解决了该问题,这个Demo唯一的缺陷就是点击人名的时候整个TextView的Selector都生效了。

源码下载地址:SourceCode

因为本人积分就剩了1个了,所以资源分要1分,以后分多了,我会改成免收的,请理解。



  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值