Android图文混排(仿QQ空间评论)

你知道TextView中可以“塞入”图片么?

之前项目需求,做一个类似QQ的点赞评论功能,效果图如下:



本文主要讲解评论这一块,至于点赞和表情帖,后续再说。
评论功能的介绍:评论内容显示:“发表评论用户”+评论内容+翻译图标。点击“发表评论用户”跳转到该用户的个人空间。点击“评论内容”,回复“发表评论用户”。点击“翻译图标”,弹出翻译对话框。
功能难点:不能用TextView和ImageView去拼凑整个评论的item,如果评论内容过多,就会出现布局问题,所以想到了图文混排来实现该功能。
功能实现:
评论的item布局我就不写了,就是一个Textview。
Textview中是可以塞入Span的,至于Span中要添加的内容,可以是字符串,也可以是图片。 TextView.BufferType并不是TextView的内部类,是一个枚举类型,设置有三个枚举值,分别为NORMAL,EDITABLE,SPANNAABLE。
SpannableString的使用:
   各种的Span就是通过SpannableString来封装样式的,设置完Span之后需要将Span放入到SpannableString类中,然后SpannableString设置到TextView中去。
comment_nickname_one.setText(addClickablePart(comment,position,dynamicId,i), TextView.BufferType.SPANNABLE);
下面我们来看一下addClickablePart方法:


/**
	 * 拼接评论那一行算法
	 * @param comment  评论集合
	 * @param position  新鲜事的position
	 * @param dynamicId  新鲜事id
	 * @param i  评论的下标
	 * 
	 * @return   评论视图
	 */
	private SpannableStringBuilder addClickablePart(final CommentBean comment, final int position, final String dynamicId,final int i) {
		
		SpannableString spanStr = new SpannableString("");
//		spanStr.setSpan(span, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
		
		SpannableStringBuilder ssb = new SpannableStringBuilder(spanStr);
		
		String poseterName = comment.getPosterName();
		
		/**
		 * 发表评论的人名长度
		 */
		int poseterNameLength = poseterName.length();
		/**被评论的人名长度*/
		int ReplyNameLength = comment.getReplyName().length();
		/**评论内容的长度*/
		int wordsLength = comment.getWords().length();
		//把评论发送者名字添加进去
		ssb.append(poseterName);
		ssb.setSpan(new ClickableSpan() {
			
			@Override
			public void onClick(View widget) {
				// TODO Auto-generated method stub
				Intent intent = new Intent(context, OtherPageActivity.class);
				Contants.friendId = comment.getPosterId();
				Contants.friendName = comment.getPosterName();
				Contants.friendIcon = comment.getPosterIcon();
				((NoteActivity)context).startActivity(intent);
			}
			@Override
			public void updateDrawState(TextPaint ds) {
				// TODO Auto-generated method stub
				super.updateDrawState(ds);
				ds.setColor(context.getResources().getColor(R.color.note_praiseblue_name));
//				// 去掉下划线
				ds.setUnderlineText(false);
			}
		}, 0, poseterNameLength, 0);
		String reply = " "+context.getResources().getString(R.string.reply)+" ";
		//添加“回复”二字
		ssb.append(reply);
		ssb.setSpan(new ClickableSpan() {
			
			@Override
			public void onClick(View widget) {
				// TODO Auto-generated method stub
			}
			@Override
			public void updateDrawState(TextPaint ds) {
				// TODO Auto-generated method stub
				super.updateDrawState(ds);
				ds.setColor(0xFF5e5d5d);
				// 去掉下划线
				ds.setUnderlineText(false);
			}
		}, poseterNameLength, reply.length()+poseterNameLength, 0);
		
		//把被回复的名字添加进去
		ssb.append(comment.getReplyName());
		ssb.setSpan(new ClickableSpan() {
			
			@Override
			public void onClick(View widget) {
				Intent intent = new Intent(context, OtherPageActivity.class);
				Contants.friendId = comment.getReplyId();
				Contants.friendName = comment.getReplyName();
				Contants.friendIcon = comment.getReplyIcon();
				((NoteActivity)context).startActivity(intent);
			}
			@Override
			public void updateDrawState(TextPaint ds) {
				super.updateDrawState(ds);
				ds.setColor(context.getResources().getColor(R.color.note_praiseblue_name));
				// 去掉下划线
				ds.setUnderlineText(false);
			}
		}, reply.length()+poseterNameLength, reply.length()+poseterNameLength+ReplyNameLength, 0);
		SpannableString spannableString1 = FaceConversionUtil.getInstace().getExpressionString(context, comment.getWords());
		
		ssb.append(" : ");
		ssb.append(spannableString1);
//		ssb.append(" : "+comment.getWords());
		
		ssb.setSpan(new ClickableSpan() {
			@Override
			public void onClick(View widget) {
				//如果是自己发表的评论,可以删除
				if(comment.getPosterId().equals(Contants.userID)){
					//弹出删除对话框
					ShowPickDialog(comment.getId(), dynamicId, i, position);
				}else{
					// TODO 点击评论内容,回复这条评论,传发表评论人的id
					
					//弹出一个Activity
					String replyId = comment.getPosterId();
					Intent intent = new Intent(context,CommentActivity.class);
					String isReply = "1";
					intent.putExtra("type", isReply);
					intent.putExtra("name", comment.getPosterName());
					intent.putExtra("replyId", replyId);
					intent.putExtra("dynamicId", dynamicId);
					String positionString = position+"";
					intent.putExtra("position", positionString);
					int IsNote = 1;
					//是从哪个页面传过去的
					intent.putExtra("commentFrom", IsNote+"");
					((NoteActivity)context).startActivityForResult(intent,IsNote);
				}
				
			}
			@Override
			public void updateDrawState(TextPaint ds) {
				// TODO Auto-generated method stub
				super.updateDrawState(ds);
				ds.setColor(context.getResources().getColor(R.color.login_regist));
				// 去掉下划线
				ds.setUnderlineText(false);
			}
		}, reply.length()+3+poseterNameLength+ReplyNameLength, reply.length()+3+poseterNameLength+ReplyNameLength+wordsLength, 0);
		
		if(!comment.getTrans().equals("") && comment.getTrans() != null){
			//添加翻译内容
			ssb.append(comment.getTrans());
			ssb.setSpan(new ClickableSpan() {
				@Override
				public void onClick(View widget) {
				}
				@Override
				public void updateDrawState(TextPaint ds) {
					// TODO Auto-generated method stub
					super.updateDrawState(ds);
					ds.setColor(context.getResources().getColor(R.color.note_praiseblue_name));
					// 去掉下划线
					ds.setUnderlineText(false);
				}
			}, reply.length()+3+poseterNameLength+ReplyNameLength+wordsLength, reply.length()+3+poseterNameLength+ReplyNameLength+wordsLength+comment.getTrans().length(), 0);
		}else{
			comment.setTrans("");
		}
		//设置翻译图标的大小
//		Drawable drawable = context.getResources().getDrawable(R.drawable.comment_translation); 
//		drawable.setBounds(0, 0, 35, 35); 
		
		ssb.append("p");
		//添加翻译图标
		ImageSpan span = new ImageSpan(context, R.drawable.comment_translation);
//		ImageSpan span = new ImageSpan(drawable);
		
		ssb.setSpan(span, reply.length()+3+poseterNameLength+ReplyNameLength+wordsLength+comment.getTrans().length(), reply.length()+4+poseterNameLength+ReplyNameLength+wordsLength+comment.getTrans().length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
		ssb.setSpan(new ClickableSpan() {
			
			@Override
			public void onClick(View widget) {
				//评论的翻译和新鲜事的翻译不同,注意
				commentTransPopu.initPopuwindow(comment.getWords(), dynamicId, Contants.userID,i);
			}
		}, reply.length()+3+poseterNameLength+ReplyNameLength+wordsLength+comment.getTrans().length(), reply.length()+4+poseterNameLength+ReplyNameLength+wordsLength+comment.getTrans().length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
//		spanStr.setSpan(span, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
		 
//		//截取
//		String[] likeUsers = str.split("、");
//		if (likeUsers.length > 0) {
//			// 最后一个
//			for (int i = 0; i < likeUsers.length; i++) {
//				String names = likeUsers[i];
//				if(i == 1){
//					 names = "  2"+names;
//				}
//				final String name = names;
//				
//				final int start = str.indexOf(name) + spanStr.length();
//				//添加到后面
//				ssb.setSpan(new ClickableSpan() {
// 
//					@Override
//					public void onClick(View widget) {
//						Toast.makeText(context, name,
//								Toast.LENGTH_SHORT).show();
//					}
// 
//					@Override
//					public void updateDrawState(TextPaint ds) {
//						super.updateDrawState(ds);
						if(name.equals("username-1")){
						ds.setColor(Color.RED); // 设置文本颜色
						}
//						ds.setColor(context.getResources().getColor(R.color.note_praiseblue_name));
//						// 去掉下划线
//						ds.setUnderlineText(false);
//					}
// 
//				}, start, start + name.length(), 0);
//			}
//		}
		
		return ssb;
	}


span的使用方法:


void android.text.SpannableStringBuilder.setSpan(Object what, int start, int end, int flags)

Object what:你要塞入的内容。
int start:从几个字符开始。
int end:到第几个字符结束。
int flags:setSpan时需要指定的 flag,它是用来标识在 Span 范围内的文本前后输入新的字符时是否把它们也应用这个效果。分别有 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括)、Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)、Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、Spanned.SPAN_INCLUSIVE_INCLUSIVE(前后都包括)。
setSpan可以设置点击时间:new ClickableSpan()


Android小学生所写,请轻喷~~


  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值