Android實現朋友圈全文/收起的功能
阿新 • • 發佈:2019-02-18
看下效果圖:
首先我們先理解收起和全文的邏輯:
假如產品設定:文字超過三行就要摺疊
1 如果文字不超過三行,那麼就不顯示“全文”和“收起”
2 如果超過了三行顯示“全文”,點選全文就可以看到所有文字,同時最下面顯示“收起”
難點在如何記錄每個Item的收起和全文的狀態?
我們知道RecyerView和ListView都是複用ViewHolder,所以免不了有一個Holder要分別渲染兩次資料,平時我們做的資料渲染只是把資料塗在了ViewHolder上,不影響Holder本身,但是這裡需要改變Holder裡面的狀態,改變之後會影響下一個Holder的顯示,如何解決呢?
關於這個BaseHolder和BaseAdapterAgency,大家可以看下我的上一篇文章打造一款簡化RecyclerView使用的開源庫
public class TextHolder extends BaseHolder<News> {
private TextView content;
private TextView all_text;
private final int MAX_LINE_COUNT = 3;//最大顯示行數
private final int STATE_UNKNOW = -1;//未知狀態
private final int STATE_NOT_OVERFLOW = 1;//文字行數小於最大可顯示行數
private final int STATE_COLLAPSED = 2;//摺疊狀態
private final int STATE_EXPANDED = 3;//展開狀態
private SparseArray<Integer> mTextStateList;//儲存文字狀態集合
public TextHolder(View itemView) {
super(itemView);
content = itemView.findViewById(R.id.content);
all_text = itemView.findViewById(R.id.all_text);
}
@Override
public void bindViewHolder(News news) {
bindViewHolder(news,null);
}
/**
* 具體的繫結檢視的操作
* @param news
* @param o
*/
public void bindViewHolder(final News news, final Object o) {
mTextStateList = (SparseArray<Integer>) o;
int state = mTextStateList.get(news.getId(), STATE_UNKNOW);
//第一次初始化,未知狀態
if (state == STATE_UNKNOW) {
content.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
//這個回掉會呼叫多次,獲取完行數後記得登出監聽
content.getViewTreeObserver().removeOnPreDrawListener(this);
//content.getViewTreeObserver().addOnPreDrawListener(null);
//如果內容顯示的行數大於最大顯示行數
if (content.getLineCount() > MAX_LINE_COUNT) {
content.setMaxLines(MAX_LINE_COUNT);//設定最大顯示行數
all_text.setVisibility(View.VISIBLE);//顯示“全文”
all_text.setText("全文");
mTextStateList.put(news.getId(), STATE_COLLAPSED);//儲存狀態
} else {
all_text.setVisibility(View.GONE);
mTextStateList.put(news.getId(), STATE_NOT_OVERFLOW);
}
return true;
}
});
content.setMaxLines(Integer.MAX_VALUE);//設定文字的最大行數,為整數的最大數值
content.setText(news.getContent());
} else {
//如果之前已經初始化過了,則使用儲存的狀態。
switch (state) {
case STATE_NOT_OVERFLOW:
all_text.setVisibility(View.GONE);
break;
case STATE_COLLAPSED:
content.setMaxLines(MAX_LINE_COUNT);
all_text.setVisibility(View.VISIBLE);
all_text.setText("全文");
break;
case STATE_EXPANDED:
content.setMaxLines(Integer.MAX_VALUE);
all_text.setVisibility(View.VISIBLE);
all_text.setText("收起");
break;
}
content.setText(news.getContent());
}
//全文和收起的點選事件
all_text.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int state = mTextStateList.get(news.getId(), STATE_UNKNOW);
if (state == STATE_COLLAPSED) {
content.setMaxLines(Integer.MAX_VALUE);
all_text.setText("收起");
mTextStateList.put(news.getId(), STATE_EXPANDED);
} else if (state == STATE_EXPANDED) {
content.setMaxLines(MAX_LINE_COUNT);
all_text.setText("全文");
mTextStateList.put(news.getId(), STATE_COLLAPSED);
}
}
});
}
}
public class NewsAgency extends BaseAdapterAgency<News> {
private Context context;
private Activity mContent;
/**
* 注意:儲存文字狀態集合的key一定要是唯一的,如果用position。
* 如果使用position作為key,則刪除、增加條目的時候會出現顯示錯亂
* 而且不能在Holder裡面建立!!!
*/
private SparseArray<Integer> mTextStateList;//儲存文字狀態集合
List<News> mList;
public NewsAgency(List<News> list, Activity context) {
super(context,list);
mContent = context;
this.mList = list;
mTextStateList = new SparseArray<>();
}
@Override
public void onBindViewHolder(BaseHolder holder, int position) {
if(holder instanceof TextHolder){
((TextHolder) holder).bindViewHolder(mList.get(position),mTextStateList);
}
}
@Override
public int getItemCount() {
return mList.size();
}
@Override
public int getAdapterItemViewType(int i) {
return 0;
}
@Override
public BaseHolder createBaseHolder(ViewGroup viewGroup, int i) {
return new TextHolder(mContent.getLayoutInflater().inflate(R.layout.item_text, viewGroup, false));
}
}
最後想說的是:
雖然網上有開源的庫可以顯示全文和收起,但是我認為開源庫的最大問題是靈活的程度(擴充套件性),假如產品讓你把文字顯示為居中,居左,居右,顏色,字型,字號等等改變的時候,開源庫很少能做到如此面面俱到,所以還是使用這種原生的方式比較好~