网上找了很多三方的实现但是都不是我想要的效果或者实现比较复杂,然后就自己写了一个。
就这种效果其实就是很轻量级的一个实现。
首先看我实现的第一个版本。
public class ExpandTextView extends AppCompatTextView {
/**
* 的右侧文字Drawable
*/
private TextDrawable mTextDrawable;
/**
* 点击了展开按钮
*/
private boolean clickExpanded = false;
/**
* 允许输入的最大行数
*/
private volatile int mMaxline = -1;
public ExpandTextView(Context context) {
this(context, null);
}
public ExpandTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public ExpandTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mTextDrawable = new TextDrawable(context);
String str = "「展开」";
SpannableString spannableString = new SpannableString(str);
spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#9891FB")), 1, str.length() - 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextDrawable.setText(spannableString);
mTextDrawable.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
mTextDrawable.setTextColor(Color.parseColor("#FF282828"));
mTextDrawable.setTextAlign(Layout.Alignment.ALIGN_CENTER);
mTextDrawable.setBounds(0, 0, mTextDrawable.getIntrinsicWidth(), mTextDrawable.getIntrinsicHeight());
}
@Override
public void setMaxLines(int maxLines) {
mMaxline = maxLines;
}
private void setTextDrawableVisible(boolean visible) {
Drawable rightDrawble = visible ? mTextDrawable : null;
setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightDrawble, getCompoundDrawables()[3]);
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
registerpredrawListener();
}
private void registerpredrawListener() {
RxView.preDraws(this, new Function0<Boolean>() {
@Override
public Boolean invoke() {
return false;
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver<Unit>() {
@Override
public void onNext(Unit bean) {
dispose();
int lineCouunt = getLineCount();
if (lineCouunt > 1) {
setGravity(Gravity.LEFT);
if (clickExpanded) {
//点击过展开按钮就不再显示展开按钮了,直接设置最大行数
ExpandTextView.super.setMaxLines(mMaxline < 0 ? Integer.MAX_VALUE : mMaxline);
setTextDrawableVisible(false);
} else {
//没有点击过展开按钮
ExpandTextView.super.setMaxLines(1);
setTextDrawableVisible(true);
}
} else {
setGravity(Gravity.CENTER);
setTextDrawableVisible(false);
}
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (getCompoundDrawables()[2] != null) {
float x = event.getX();
float padRight = getPaddingRight();
float iconWidth = getCompoundDrawables()[2].getIntrinsicWidth();
boolean touchAble = (x > (getWidth() - padRight - iconWidth)) && (x < getWidth() - padRight);
if (touchAble) {
clickExpanded = true;
super.setMaxLines(mMaxline < 0 ? Integer.MAX_VALUE : mMaxline);
setTextDrawableVisible(false);
}
}
}
return super.onTouchEvent(event);
}
}
实现方法很简单,就是在右侧的Drawable中添加一个展开的文本形式的Drawable,然后给它一个点击事件,点击就把Maxlines修改掉。在OnPreDrawListener中获取TextView的lineCount对展开按钮进行显示与隐藏的控制。这么做没有太大的毛病,但是我将其放在了可以滑动的布局中,在展开文本后就有问题了,布局就不能滑动了。因为开展之后测量的布局不准了。为了解决这个问题我写了第二个版本
public class ExpandableTextView extends AppCompatTextView {
/**
* 的右侧文字Drawable
*/
private TextDrawable mTextDrawable;
/**
* 点击了展开按钮
*/
private boolean clickExpanded = false;
/**
* 允许输入的最大行数
*/
private volatile int mMaxline = -1;
public ExpandableTextView(Context context) {
this(context, null);
}
public ExpandableTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public ExpandableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mTextDrawable = new TextDrawable(context);
String str = "「展开」";
SpannableString spannableString = new SpannableString(str);
spannableString.setSpan(new ForegroundColorSpan(Color.parseColor("#9891FB")), 1, str.length() - 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextDrawable.setText(spannableString);
mTextDrawable.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
mTextDrawable.setTextColor(Color.parseColor("#FF282828"));
mTextDrawable.setTextAlign(Layout.Alignment.ALIGN_CENTER);
mTextDrawable.setBounds(0, 0, mTextDrawable.getIntrinsicWidth(), mTextDrawable.getIntrinsicHeight());
}
@Override
public void setMaxLines(int maxLines) {
mMaxline = maxLines;
}
private void setTextDrawableVisible(boolean visible) {
Drawable rightDrawble = visible ? mTextDrawable : null;
setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightDrawble, getCompoundDrawables()[3]);
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ExpandableTextView.super.setMaxLines(mMaxline < 0 ? Integer.MAX_VALUE : mMaxline);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int lineCouunt = getLineCount();
if (lineCouunt > 1) {
setGravity(Gravity.LEFT);
if (clickExpanded) {
//点击过展开按钮就不再显示展开按钮了,直接设置最大行数
ExpandableTextView.super.setMaxLines(mMaxline < 0 ? Integer.MAX_VALUE : mMaxline);
setTextDrawableVisible(false);
} else {
//没有点击过展开按钮
ExpandableTextView.super.setMaxLines(1);
setTextDrawableVisible(true);
}
} else {
setGravity(Gravity.CENTER);
setTextDrawableVisible(false);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (getCompoundDrawables()[2] != null) {
float x = event.getX();
float padRight = getPaddingRight();
float iconWidth = getCompoundDrawables()[2].getIntrinsicWidth();
boolean touchAble = (x > (getWidth() - padRight - iconWidth)) && (x < getWidth() - padRight);
if (touchAble) {
clickExpanded = true;
requestLayout();
}
}
}
return super.onTouchEvent(event);
}
}
在TextView的onMeasure中获取lineCount对展开按钮进行控制,如果TextView已经展开就再进行一次测量。这样展开后的测量数据就是准确的了。