Android项目实战(十六)(QQ空间实现—— 展示说说中的评论内容并有相应点击事件)

出门莫恨无人随,书中车马多如簇。这篇文章主要讲述Android项目实战(十六):QQ空间实现—— 展示说说中的评论内容并有相应点击事件相关的知识,希望能为你提供帮助。
原文:Android项目实战(十六):QQ空间实现(一)—— 展示说说中的评论内容并有相应点击事件大家都玩QQ空间客户端,对于每一个说说,我们都可以评论,那么,对于某一条评论:

白雪公主 回复 小矮人 : 你们好啊~

我们来分析一下:
1、QQ空间允许我们 点击 回复人和被回复人的名字就可以进入对于用户的个人主页(即点击文字“ 白雪公主” /“ 小矮人” ,就可以进入到这俩用户相应个人主页) 2、点击 回复的文字,就可以对回复人进行回复(即点击评论中回复的内容“ 你们好啊~” ,便对弹出一个编辑框对回复人“ 白雪公主” 进行回复) 3、回复人 和 被回复人 的名字是有颜色的

效果图:
Android项目实战(十六)(QQ空间实现—— 展示说说中的评论内容并有相应点击事件)

文章图片

作为一个android开发者,我们要实现对一个TextView :
1、点击不同的文字部分(文字个数还不确定)有相应的响应操作(进入个人主页等等)2、一个TextView中某些文字有不同的颜色

下面学习如何实现-->
----------------------------------------------------------------------------------
首先介绍下QQ空间说说列表这一个界面(fragment来实现)的整体框架:
1、使用RecyclerView来展示说说列表     why? 
1、RecyclerView 自带实现复用机制,对于工作1--2年左右的,不建议使用自己写的复用ListView 2、RecyclerView 方便对于某一个item 项的增删改操作 (大优势),比如控件删除该说说的功能的实现 RecyclerView实现更好

2、每一个item 内部 ,评论文字部分 用不可以滑动的ListView(RecyclerView理论上更棒,反正不可以滑动就行了)来展示 (博主一开始想的是用LinearLayout 内部 动态添加TextView来展示,经测试,太麻烦且易出错)
不可滑动的ListView 代码 -->   自定义不可滑动的ListView和GridView
-----------------------------------------------------------------------------------
下面用一个Demo来学习如何实现说说评论的效果:
首先布局文件,就一个不可滑动的ListView,我们Demo只展示评论列表
< RelativeLayout 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"
tools:context=".MainActivity">

< !-- 注意listview要去除分割线 -->
< com.xqx.com.qqhome.NoScrollListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null" >
< /com.xqx.com.qqhome.NoScrollListView>

< /RelativeLayout>

然后是Item项的布局文件(评论文字):
< ?xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> < TextView android:id="@+id/txt_comment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="2dp" /> < /LinearLayout>

-----------------------------------------------------------------------------------
【Android项目实战(十六)(QQ空间实现—— 展示说说中的评论内容并有相应点击事件)】看java文件部分:
MainActivity.java
很简单,自己创建了5条评论,添加到自己写的适配器中
注意:评论有的是没有被回复人的!
 
public class MainActivity extends Activity {private NoScrollListView noScrollListView; /* --------- 数据源----------- */ //记录回复说说用户的集合 private ArrayList< String> name; //记录被回复说说用户的集合 private ArrayList< String> toName; //记录评论内容的集合 private ArrayList< String> content; /* --------- 适配器------------*/ private CommentAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); noScrollListView = (NoScrollListView) findViewById(R.id.listview); name = new ArrayList< > (); toName = new ArrayList< > (); content = new ArrayList< > (); //添加数据 ,Demo只添加5条评论 name.add("白雪公主"); toName.add("小矮人"); content.add("你们好啊~"); name.add("小矮人"); toName.add("白雪公主"); content.add("白雪公主,早上好啊~"); name.add("王子"); toName.add(""); content.add("这条说说很有道理的样子啊~"); name.add("国王"); toName.add(""); content.add("我很喜欢这条说说~"); name.add("白雪公主"); toName.add("王子"); content.add("你也是XX的朋友啊?"); adapter = new CommentAdapter(name,toName,content,this); noScrollListView.setAdapter(adapter); }}

 
 
 
-----------------------------------------------------------------------------------
  布局文件有了,MainActivity有了,剩下最主要的适配器了
  看下自定义适配器所需要的属性 和 写个必要方法:
public class CommentAdapter extends BaseAdapter {/* --------- 数据源----------- */ //记录回复说说用户的集合 private ArrayList< String> name; //记录被回复说说用户的集合 private ArrayList< String> toName; //记录评论内容的集合 private ArrayList< String> content; private Context context; public CommentAdapter(ArrayList< String> name, ArrayList< String> toName, ArrayList< String> content, Context context) { this.name = name; this.toName = toName; this.content = content; this.context = context; }@Override public int getCount() { int ret = 0; if (name != null& & name.size()!=0) ret = name.size(); return ret; }@Override public Object getItem(int position) { return position; }@Override public long getItemId(int position) { return position; }

class ViewHolder{
TextView txt_comment;
}

 
重点来了 getView() ~~
首先 建议大家要看下这几篇文章
(转) SpannableString与SpannableStringBuilder
TextView显示html样式的文字
浅谈ClickableSpan , 实现TextView文本某一部分文字的点击响应
然后~~
注释都在代码中:
@Override public View getView(int position, View convertView, ViewGroup parent) { //其实评论一般都是文字,高级点的带有图片评论,光文字的话复用不复用就没什么大区别了 View view = null; if(convertView!=null) { view = convertView; } else { view = LayoutInflater.from(context).inflate(R.layout.item_comment, parent,false); } ViewHolder holder = (ViewHolder) view.getTag(); if(holder==null) { holder = new ViewHolder(); holder.txt_comment = (TextView) view.findViewById(R.id.txt_comment); view.setTag(holder); } //给相应位置的文字赋内容 if (name != null & & name.size()!=0) { StringBuilder actionText = new StringBuilder(); //谁回复 actionText.append("< a style=\\"text-decoration:none; \\" href=https://www.songbingjia.com/android/‘name‘ > < font color=‘#1468a3‘>" + name.get(position)+ "< /font> < /a> "); // 回复谁,被回复的人可能不存在。 if(toName.get(position)!=null& & toName.get(position).length()> 0) { actionText.append("回复"); actionText.append("< font color=‘#1468a3‘> < a style=\\"text-decoration:none; \\" href=https://www.songbingjia.com/android/‘toName‘>" + toName.get(position) + " " + " < /a> < /font> "); } // 内容 actionText.append("< font color=‘#484848‘> < a style=\\"text-decoration:none; \\" href=https://www.songbingjia.com/android/‘content‘>" + ":" + content.get(position) + " " + " < /a> < /font> "); holder.txt_comment.setText(html.fromHtml(actionText.toString())); holder.txt_comment.setMovementMethod(LinkMovementMethod .getInstance()); CharSequence text = holder.txt_comment.getText(); int ends = text.length(); Spannable spannable = (Spannable) holder.txt_comment.getText(); URLSpan[] urlspan = spannable.getSpans(0, ends, URLSpan.class); SpannableStringBuilder stylesBuilder = new SpannableStringBuilder(text); stylesBuilder.clearSpans(); for (URLSpan url : urlspan) { FeedTextViewURLSpan myURLSpan = new FeedTextViewURLSpan(url.getURL(), context,name.get(position),toName.get(position),content.get(position)); stylesBuilder.setSpan(myURLSpan, spannable.getSpanStart(url), spannable.getSpanEnd(url), spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } holder.txt_comment.setText(stylesBuilder); holder.txt_comment.setFocusable(false); holder.txt_comment.setClickable(false); holder.txt_comment.setLongClickable(false); }return view; }static class FeedTextViewURLSpan extends ClickableSpan { private String clickString; private Context context; // 回复人的名字 private String name; // 被回复人的名字 private String toName; // 评论内容 private String content; public FeedTextViewURLSpan(String clickString, Context context, String name, String toName, String content) { this.clickString = clickString; this.context = context; this.name = name; this.toName = toName; this.content = content; }@Override public void updateDrawState(TextPaint ds) { ds.setUnderlineText(false); //给标记的部分 的文字 添加颜色 if(clickString.equals("toName")){ ds.setColor(context.getResources().getColor(R.color.blue)); }else if(clickString.equals("name")){ ds.setColor(context.getResources().getColor(R.color.blue)); } }@Override public void onClick(View widget) { // 根据文字的标记 来进行相应的 响应事件 if (clickString.equals("toName")) { //可以再次进行跳转activity的操作 Toast.makeText(context,"点击了"+toName,Toast.LENGTH_SHORT).show(); } else if (clickString.equals("name")) { //可以再次进行跳转activity的操作 Toast.makeText(context,"点击了"+name,Toast.LENGTH_SHORT).show(); } else if(clickString.equals("content")){ //可以再次进去回复评论的操作 Toast.makeText(context,"点击了"+content,Toast.LENGTH_SHORT).show(); } } }

 
  适配器完整代码:
Android项目实战(十六)(QQ空间实现—— 展示说说中的评论内容并有相应点击事件)

文章图片
Android项目实战(十六)(QQ空间实现—— 展示说说中的评论内容并有相应点击事件)

文章图片
import android.content.Context; import android.text.Html; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextPaint; import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Adapter; import android.widget.BaseAdapter; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; public class CommentAdapter extends BaseAdapter {/* --------- 数据源----------- */ //记录回复说说用户的集合 private ArrayList< String> name; //记录被回复说说用户的集合 private ArrayList< String> toName; //记录评论内容的集合 private ArrayList< String> content; private Context context; public CommentAdapter(ArrayList< String> name, ArrayList< String> toName, ArrayList< String> content, Context context) { this.name = name; this.toName = toName; this.content = content; this.context = context; }@Override public int getCount() { int ret = 0; if (name != null& & name.size()!=0) ret = name.size(); return ret; }@Override public Object getItem(int position) { return position; }@Override public long getItemId(int position) { return position; }@Override public View getView(int position, View convertView, ViewGroup parent) { //其实评论一般都是文字,高级点的带有图片评论,光文字的话复用不复用就没什么大区别了 View view = null; if(convertView!=null) { view = convertView; } else { view = LayoutInflater.from(context).inflate(R.layout.item_comment, parent,false); } ViewHolder holder = (ViewHolder) view.getTag(); if(holder==null) { holder = new ViewHolder(); holder.txt_comment = (TextView) view.findViewById(R.id.txt_comment); view.setTag(holder); } //给相应位置的文字赋内容 if (name != null & & name.size()!=0) { StringBuilder actionText = new StringBuilder(); //谁回复 actionText.append("< a style=\\"text-decoration:none; \\" href=https://www.songbingjia.com/android/‘name‘ > < font color=‘#1468a3‘>" + name.get(position)+ "< /font> < /a> "); // 回复谁,被回复的人可能不存在。 if(toName.get(position)!=null& & toName.get(position).length()> 0) { actionText.append("回复"); actionText.append("< font color=‘#1468a3‘> < a style=\\"text-decoration:none; \\" href=https://www.songbingjia.com/android/‘toName‘>" + toName.get(position) + " " + " < /a> < /font> "); } // 内容 actionText.append("< font color=‘#484848‘> < a style=\\"text-decoration:none; \\" href=https://www.songbingjia.com/android/‘content‘>" + ":" + content.get(position) + " " + " < /a> < /font> "); holder.txt_comment.setText(Html.fromHtml(actionText.toString())); holder.txt_comment.setMovementMethod(LinkMovementMethod .getInstance()); CharSequence text = holder.txt_comment.getText(); int ends = text.length(); Spannable spannable = (Spannable) holder.txt_comment.getText(); URLSpan[] urlspan = spannable.getSpans(0, ends, URLSpan.class); SpannableStringBuilder stylesBuilder = new SpannableStringBuilder(text); stylesBuilder.clearSpans(); for (URLSpan url : urlspan) { FeedTextViewURLSpan myURLSpan = new FeedTextViewURLSpan(url.getURL(), context,name.get(position),toName.get(position),content.get(position)); stylesBuilder.setSpan(myURLSpan, spannable.getSpanStart(url), spannable.getSpanEnd(url), spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } holder.txt_comment.setText(stylesBuilder); holder.txt_comment.setFocusable(false); holder.txt_comment.setClickable(false); holder.txt_comment.setLongClickable(false); }return view; }static class FeedTextViewURLSpan extends ClickableSpan { private String clickString; private Context context; // 回复人的名字 private String name; // 被回复人的名字 private String toName; // 评论内容 private String content; public FeedTextViewURLSpan(String clickString, Context context, String name, String toName, String content) { this.clickString = clickString; this.context = context; this.name = name; this.toName = toName; this.content = content; }@Override public void updateDrawState(TextPaint ds) { ds.setUnderlineText(false); //给标记的部分 的文字 添加颜色 if(clickString.equals("toName")){ ds.setColor(context.getResources().getColor(R.color.blue)); }else if(clickString.equals("name")){ ds.setColor(context.getResources().getColor(R.color.blue)); } }@Override public void onClick(View widget) { // 根据文字的标记 来进行相应的 响应事件 if (clickString.equals("toName")) { //可以再次进行跳转activity的操作 Toast.makeText(context,"点击了"+toName,Toast.LENGTH_SHORT).show(); } else if (clickString.equals("name")) { //可以再次进行跳转activity的操作 Toast.makeText(context,"点击了"+name,Toast.LENGTH_SHORT).show(); } else if(clickString.equals("content")){ //可以再次进去回复评论的操作 Toast.makeText(context,"点击了"+content,Toast.LENGTH_SHORT).show(); }} }class ViewHolder{ TextView txt_comment; }}

CommentAdapter.java 
-----------------------------------------------------------------------------------
  如何实现QQ空间说说列表评论的展示介绍完了~~
  那么如何 回复评论呢?
      如何将新评论的评论及时的显示在当前列表呢?
      之后的博客继续讨论~~~
 
相关知识:
QQ空间实现(二)— — 分享功能 / 弹出PopupWindow
 
博主现在从事社交类社区类APP开发,有同领域的朋友欢迎关注交流~~~                                                                                         
         



















    推荐阅读