@@ -37,6 +37,11 @@ public class TextViewReadMore extends AppCompatTextView {
3737
3838 private static final String DEFAULT_EXPAND_TEXT = "Read More" ;
3939 private static final String DEFAULT_COLLAPSE_TEXT = "Close" ;
40+ private static final String DOTS_CODE = "\u2026 " ;
41+ private static final String SPACE_CODE = "\u00A0 " ;
42+
43+ private static final int ELLIPSIS_TYPE_DOTS = 0 ;
44+ private static final int ELLIPSIS_TYPE_NONE = 1 ;
4045
4146 private String text ;
4247
@@ -68,6 +73,7 @@ public class TextViewReadMore extends AppCompatTextView {
6873 private View .OnClickListener onClickExpand ;
6974 private View .OnClickListener onClickCollapse ;
7075 private int actionClickColor = 0 ;
76+ private int ellipsisType = ELLIPSIS_TYPE_DOTS ;
7177
7278 private static long mLastClickTime = 0 ;
7379
@@ -110,11 +116,15 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
110116 collapseTextStyle = typedArray .getInt (R .styleable .TextViewReadMore_collapseTextStyle , 0 );
111117 collapseTextUnderline = typedArray .getBoolean (R .styleable .TextViewReadMore_collapseTextUnderline , collapseTextUnderline );
112118
119+
113120 int defaultActionClickColor = ContextCompat .getColor (context , R .color .text_view_read_more_button_hover_color );
114121 actionClickColor = typedArray .getColor (R .styleable .TextViewReadMore_actionClickColor , defaultActionClickColor );
115122
116123 int getAnimationDuration = typedArray .getInt (R .styleable .TextViewReadMore_android_animationDuration , animationDuration );
117124 animationDuration = Math .max (getAnimationDuration , 100 );
125+
126+ ellipsisType = typedArray .getInt (R .styleable .TextViewReadMore_ellipsisType , ELLIPSIS_TYPE_DOTS );
127+
118128 } finally {
119129 typedArray .recycle ();
120130 }
@@ -161,13 +171,13 @@ private void buildSpan() {
161171 } else {
162172 expandBuilder ();
163173 setText (spanExpanded );
164- ViewGroup .LayoutParams params = getLayoutParams ();
165- params .height = ViewGroup .LayoutParams .WRAP_CONTENT ;
166- setLayoutParams (params );
174+ setWrapLayout ();
167175 }
168176 setMovementMethod (LinkMovementMethod .getInstance ());
169177 rebuild = false ;
170178 }
179+ } else {
180+ setWrapLayout ();
171181 }
172182 }
173183 }
@@ -189,29 +199,51 @@ private boolean isEllipsized(String text) {
189199
190200 private void collapsedBuilder () {
191201 StaticLayout layout ;
202+ String replaceSpace = textReplaceSpace ();
192203 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
193204 layout = StaticLayout .Builder
194- .obtain (text , 0 , text .length (), getPaint (), lineWidth )
205+ .obtain (replaceSpace , 0 , replaceSpace .length (), getPaint (), lineWidth )
195206 .setLineSpacing (getLineSpacingExtra (), getLineSpacingMultiplier ())
196207 .build ();
197208 } else {
198- layout = new StaticLayout (text , getPaint (), lineWidth , Layout .Alignment .ALIGN_NORMAL ,
209+ layout = new StaticLayout (replaceSpace , getPaint (), lineWidth , Layout .Alignment .ALIGN_NORMAL ,
199210 getLineSpacingMultiplier (), getLineSpacingExtra (), true
200211 );
201212 }
202- int sumOfLw = 0 ;
213+ int sumLineWidth = 0 ;
214+ CharSequence lastLineLetter = null ;
215+ int lastLineLetterCount = 0 ;
203216 for (int i =0 ; i <maxLines ; i ++) {
204217 int count = (int ) layout .getLineWidth (i );
205- sumOfLw +=count ;
218+ int start = layout .getLineStart (i );
219+ int end = layout .getLineEnd (i );
220+ lastLineLetter = replaceSpace .subSequence (start , end );
221+ lastLineLetterCount = lastLineLetter .length ();
222+ sumLineWidth +=count ;
206223 }
207- float expandActionWidth = getPaint ().measureText (expandText );
224+ float expandActionWidth = getPaint ().measureText (" " + expandText );
208225 float doubleExpandWith = expandActionWidth * 2 ;
209- float truncatedTextWidth = sumOfLw - expandActionWidth ;
210- if (sumOfLw < doubleExpandWith ) {
211- truncatedTextWidth = sumOfLw ;
226+
227+ if (lastLineLetterCount < 3 ) {
228+ if (lastLineLetter != null ) {
229+ String lastChar = lastLineLetter .toString ().replaceAll ("\n " , "" );
230+ float lastLineLetterAdd = getPaint ().measureText (lastChar );
231+ sumLineWidth +=lastLineLetterAdd ;
232+ }
212233 }
213- CharSequence truncatedText = TextUtils .ellipsize (text , getPaint (), truncatedTextWidth , TextUtils .TruncateAt .END );
214- spanCollapsed = spanCollapsed (truncatedText +expandText );
234+
235+ float truncatedTextWidth = sumLineWidth - expandActionWidth ;
236+ if (sumLineWidth < doubleExpandWith ) {
237+ truncatedTextWidth = sumLineWidth ;
238+ }
239+ CharSequence truncatedText = TextUtils .ellipsize (replaceSpace , getPaint (), truncatedTextWidth , TextUtils .TruncateAt .END );
240+ String exp = expandText .replaceAll (" " , SPACE_CODE );
241+ String finalText = truncatedText .toString ();
242+ if (ellipsisType == ELLIPSIS_TYPE_NONE ) {
243+ finalText = truncatedText .toString ().replace (DOTS_CODE , "" );
244+ }
245+
246+ spanCollapsed = spanCollapsed (finalText +SPACE_CODE +exp );
215247 }
216248
217249 private SpannableStringBuilder spanCollapsed (String text ) {
@@ -260,7 +292,9 @@ public void updateDrawState(@NonNull TextPaint ds) {
260292 }
261293
262294 private void expandBuilder () {
263- String fullText = text +collapseText ;
295+ String replaceSpace = textReplaceSpace ();
296+ String collapsedTextSpace = collapseText .replaceAll (" " , SPACE_CODE );
297+ String fullText = replaceSpace +SPACE_CODE +collapsedTextSpace ;
264298 spanExpanded = spanExpanded (fullText );
265299 }
266300
@@ -317,7 +351,8 @@ public void toggle() {
317351 setMovementMethod (null );
318352
319353 if (collapsed ) {
320- String fullText = text +collapseText ;
354+ String collapsedTextSpace = collapseText .replaceAll (" " , SPACE_CODE );
355+ String fullText = textReplaceSpace ()+SPACE_CODE +collapsedTextSpace ;
321356 StaticLayout staticFull ;
322357 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
323358 staticFull = StaticLayout .Builder
@@ -335,7 +370,7 @@ fullText, getPaint(), lineWidth, Layout.Alignment.ALIGN_NORMAL,
335370 StaticLayout staticHalf ;
336371 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
337372 staticHalf = StaticLayout .Builder
338- .obtain (text , 0 , text .length (), getPaint (), lineWidth )
373+ .obtain (textReplaceSpace () , 0 , textReplaceSpace () .length (), getPaint (), lineWidth )
339374 .setMaxLines (maxLines )
340375 .setEllipsize (TextUtils .TruncateAt .END )
341376 .setLineSpacing (getLineSpacingExtra (), getLineSpacingMultiplier ())
@@ -353,7 +388,8 @@ fullText, getPaint(), lineWidth, Layout.Alignment.ALIGN_NORMAL,
353388 halfHeight = staticHalf .getHeight () + getCompoundPaddingTop () + getCompoundPaddingBottom ();
354389 }
355390
356- int start = collapsed ? halfHeight : fullHeight ;
391+ //int start = collapsed ? halfHeight : fullHeight;
392+ int start = getHeight ();
357393 int end = collapsed ? fullHeight : halfHeight ;
358394 ValueAnimator anim = ValueAnimator .ofInt (start , end );
359395 anim .setDuration (animationDuration );
@@ -367,8 +403,10 @@ fullText, getPaint(), lineWidth, Layout.Alignment.ALIGN_NORMAL,
367403 public void onAnimationStart (Animator animation ) {
368404 super .onAnimationStart (animation );
369405 isAnimate = true ;
370- if (collapsed )
371- setText (text , BufferType .SPANNABLE );
406+ if (collapsed ) {
407+ String replaceSpace = textReplaceSpace ();
408+ setText (replaceSpace , BufferType .SPANNABLE );
409+ }
372410 }
373411 @ Override
374412 public void onAnimationEnd (Animator animation ) {
@@ -431,4 +469,14 @@ public interface ToggleListener {
431469 public void onToggle (boolean collapsed );
432470 }
433471
472+ private String textReplaceSpace () {
473+ return text .replaceAll (" " , SPACE_CODE );
474+ }
475+
476+ private void setWrapLayout () {
477+ ViewGroup .LayoutParams params = getLayoutParams ();
478+ params .height = ViewGroup .LayoutParams .WRAP_CONTENT ;
479+ setLayoutParams (params );
480+ }
481+
434482}
0 commit comments