项目需求是可以实现文章的点开查看全文和收起功能这里用到了
SpannableStringBuilder进行拼接,对文章行数以及字数进行相关的处理,然后进行点击事件的处理
结果最后出现了问题:在同一段文字中,点击可点击文字部分时,所有的文字也会响应,也就是span响应的同时,onclick也响应了
第一时间想到的就是怎么拦截它
下面奉上自定义的这个View
public class CollapsedTextView extends androidx.appcompat.widget.AppCompatTextView {
/**
* 收起状态下的最大行数
*/
private int maxLine = 1;
/**
* 截取后,文本末尾的字符串
*/
private static final String ELLIPSE = "...";
/**
* 默认全文的Text
*/
private static final String EXPANDEDTEXT = "展开全文";
/**
* 默认收起的text
*/
private static final String COLLAPSEDTEXT = "收起";
/**
* 所有行数
*/
private int allLines = 1;
/**
* 是否是收起状态,默认收起
*/
private boolean collapsed = true;
/**
* 真实的text
*/
private String text;
/**
* 收起时实际显示的text
*/
private CharSequence collapsedCs;
private SpannableStringBuilder downBT;
private SpannableStringBuilder upBT;
public CollapsedTextView(Context context) {
super(context);
initView(context, null);
}
public CollapsedTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public CollapsedTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
downBT = new SpannableStringBuilder("展开全文");
Drawable dDown = getResources().getDrawable(R.drawable.ic_launcher);//subs_descibe_up
dDown.setBounds(0, 0, dDown.getIntrinsicWidth() , dDown.getIntrinsicHeight());
//创建ImageSpan
ImageSpan downSpan = new ImageSpan(dDown, ImageSpan.ALIGN_BASELINE);
//用ImageSpan替换文本
downBT.setSpan(EXPANDEDTEXT, 0, downBT.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
// downBT.setSpan(downSpan, 0, downBT.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//图标
upBT = new SpannableStringBuilder(" 收起");
Drawable dUp = getResources().getDrawable(R.drawable.ic_launcher);//subs_descibe_down
dUp.setBounds(0, 0, dUp.getIntrinsicWidth(), dUp.getIntrinsicHeight());
//创建ImageSpan
ImageSpan upSpan = new ImageSpan(dUp, ImageSpan.ALIGN_BASELINE);
//用ImageSpan替换文本
upBT.setSpan(COLLAPSEDTEXT, 0, upBT.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
// upBT.setSpan(upSpan, 0, upBT.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//图标
}
public void setShowText(String text) {
this.text = text;
if (allLines > 0) {
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
ViewTreeObserver obs = getViewTreeObserver();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
obs.removeOnGlobalLayoutListener(this);
} else {
obs.removeGlobalOnLayoutListener(this);
}
TextPaint paint = getPaint();
float measureText = paint.measureText(text);
int showWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int lines = (int) (measureText / showWidth);
if (measureText % showWidth != 0) {
lines++;
}
allLines = (int) (paint.measureText(text + downBT) / showWidth);
if (lines > maxLine) {
int expect = text.length() / lines;
int end = 0;
int lastLineEnd = 0;
int expandedTextWidth = (int) paint.measureText(ELLIPSE + downBT);
//计算每行显示文本数
for (int i = 1; i <= maxLine; i++) {
int tempWidth = 0;
if (i == maxLine) {
tempWidth = expandedTextWidth;
}
end += expect;
if (end > text.length()) {
end = text.length();
}
if (paint.measureText(text, lastLineEnd, end) > showWidth - tempWidth) {
//预期的第一行超过了实际显示的宽度
end--;
while (paint.measureText(text, lastLineEnd, end) > showWidth - tempWidth) {
end--;
}
} else {
end++;
while (paint.measureText(text, lastLineEnd, end) < showWidth - tempWidth) {
end++;
}
end--;
}
lastLineEnd = end;
}
setMovementMethod(MyLinkedMovementMethod.getInstance());
SpannableStringBuilder s = new SpannableStringBuilder(text, 0, end)
.append(ELLIPSE);
collapsedCs = addClickableSpan(s, downBT);
setText(collapsedCs);
append(downBT);
} else {
setText(text);
}
}
});
}
}
private static class MyLinkedMovementMethod extends LinkMovementMethod{
private static MyLinkedMovementMethod sInstance;
public static MyLinkedMovementMethod getInstance() {
if (sInstance == null)
sInstance = new MyLinkedMovementMethod();
return sInstance;
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
// 因为TextView没有点击事件,所以点击TextView的非富文本时,super.onTouchEvent()返回false;
// 此时可以让TextView的父容器执行点击事件;
boolean isConsume = super.onTouchEvent(widget, buffer, event);
if (!isConsume && event.getAction() == MotionEvent.ACTION_UP) {
ViewParent parent = widget.getParent();
if (parent instanceof ViewGroup) {
// 获取被点击控件的父容器,让父容器执行点击;
((ViewGroup) parent).performClick();
}
}
return isConsume;
}
}
private CharSequence addClickableSpan(SpannableStringBuilder s, SpannableStringBuilder collapsedText) {
collapsedText.setSpan(new ClickableSpan() {//这里用可以点击的部分进行setspan
@Override
public void onClick(@NonNull View widget) {
if (collapsed) {
SpannableStringBuilder s = new SpannableStringBuilder(text);
setText(addClickableSpan(s, upBT));
append(upBT);
} else {
setText(collapsedCs);
append(downBT);
}
collapsed = !collapsed;
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setAntiAlias(true);
ds.setUnderlineText(false);
}
},0, collapsedText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return s;
}
}
借鉴文章:https://blog.youkuaiyun.com/Love667767/article/details/82903992
903

被折叠的 条评论
为什么被折叠?



