Skip to content

Instantly share code, notes, and snippets.

@wei-spring
Created September 21, 2016 09:11
Show Gist options
  • Save wei-spring/cb8c58a0a8813867f45795bb4c58703f to your computer and use it in GitHub Desktop.
Save wei-spring/cb8c58a0a8813867f45795bb4c58703f to your computer and use it in GitHub Desktop.
查看更多TextView
/*
* Copyright (C) 2016 Borja Bravo Álvarez
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.borjabravo.readmoretextview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.TextView;
/**
* Created by borja on 17/4/16.
*/
public class ReadMoreTextView extends TextView {
private static final int TRIM_MODE_LINES = 0;
private static final int TRIM_MODE_LENGTH = 1;
private static final int DEFAULT_TRIM_LENGTH = 240;
private static final int DEFAULT_TRIM_LINES = 2;
private static final boolean DEFAULT_SHOW_TRIM_EXPANDED_TEXT = true;
private static final String ELLIPSIZE = "... ";
private CharSequence text;
private BufferType bufferType;
private boolean readMore = true;
private int trimLength;
private CharSequence trimCollapsedText;
private CharSequence trimExpandedText;
private ReadMoreClickableSpan viewMoreSpan;
private int colorClickableText;
private boolean showTrimExpandedText;
private int trimMode;
private int lineEndIndex;
private int trimLines;
public ReadMoreTextView(Context context) {
this(context, null);
}
public ReadMoreTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ReadMoreTextView);
this.trimLength = typedArray.getInt(R.styleable.ReadMoreTextView_trimLength, DEFAULT_TRIM_LENGTH);
int resourceIdTrimCollapsedText =
typedArray.getResourceId(R.styleable.ReadMoreTextView_trimCollapsedText, R.string.read_more);
int resourceIdTrimExpandedText =
typedArray.getResourceId(R.styleable.ReadMoreTextView_trimExpandedText, R.string.read_less);
this.trimCollapsedText = getResources().getString(resourceIdTrimCollapsedText);
this.trimExpandedText = getResources().getString(resourceIdTrimExpandedText);
this.trimLines = typedArray.getInt(R.styleable.ReadMoreTextView_trimLines, DEFAULT_TRIM_LINES);
this.colorClickableText = typedArray.getColor(R.styleable.ReadMoreTextView_colorClickableText,
ContextCompat.getColor(context, R.color.accent));
this.showTrimExpandedText =
typedArray.getBoolean(R.styleable.ReadMoreTextView_showTrimExpandedText, DEFAULT_SHOW_TRIM_EXPANDED_TEXT);
this.trimMode = typedArray.getInt(R.styleable.ReadMoreTextView_trimMode, TRIM_MODE_LINES);
typedArray.recycle();
viewMoreSpan = new ReadMoreClickableSpan();
onGlobalLayoutLineEndIndex();
setText();
}
private void setText() {
super.setText(getDisplayableText(), bufferType);
setMovementMethod(LinkMovementMethod.getInstance());
setHighlightColor(Color.TRANSPARENT);
}
private CharSequence getDisplayableText() {
return getTrimmedText(text);
}
@Override
public void setText(CharSequence text, BufferType type) {
this.text = text;
bufferType = type;
setText();
}
private CharSequence getTrimmedText(CharSequence text) {
if (trimMode == TRIM_MODE_LENGTH) {
if (text != null && text.length() > trimLength) {
if (readMore) {
return updateCollapsedText();
} else {
return updateExpandedText();
}
}
}
if (trimMode == TRIM_MODE_LINES) {
if (text != null && lineEndIndex > 0) {
if (readMore) {
return updateCollapsedText();
} else {
return updateExpandedText();
}
}
}
return text;
}
private CharSequence updateCollapsedText() {
int trimEndIndex = text.length();
switch (trimMode) {
case TRIM_MODE_LINES:
trimEndIndex = lineEndIndex - (ELLIPSIZE.length() + trimCollapsedText.length() + 1);
if (trimEndIndex < 0) {
trimEndIndex = trimLength + 1;
}
break;
case TRIM_MODE_LENGTH:
trimEndIndex = trimLength + 1;
break;
}
SpannableStringBuilder s = new SpannableStringBuilder(text, 0, trimEndIndex)
.append(ELLIPSIZE)
.append(trimCollapsedText);
return addClickableSpan(s, trimCollapsedText);
}
private CharSequence updateExpandedText() {
if (showTrimExpandedText) {
SpannableStringBuilder s = new SpannableStringBuilder(text, 0, text.length()).append(trimExpandedText);
return addClickableSpan(s, trimExpandedText);
}
return text;
}
private CharSequence addClickableSpan(SpannableStringBuilder s, CharSequence trimText) {
s.setSpan(viewMoreSpan, s.length() - trimText.length(), s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return s;
}
public void setTrimLength(int trimLength) {
this.trimLength = trimLength;
setText();
}
public void setColorClickableText(int colorClickableText) {
this.colorClickableText = colorClickableText;
}
public void setTrimCollapsedText(CharSequence trimCollapsedText) {
this.trimCollapsedText = trimCollapsedText;
}
public void setTrimExpandedText(CharSequence trimExpandedText) {
this.trimExpandedText = trimExpandedText;
}
public void setTrimMode(int trimMode) {
this.trimMode = trimMode;
}
public void setTrimLines(int trimLines) {
this.trimLines = trimLines;
}
private class ReadMoreClickableSpan extends ClickableSpan {
@Override
public void onClick(View widget) {
readMore = !readMore;
setText();
}
@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(colorClickableText);
}
}
private void onGlobalLayoutLineEndIndex() {
if (trimMode == TRIM_MODE_LINES) {
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);
}
refreshLineEndIndex();
setText();
}
});
}
}
private void refreshLineEndIndex() {
try {
if (trimLines == 0) {
lineEndIndex = getLayout().getLineEnd(0);
} else if (trimLines > 0 && getLineCount() >= trimLines) {
lineEndIndex = getLayout().getLineEnd(trimLines - 1);
} else {
lineEndIndex = getLayout().getLineEnd(getLayout().getLineCount() - 1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment