大家都玩QQ空間用戶端,對于每一個說說,我們都可以評論,那麼,對于某一條評論:
白雪公主 回複 小矮人 : 你們好啊~
我們來分析一下:
1、QQ空間允許我們 點選 回複人和被回複人的名字就可以進入對于使用者的個人首頁(即點選文字“白雪公主”/“小矮人”,就可以進入到這倆使用者相應個人首頁)
2、點選 回複的文字,就可以對回複人進行回複(即點選評論中回複的内容“你們好啊~”,便對彈出一個編輯框對回複人“白雪公主”進行回複)
3、回複人 和 被回複人 的名字是有顔色的
效果圖:
作為一個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>
看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='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='toName'>"
+ toName.get(position) + " " + " </a></font>");
}
// 内容
actionText.append("<font color='#484848'><a style=\"text-decoration:none;\" href='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();
}
}
}
擴充卡完整代碼:

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='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='toName'>"
+ toName.get(position) + " " + " </a></font>");
}
// 内容
actionText.append("<font color='#484848'><a style=\"text-decoration:none;\" href='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開發,有同領域的朋友歡迎關注交流~~~
作者:聽着music睡
出處:http://www.cnblogs.com/xqxacm/
Android交流群:38197636
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。