QQ空间点评列表效果实现

首先,我们要实现的效果是这样的:

1.  评论人和被评论人颜色与评论内容颜色不同。

通过重写ClickabSpan的updateDrawState方法来实现。

		@Override
		public void updateDrawState(TextPaint ds) {
			ds.setUnderlineText(false);
			ds.setColor(Color.BLUE);
		}

2.  点击评论人名字C(onClick,onLongClick),触发相应的操作,点击有selector效果。

3.  点击评论内容D(onClick,onLongClick),触发相应的操作,点击有selector效果。

4.  点击layout B(onClick,onLongClick),触发相应的操作,点击有selector效果。

5.  点击layout A(onClick,onLongClick),触发相应的操作,点击有selector效果。

要求A,B,C的点击效果不冲突(B和D的点击效果一致)。可以操作QQ空间体验一下。

主要是实现Layout B的效果。

B是一个包含TextView的RelativeLayout。而这个TextView的text使用了ClickableSpan,当点击ClickableSpan指向的内容时,会执行ClickableSpan的onClick方法。而当点击TextView中非ClickableSpan指向的内容时,却不会执行RelativeLayout的点击行为。

我们首先来解决这个问题。

我们要达到的目标是:当点击TextView中ClickableSpan指向的内容时,响应的是ClickableSpan的onClick方法。而当点击TextView中非ClickableSpan指向的内容时,响应的是RelativeLayout的点击事件。

怎么才能实现呢?

最直观的想法就是重写TextView的onTouchEvent方法,当触摸到ClickableSpan指向的内容时,onTouchEvent返回true,当触摸到非ClickableSpan指向的内容时,onTouchEvent需要返回false,让其父view,也就是RelativeLayout去处理。(涉及到事件传递方面的知识)。

最关键的问题来了,怎么判断用户点触的是ClickableSapn指向的内容?

我们想,当我们点击到ClickableSpan指向的内容时,ClickableSpan可以响应,它是怎么判断的?

我们在使用ClickableSpan的时候必须要设置LinkMoventMethod,否则点击ClickableSpan是没有效果的。

	public void setHtmlText(String str) {
		Spannable span = setClickableSpan(str);
		if (null != span) {
			setMovementMethod(LinkMovementMethod.getInstance());
			setText(span);
		} else {
			setText(str);
		}
	}

(里建议在有ClickableSpan的时候才设置LinkMovementMethod。)

我们再看下TextView的onTouchEvent方法,其中有这样一段代码:

          if (mMovement != null) {
                handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
            }

mMovement 就是设置的 LinkMovementMethod 我们再去看下 LinkMovementMethod 的源代码

    @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]));
                }

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

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

就是在这个方法中触发的ClickableSpan的onClick事件。我们可以借鉴这个方法的代码来判断是否点击到ClickableSpan指向的区域。

基于此,我们重写TextView,命名为MyTextView:

主要方法有两个:

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		boolean result = super.onTouchEvent(event);

		int action = event.getAction();

		int x = (int) event.getX();
		int y = (int) event.getY();

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

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

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

		CharSequence text = getText();
		if (TextUtils.isEmpty(text) || !(text instanceof Spannable)) {
			return result;
		}

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

		if (link.length > 0) {
			return true;
		} else {
			return false;
		}
	}

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

ok,测试,搞定。

RelativeLayout可以通过设置background来设置selector,那点击ClickableSpan的时候,selector效果是怎么实现?

ClickableSpan没有API可以调用去设置selector,我们可以通过在onTouchEvent方法中通过监听ACTION_DOWN和ACTION_UP来设置不同的background来达到这种效果。

我们通过BackgroundSpan来设置背景颜色。

那贴上我们加上selector效果后MyTextView的onTouchEvent方法代码:

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		boolean result = super.onTouchEvent(event);

		int action = event.getAction();

		int x = (int) event.getX();
		int y = (int) event.getY();

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

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

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

		CharSequence text = getText();
		if (TextUtils.isEmpty(text) || !(text instanceof Spannable)) {
			return result;
		}

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

		if (link.length != 0) {

			if (action == MotionEvent.ACTION_DOWN) {

				mStart = buffer.getSpanStart(link[0]);
				mEnd = buffer.getSpanEnd(link[0]);

				if (mStart >= 0 && mEnd >= mStart) {
					buffer.setSpan(new BackgroundColorSpan(Color.GRAY), mStart, mEnd,
							Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
				}
			} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {

				if (mStart >= 0 && mEnd >= mStart) {
					buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT), mStart, mEnd,
							Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
					Selection.removeSelection(buffer);
					mStart = -1;
					mEnd = -1;
				}
			}

			return true;
		} else {
			if (mStart >= 0 && mEnd >= mStart) {
				buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT), mStart, mEnd,
						Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
				Selection.removeSelection(buffer);
				mStart = -1;
				mEnd = -1;
			}

			return false;
		}
	}

ok,测试,搞定。

注意,当使用ListView的onItemClick和onItemLongClick来处理点击事件时,会造成ListView的子View与Item的点击事件冲突。可以使用在getView的时候,通过设置View的onClick事件和onLongClick事件来达到效果。

Demo地址: QQ空间点评列表效果Demo
2021已然来临,在此之际debug抽空撸了一套 类似“QQ空间”、“新浪微博”、“微信朋友圈”PC版的互联网社交软件系统,并将其录制成了视频,特此分享给诸位进行学习,以掌握、巩固更多的技术栈和项目、产品开发经验! 言归正常,下面以问答的方式重点介绍下本门课程/系统的相关内容!  (1)问题一:这是一门什么样的课程? 本门课程是一门项目实战课程,基于Spring Boot2.X开发的一款类似“新浪微博”、“QQ空间”、“微信朋友圈”PC版的互联网社交软件,包含完整的门户网前端 以及 后台系统管理端,可以说是一套相当完整的系统!,大纲图如下所示:  而整个系统的系统架构设计如下图所示(注意:该图表示的是整个系统架构将经历N个阶段的演进,目前初定是4个阶段的演进,分别是架构1.0、2.0、3.0、4.0 !)   (2)问题二:可以学到哪些技术? 本课程对应着系统架构1.0,即第一阶段,主要的目标在于实现一个完整的系统,可以学到的技术还是比较多的:Spring Boot2.X、Java基础、Java8、JUC、NIO、微服务、分布式、系统架构设计、SpringMVC、MySQL、Lucene、多线程、并发编程、Bootstrap、HTML5、CSS3、JQuery、AdminLTE、VUE、LayUI相关组件等等 从架构2.0,即第二阶段的内容(对应第2门课程)开始将慢慢融入更多地技术栈,用以解决更多的业务、性能和服务拆分等问题!本门课程是后续其他阶段对应的课程的奠基,因此如果想要学习后续架构2.0、3.0、4.0的演进,则必须得先学习本门课程!   (3)问题三:系统运行起来有效果图看吗?   (4)问题四:学习本课程之前有什么要求? 要求的话,主要有两点,一是要有一定的Spring Boot、MySQL 以及 Web开发基础;二是最好学过Debug录制的 “企业权限管理平台(Spring Boot2.X+Shiro+Vue)”项目实战课程,因为本门课程“仿微博系统全程实战”的后台管理正是基于 “企业权限管理平台”项目二次开发的,因此建议最好先撸了那个课程再来学习本门课程! 友情提示:“企业权限管理平台(Spring Boot2.X+Shiro+Vue)”项目实战课程的购买学习地址:https://edu.csdn.net/course/detail/25646  (TIP:可以考虑购买组合套餐课程哦,更加实惠!!!)  岁末将至,人心浮躁 当此之际,应当沉下心,摒弃浮躁 要相信技术是第一生产力 相信技术改变生活、技术成就梦想! 特别是那些即将在过完年准备跳槽面试的小伙伴,本系统将可以为你增添几分亮点!!!  寄语:购买本课程的小伙伴将可获得本课程完整的视频教程、系统源代码数据库、课件PPT以及其他相关的工具跟资料,还可以进专属技术交流群交流技术!!!
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值