1919public class ExpandableTextView extends TextView
2020{
2121 private static final int DEFAULT_DURATION = 750 ;
22- private static final int LINES = 1 ;
22+ private static final int MAXMODE_LINES = 1 ;
2323
2424 private OnExpandListener onExpandListener ;
25- private final int duration ;
25+
26+ private long animationDuration ;
27+ private boolean animating ;
2628 private boolean expanded ;
2729 private int maxLines ;
2830 private int originalHeight ;
@@ -43,7 +45,7 @@ public ExpandableTextView(Context context, AttributeSet attrs, int defStyle)
4345
4446 // read attributes
4547 final TypedArray attributes = context .obtainStyledAttributes (attrs , R .styleable .ExpandableTextView , defStyle , 0 );
46- this .duration = attributes .getInt (R .styleable .ExpandableTextView_duration , DEFAULT_DURATION );
48+ this .animationDuration = attributes .getInt (R .styleable .ExpandableTextView_animation_duration , DEFAULT_DURATION );
4749 attributes .recycle ();
4850
4951 // keep the original value of maxLines
@@ -68,14 +70,18 @@ public int getMaxLines()
6870 final int mMaxModeValue = (int ) mMaxMode .get (this );
6971 final int mMaximumValue = (int ) mMaximum .get (this );
7072
71- return mMaxModeValue == LINES ? mMaximumValue : -1 ;
73+ return mMaxModeValue == MAXMODE_LINES ? mMaximumValue : -1 ;
7274 }
7375 catch (final Exception e )
7476 {
7577 return -1 ;
7678 }
7779 }
7880
81+ /**
82+ * Toggle the expanded state of this {@link ExpandableTextView}.
83+ * @return true if toggled, false otherwise.
84+ */
7985 public boolean toggle ()
8086 {
8187 if (this .expanded )
@@ -86,11 +92,15 @@ public boolean toggle()
8692 return this .expand ();
8793 }
8894
95+ /**
96+ * Expand this {@link ExpandableTextView}.
97+ * @return true if expanded, false otherwise.
98+ */
8999 public boolean expand ()
90100 {
91- if (!this .expanded && this .maxLines >= 0 )
101+ if (!this .expanded && ! this . animating && this .maxLines >= 0 )
92102 {
93- this .expanded = true ;
103+ this .animating = true ;
94104
95105 // notify listener
96106 if (this .onExpandListener != null )
@@ -130,10 +140,19 @@ public void onAnimationUpdate(final ValueAnimator animation)
130140 ExpandableTextView .this .setLayoutParams (layoutParams );
131141 }
132142 });
143+ valueAnimator .addListener (new AnimatorListener ()
144+ {
145+ @ Override
146+ public void onAnimationEnd (final Animator animation )
147+ {
148+ ExpandableTextView .this .expanded = true ;
149+ ExpandableTextView .this .animating = false ;
150+ }
151+ });
133152
134153 // start the animation
135154 valueAnimator
136- .setDuration (this .duration )
155+ .setDuration (this .animationDuration )
137156 .start ();
138157
139158 return true ;
@@ -142,11 +161,15 @@ public void onAnimationUpdate(final ValueAnimator animation)
142161 return false ;
143162 }
144163
164+ /**
165+ * Collapse this {@link TextView}.
166+ * @return true if collapsed, false otherwise.
167+ */
145168 public boolean collapse ()
146169 {
147- if (this .expanded && this .maxLines >= 0 )
170+ if (this .expanded && ! this . animating && this .maxLines >= 0 )
148171 {
149- this .expanded = false ;
172+ this .animating = true ;
150173
151174 // notify listener
152175 if (this .onExpandListener != null )
@@ -175,12 +198,15 @@ public void onAnimationEnd(final Animator animation)
175198 {
176199 // set maxLines to original value
177200 ExpandableTextView .this .setMaxLines (ExpandableTextView .this .maxLines );
201+
202+ ExpandableTextView .this .expanded = false ;
203+ ExpandableTextView .this .animating = false ;
178204 }
179205 });
180206
181207 // start the animation
182208 valueAnimator
183- .setDuration (this .duration )
209+ .setDuration (this .animationDuration )
184210 .start ();
185211
186212 return true ;
@@ -189,16 +215,37 @@ public void onAnimationEnd(final Animator animation)
189215 return false ;
190216 }
191217
218+ /**
219+ * Sets the duration of the expand / collapse animation.
220+ * @param animationDuration duration in milliseconds.
221+ */
222+ public void setAnimationDuration (final long animationDuration )
223+ {
224+ this .animationDuration = animationDuration ;
225+ }
226+
227+ /**
228+ * Sets a listener which receives updates about this {@link ExpandableTextView}.
229+ * @param onExpandListener the listener.
230+ */
192231 public void setOnExpandListener (final OnExpandListener onExpandListener )
193232 {
194233 this .onExpandListener = onExpandListener ;
195234 }
196235
236+ /**
237+ * Returns the {@link OnExpandListener}.
238+ * @return the listener.
239+ */
197240 public OnExpandListener getOnExpandListener ()
198241 {
199242 return onExpandListener ;
200243 }
201244
245+ /**
246+ * Is this {@link ExpandableTextView} expanded or not?
247+ * @return true if expanded, false if collapsed.
248+ */
202249 public boolean isExpanded ()
203250 {
204251 return this .expanded ;
0 commit comments