朋友圈列表的點(diǎn)擊“全文”展開(kāi)、點(diǎn)擊“收起”折疊,實(shí)現(xiàn)起來(lái)很簡(jiǎn)單,主要是以下兩步:
- 獲取item文本的行數(shù)
- 記錄item文本的狀態(tài)
1.獲取文本的行數(shù)
很容易想到獲取文本的行數(shù),超出規(guī)定行數(shù)便折疊文本,但沒(méi)有方法可以直接根據(jù)字?jǐn)?shù)計(jì)算出TextView的行數(shù),所以只能用
content.setText();
content.getLineCount();
這時(shí)會(huì)發(fā)現(xiàn)這樣獲取到的行數(shù)為0,因?yàn)?code>setText()后立即調(diào)用getLineCount()TextView還未完成measure,要想準(zhǔn)確獲取到TextView的行數(shù)有兩種方法:
- ViewTreeObserver監(jiān)聽(tīng)View初始化的各種狀態(tài)
使用它的OnPreDrawListener在TextView完成測(cè)量和定位即將繪制時(shí)調(diào)用getLineCount()即可得到TextView的真實(shí)行數(shù) - View.post(Runnable r)方法
這個(gè)Runnable會(huì)被添加到一個(gè)順序執(zhí)行的UI事件隊(duì)列,等執(zhí)行到里面的代碼時(shí),View已經(jīng)完成了measure和layout等一系列初始化工作,所以可以正確獲取到View的高度等信息,很好用的方法,相比第一種方法的好處就是代碼少且只執(zhí)行一次,不用取消監(jiān)聽(tīng)The UI event queue will process events in order. After setContentView() is invoked, the event queue will contain a message asking for a relayout, so anything you post to the queue will happen after the layout pass
這里還是用了第一種方法ViewTreeObserver,感覺(jué)語(yǔ)義性更好
holder.content.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
//這個(gè)回調(diào)會(huì)調(diào)用多次,獲取完行數(shù)記得注銷監(jiān)聽(tīng)
holder.content.getViewTreeObserver().removeOnPreDrawListener(this);
if(holder.content.getLineCount() > MAX_LINE_COUNT){
holder.content.setMaxLines(MAX_LINE_COUNT);
holder.expandOrCollapse.setVisibility(View.VISIBLE);
holder.expandOrCollapse.setText("全文");
}else{
holder.expandOrCollapse.setVisibility(View.GONE);
}
return true;
}
});
holder.content.setMaxLines(Integer.MAX_VALUE);
holder.content.setText(Util.getContent(position));
2.記錄item文本的狀態(tài)
如果只是像上面寫(xiě)的那樣每次初始化item時(shí)去獲取文本的行數(shù),然后根據(jù)行數(shù)選擇是否折疊文本的話,會(huì)引發(fā)一個(gè)問(wèn)題:
**
即已經(jīng)獲取過(guò)行數(shù)的position item滑出可視范圍又滑回來(lái)時(shí),根據(jù)RecyclerView的復(fù)用,TextView又會(huì)被重新測(cè)量高度行數(shù)然后是否折疊,有興趣的同學(xué)可以試試,從列表頂部往下滑是沒(méi)問(wèn)題,但從底部往上滑,列表會(huì)不斷跳動(dòng),在文字多的情況下甚至滑不回頂部,因?yàn)樯厦婕磳⑦M(jìn)入可視范圍的item始終處于measure(展開(kāi))和超出行數(shù)折疊文本的死循環(huán)
**
所以當(dāng)獲取完每個(gè)position上的item文本行數(shù)后應(yīng)把信息存起來(lái),在這里我們定義三種狀態(tài)并在每個(gè)item初始化時(shí)保存起來(lái):
STATE_NOT_OVERFLOW //文本不超過(guò)規(guī)定行數(shù)
STATE_COLLAPSED //文本超過(guò)了規(guī)定行數(shù),處于折疊狀態(tài)
STATE_EXPANDED //文本超過(guò)了規(guī)定行數(shù),被點(diǎn)擊后處于展開(kāi)狀態(tài)
代碼如下:
int state = mTextStateList.get(position, STATE_UNKNOW);
//如果該item是第一次初始化,則去獲取文本的行數(shù)
if(state == STATE_UNKNOW){
holder.content.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
//這個(gè)回調(diào)會(huì)調(diào)用多次,獲取完行數(shù)記得注銷監(jiān)聽(tīng)
holder.content.getViewTreeObserver().removeOnPreDrawListener(this);
//記錄文本的狀態(tài)
if(holder.content.getLineCount() > MAX_LINE_COUNT){
holder.content.setMaxLines(MAX_LINE_COUNT);
holder.expandOrCollapse.setVisibility(View.VISIBLE);
holder.expandOrCollapse.setText("全文");
mTextStateList.put(position, STATE_COLLAPSED);
}else{
holder.expandOrCollapse.setVisibility(View.GONE);
mTextStateList.put(position, STATE_NOT_OVERFLOW);
}
return true;
}
});
holder.content.setMaxLines(Integer.MAX_VALUE);
holder.content.setText(Util.getContent(position));
}else{
//如果之前已經(jīng)初始化過(guò)了,則使用保存的狀態(tài),無(wú)需再獲取一次
switch (state){
case STATE_NOT_OVERFLOW:
holder.expandOrCollapse.setVisibility(View.GONE);
break;
case STATE_COLLAPSED:
holder.content.setMaxLines(MAX_LINE_COUNT);
holder.expandOrCollapse.setVisibility(View.VISIBLE);
holder.expandOrCollapse.setText("全文");
break;
case STATE_EXPANDED:
holder.content.setMaxLines(Integer.MAX_VALUE);
holder.expandOrCollapse.setVisibility(View.VISIBLE);
holder.expandOrCollapse.setText("收起");
break;
}
holder.content.setText(Util.getContent(position));
}
最后設(shè)置點(diǎn)擊事件:
holder.expandOrCollapse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int state = mTextStateList.get(position, STATE_UNKNOW);
if(state == STATE_COLLAPSED){
holder.content.setMaxLines(Integer.MAX_VALUE);
holder.expandOrCollapse.setText("收起");
mTextStateList.put(position, STATE_EXPANDED);
}else if(state == STATE_EXPANDED){
holder.content.setMaxLines(MAX_LINE_COUNT);
holder.expandOrCollapse.setText("全文");
mTextStateList.put(position, STATE_COLLAPSED);
}
}
});
最終效果圖如下:
