@@ -37,6 +37,11 @@ public class TextViewReadMore extends AppCompatTextView {
37
37
38
38
private static final String DEFAULT_EXPAND_TEXT = "Read More" ;
39
39
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 ;
40
45
41
46
private String text ;
42
47
@@ -68,6 +73,7 @@ public class TextViewReadMore extends AppCompatTextView {
68
73
private View .OnClickListener onClickExpand ;
69
74
private View .OnClickListener onClickCollapse ;
70
75
private int actionClickColor = 0 ;
76
+ private int ellipsisType = ELLIPSIS_TYPE_DOTS ;
71
77
72
78
private static long mLastClickTime = 0 ;
73
79
@@ -110,11 +116,15 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
110
116
collapseTextStyle = typedArray .getInt (R .styleable .TextViewReadMore_collapseTextStyle , 0 );
111
117
collapseTextUnderline = typedArray .getBoolean (R .styleable .TextViewReadMore_collapseTextUnderline , collapseTextUnderline );
112
118
119
+
113
120
int defaultActionClickColor = ContextCompat .getColor (context , R .color .text_view_read_more_button_hover_color );
114
121
actionClickColor = typedArray .getColor (R .styleable .TextViewReadMore_actionClickColor , defaultActionClickColor );
115
122
116
123
int getAnimationDuration = typedArray .getInt (R .styleable .TextViewReadMore_android_animationDuration , animationDuration );
117
124
animationDuration = Math .max (getAnimationDuration , 100 );
125
+
126
+ ellipsisType = typedArray .getInt (R .styleable .TextViewReadMore_ellipsisType , ELLIPSIS_TYPE_DOTS );
127
+
118
128
} finally {
119
129
typedArray .recycle ();
120
130
}
@@ -161,13 +171,13 @@ private void buildSpan() {
161
171
} else {
162
172
expandBuilder ();
163
173
setText (spanExpanded );
164
- ViewGroup .LayoutParams params = getLayoutParams ();
165
- params .height = ViewGroup .LayoutParams .WRAP_CONTENT ;
166
- setLayoutParams (params );
174
+ setWrapLayout ();
167
175
}
168
176
setMovementMethod (LinkMovementMethod .getInstance ());
169
177
rebuild = false ;
170
178
}
179
+ } else {
180
+ setWrapLayout ();
171
181
}
172
182
}
173
183
}
@@ -189,29 +199,51 @@ private boolean isEllipsized(String text) {
189
199
190
200
private void collapsedBuilder () {
191
201
StaticLayout layout ;
202
+ String replaceSpace = textReplaceSpace ();
192
203
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
193
204
layout = StaticLayout .Builder
194
- .obtain (text , 0 , text .length (), getPaint (), lineWidth )
205
+ .obtain (replaceSpace , 0 , replaceSpace .length (), getPaint (), lineWidth )
195
206
.setLineSpacing (getLineSpacingExtra (), getLineSpacingMultiplier ())
196
207
.build ();
197
208
} else {
198
- layout = new StaticLayout (text , getPaint (), lineWidth , Layout .Alignment .ALIGN_NORMAL ,
209
+ layout = new StaticLayout (replaceSpace , getPaint (), lineWidth , Layout .Alignment .ALIGN_NORMAL ,
199
210
getLineSpacingMultiplier (), getLineSpacingExtra (), true
200
211
);
201
212
}
202
- int sumOfLw = 0 ;
213
+ int sumLineWidth = 0 ;
214
+ CharSequence lastLineLetter = null ;
215
+ int lastLineLetterCount = 0 ;
203
216
for (int i =0 ; i <maxLines ; i ++) {
204
217
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 ;
206
223
}
207
- float expandActionWidth = getPaint ().measureText (expandText );
224
+ float expandActionWidth = getPaint ().measureText (" " + expandText );
208
225
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
+ }
212
233
}
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 );
215
247
}
216
248
217
249
private SpannableStringBuilder spanCollapsed (String text ) {
@@ -260,7 +292,9 @@ public void updateDrawState(@NonNull TextPaint ds) {
260
292
}
261
293
262
294
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 ;
264
298
spanExpanded = spanExpanded (fullText );
265
299
}
266
300
@@ -317,7 +351,8 @@ public void toggle() {
317
351
setMovementMethod (null );
318
352
319
353
if (collapsed ) {
320
- String fullText = text +collapseText ;
354
+ String collapsedTextSpace = collapseText .replaceAll (" " , SPACE_CODE );
355
+ String fullText = textReplaceSpace ()+SPACE_CODE +collapsedTextSpace ;
321
356
StaticLayout staticFull ;
322
357
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
323
358
staticFull = StaticLayout .Builder
@@ -335,7 +370,7 @@ fullText, getPaint(), lineWidth, Layout.Alignment.ALIGN_NORMAL,
335
370
StaticLayout staticHalf ;
336
371
if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
337
372
staticHalf = StaticLayout .Builder
338
- .obtain (text , 0 , text .length (), getPaint (), lineWidth )
373
+ .obtain (textReplaceSpace () , 0 , textReplaceSpace () .length (), getPaint (), lineWidth )
339
374
.setMaxLines (maxLines )
340
375
.setEllipsize (TextUtils .TruncateAt .END )
341
376
.setLineSpacing (getLineSpacingExtra (), getLineSpacingMultiplier ())
@@ -353,7 +388,8 @@ fullText, getPaint(), lineWidth, Layout.Alignment.ALIGN_NORMAL,
353
388
halfHeight = staticHalf .getHeight () + getCompoundPaddingTop () + getCompoundPaddingBottom ();
354
389
}
355
390
356
- int start = collapsed ? halfHeight : fullHeight ;
391
+ //int start = collapsed ? halfHeight : fullHeight;
392
+ int start = getHeight ();
357
393
int end = collapsed ? fullHeight : halfHeight ;
358
394
ValueAnimator anim = ValueAnimator .ofInt (start , end );
359
395
anim .setDuration (animationDuration );
@@ -367,8 +403,10 @@ fullText, getPaint(), lineWidth, Layout.Alignment.ALIGN_NORMAL,
367
403
public void onAnimationStart (Animator animation ) {
368
404
super .onAnimationStart (animation );
369
405
isAnimate = true ;
370
- if (collapsed )
371
- setText (text , BufferType .SPANNABLE );
406
+ if (collapsed ) {
407
+ String replaceSpace = textReplaceSpace ();
408
+ setText (replaceSpace , BufferType .SPANNABLE );
409
+ }
372
410
}
373
411
@ Override
374
412
public void onAnimationEnd (Animator animation ) {
@@ -431,4 +469,14 @@ public interface ToggleListener {
431
469
public void onToggle (boolean collapsed );
432
470
}
433
471
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
+
434
482
}
0 commit comments