Skip to content

Commit 9cde484

Browse files
committed
fix unstable max lines, action space, ellipsis option
1 parent 6669194 commit 9cde484

File tree

8 files changed

+90
-32
lines changed

8 files changed

+90
-32
lines changed

app/src/main/java/com/erif/readmoretextview/MainActivityRecyclerView.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ protected void onCreate(Bundle savedInstanceState) {
3333
getString(R.string.lorem_ngawur2),
3434
getString(R.string.lorem_ipsum1),
3535
getString(R.string.lorem_ipsum2),
36-
getString(R.string.lorem_ipsum3),
36+
getString(R.string.lorem_ngawur_kabeh),
3737
getString(R.string.lorem_ipsum1),
3838
getString(R.string.lorem_ipsum2),
39-
getString(R.string.lorem_ipsum3),
39+
getString(R.string.lorem_ngawur_kabeh2),
4040
getString(R.string.lorem_ipsum1),
4141
getString(R.string.lorem_ipsum2),
4242
getString(R.string.lorem_ipsum3),

app/src/main/java/com/erif/readmoretextview/helper/AdapterRecyclerView.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
3232
ModelItemRecyclerView item = list.get(position);
3333
mHolder.text.setText(item.getText());
3434
mHolder.text.collapsed(item.isCollapsed());
35-
/*mHolder.text.onClickExpand(v -> mHolder.text.toggle());
35+
mHolder.text.onClickExpand(v -> mHolder.text.toggle());
3636
mHolder.text.onClickCollapse(v -> mHolder.text.toggle());
3737

3838
mHolder.text.toggleListener(collapsed -> {
3939
item.setCollapsed(collapsed);
4040
update(position);
41-
});*/
42-
mHolder.text.onClickExpand(v -> {
41+
});
42+
/*mHolder.text.onClickExpand(v -> {
4343
boolean status = !item.isCollapsed();
4444
mHolder.text.collapsed(status);
4545
item.setCollapsed(status);
@@ -51,7 +51,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
5151
mHolder.text.collapsed(status);
5252
item.setCollapsed(status);
5353
update(position);
54-
});
54+
});*/
5555

5656
}
5757
}

app/src/main/res/layout/activity_main.xml

+4-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
android:id="@+id/txtReadMore"
1212
android:layout_width="wrap_content"
1313
android:layout_height="wrap_content"
14-
android:padding="12dp"
15-
app:readMoreMaxLines="2"
14+
android:background="#e3e3e3"
15+
android:padding="10dp"
16+
app:readMoreMaxLines="3"
1617
app:expandText="@string/read_more"
1718
app:expandTextStyle="bold|italic"
1819
app:expandTextColor="@color/teal_700"
@@ -23,7 +24,7 @@
2324
app:collapseTextColor="@color/teal_700"
2425
app:collapseTextUnderline="true"
2526
app:actionClickColor="@color/teal_200"
26-
android:text="@string/lorem_ngawur_wur" />
27+
android:text="@string/lorem_ngawur2"/>
2728

2829
<Button
2930
android:id="@+id/btnSet"

app/src/main/res/layout/item_recycler_view.xml

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
android:layout_width="wrap_content"
1919
android:layout_height="wrap_content"
2020
android:text="@string/lorem_ipsum1"
21-
android:textColor="@color/black" />
21+
android:textColor="@color/black"
22+
app:readMoreMaxLines="3"
23+
app:ellipsisType="none"/>
2224

2325
</RelativeLayout>
2426

app/src/main/res/values/strings.xml

+4-1
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,16 @@
7070
<string name="lorem_ngawur">Ngawur\nplacerat massa\nMaecenas sodales\n rutrum est sed\n efficitur Nunc at \nNunc at placerat massa Maecenas\n sodales
7171
placerat massa. asdfasf Maecenas \nsodales rutrum \nest sed efficitur.</string>
7272

73-
<string name="lorem_ngawur2">ngawur2\nas\nas</string>
73+
<string name="lorem_ngawur2">ejej\ndee\nd\nd\nf\nf\nd\nd</string>
7474

7575
<string name="lorem_ngawur_wur">2Lorem ipsum dolor sit amet, consectetur adipiscing elit.
7676
Maecenas sodales rutrum est sed efficitur. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
7777
Fusce eget ligula sed dolor accumsan tristique id vel turpis. Nam congue nunc hendrerit eros fermentum eleifend.
7878
Sed tristique facilisis imperdiet. Donec eget interdum dui. Sed tristique facilisis imperdiet. Donec</string>
7979

80+
<string name="lorem_ngawur_kabeh">1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111S11111111111111111111111111111111111111111111111111111111111111E</string>
81+
<string name="lorem_ngawur_kabeh2">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXBukaDong</string>
82+
8083
<string name="read_more">Buka Dong</string>
8184
<string name="read_less">Tutup Ah</string>
8285

build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22
plugins {
3-
id 'com.android.application' version '7.2.1' apply false
4-
id 'com.android.library' version '7.2.1' apply false
3+
id 'com.android.application' version '7.2.2' apply false
4+
id 'com.android.library' version '7.2.2' apply false
55
}
66

77
task clean(type: Delete) {

readMoreTextView/src/main/java/com/erif/readmoretextview/TextViewReadMore.java

+67-19
Original file line numberDiff line numberDiff line change
@@ -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
}

readMoreTextView/src/main/res/values/attrs.xml

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
</attr>
2424
<attr name="android:animationDuration"/>
2525
<attr name="actionClickColor" format="reference|color"/>
26+
<attr name="ellipsisType">
27+
<flag name="dots" value="0"/>
28+
<flag name="none" value="1"/>
29+
</attr>
2630
</declare-styleable>
2731

2832
</resources>

0 commit comments

Comments
 (0)