2020import com .beardedhen .androidbootstrap .api .attributes .BootstrapBrand ;
2121import com .beardedhen .androidbootstrap .api .defaults .DefaultBootstrapBrand ;
2222import com .beardedhen .androidbootstrap .utils .DimenUtils ;
23+ import com .beardedhen .androidbootstrap .utils .ViewUtils ;
2324
2425import java .util .concurrent .atomic .AtomicInteger ;
2526
26- public class BootstrapAlert extends RelativeLayout {
27+ /**
28+ * See <a href="http://getbootstrap.com/components/#badges>http://getbootstrap.com/components/#alerts</a>
29+ */
30+ @ BetaApi
31+ public class BootstrapAlert extends RelativeLayout implements Animation .AnimationListener {
32+
33+ /**
34+ * Provides methods which receive callbacks in response to changes in the view visibility.
35+ */
36+ public interface VisibilityChangeListener {
37+
38+ /**
39+ * Called when the alert is set to be dismissed with an animation.
40+ * @param alert the alert
41+ */
42+ void onAlertDismissStarted (BootstrapAlert alert );
43+
44+ /**
45+ * Called when the alert is no longer visible.
46+ * @param alert the alert
47+ */
48+ void onAlertDismissCompletion (BootstrapAlert alert );
49+
50+ /**
51+ * Called when the alert set to appear with an animation
52+ * @param alert the alert
53+ */
54+ void onAlertAppearStarted (BootstrapAlert alert );
55+
56+ /**
57+ * Called when the alert is now visible.
58+ * @param alert the alert
59+ */
60+ void onAlertAppearCompletion (BootstrapAlert alert );
61+ }
2762
2863 private ImageView closeButton ;
29- private TextView alertText ;
3064
3165 private BootstrapBrand bootstrapBrand ;
3266
@@ -39,10 +73,9 @@ public class BootstrapAlert extends RelativeLayout {
3973 private AlphaAnimation fadeInAnimation ;
4074 private AlphaAnimation fadeOutAnimation ;
4175
42- private boolean dismissible ;
43- private boolean hidden ;
76+ private boolean userDismissible ;
4477
45- private OnDismissListener onDismissListener ;
78+ private VisibilityChangeListener visibilityChangeListener ;
4679
4780 private static final AtomicInteger nextGeneratedId = new AtomicInteger (1 );
4881
@@ -71,148 +104,221 @@ private void initialise(AttributeSet attrs) {
71104
72105 strongText = a .getString (R .styleable .BootstrapAlert_strongText );
73106 messageText = a .getString (R .styleable .BootstrapAlert_messageText );
74- dismissible = a .getBoolean (R .styleable .BootstrapAlert_dismissible , false );
107+ userDismissible = a .getBoolean (R .styleable .BootstrapAlert_dismissible , false );
108+
75109 if (strongText == null ) {
76110 strongText = "" ;
77111 }
78112 if (messageText == null ) {
79113 messageText = "" ;
80114 }
81- } finally {
115+ }
116+ finally {
82117 a .recycle ();
83118 }
84119
85- baselineFontSize = DimenUtils .pixelsFromSpResource (getContext (), R .dimen .bootstrap_button_default_font_size );
86- baselinePadding = DimenUtils .pixelsFromDpResource (getContext (), R .dimen .bootstrap_alert_paddings );
87-
120+ baselineFontSize = DimenUtils .pixelsFromSpResource (getContext (),
121+ R .dimen .bootstrap_button_default_font_size );
122+ baselinePadding = DimenUtils .pixelsFromDpResource (getContext (),
123+ R .dimen .bootstrap_alert_paddings );
124+ setupAnimations ();
88125 updateBootstrapState ();
89126 }
90127
91128 private void updateBootstrapState () {
92- alertText = new TextView (getContext ());
129+ TextView alertText = new TextView (getContext ());
93130 closeButton = new ImageView (getContext ());
131+
94132 if (Build .VERSION .SDK_INT < Build .VERSION_CODES .JELLY_BEAN_MR1 ) {
95133 alertText .setId (generateViewUniqueId ());
96134 closeButton .setId (generateViewUniqueId ());
97- } else {
135+ }
136+ else {
98137 alertText .setId (View .generateViewId ());
99138 closeButton .setId (View .generateViewId ());
100139 }
101- fadeInAnimation = new AlphaAnimation (0.0f , 1.0f );
102- fadeInAnimation .setDuration (300 );
103- fadeInAnimation .setInterpolator (new AccelerateInterpolator ());
104- fadeOutAnimation = new AlphaAnimation (1.0f , 0.0f );
105- fadeOutAnimation .setDuration (300 );
106- fadeOutAnimation .setInterpolator (new AccelerateInterpolator ());
107140
108- fadeInAnimation .setAnimationListener (new Animation .AnimationListener () {
109- @ Override public void onAnimationStart (Animation animation ) {setVisibility (VISIBLE );}
110- @ Override public void onAnimationEnd (Animation animation ) {}
111- @ Override public void onAnimationRepeat (Animation animation ) {}
112- });
113-
114- fadeOutAnimation .setAnimationListener (new Animation .AnimationListener () {
115- @ Override public void onAnimationStart (Animation animation ) {}
116- @ Override public void onAnimationEnd (Animation animation ) {
117- setVisibility (GONE );
118- if (onDismissListener != null ) onDismissListener .onDismiss ();
119- }
120- @ Override public void onAnimationRepeat (Animation animation ) {}
121- });
122141
123- LayoutParams textParams = new LayoutParams (LayoutParams .MATCH_PARENT , LayoutParams .WRAP_CONTENT );
124- LayoutParams closeParams = new LayoutParams (LayoutParams .WRAP_CONTENT , LayoutParams .WRAP_CONTENT );
142+ LayoutParams textParams = new LayoutParams (LayoutParams .MATCH_PARENT ,
143+ LayoutParams .WRAP_CONTENT );
144+ LayoutParams closeParams = new LayoutParams (LayoutParams .WRAP_CONTENT ,
145+ LayoutParams .WRAP_CONTENT );
125146 textParams .addRule (RelativeLayout .LEFT_OF , closeButton .getId ());
126147 closeParams .addRule (RelativeLayout .ALIGN_PARENT_RIGHT , RelativeLayout .TRUE );
127148
128149 alertText .setLayoutParams (textParams );
129150 alertText .setTextSize (baselineFontSize );
130- alertText .setGravity (Gravity .LEFT );
131- alertText .setTextColor (BootstrapDrawableFactory .bootstrapButtonText (
132- getContext (),
133- true ,
134- bootstrapBrand ));
135- alertText .setText (Html .fromHtml (String .format ("<b>%s</b>%s" , strongText , (strongText .length () > 0 ? " " + messageText : messageText ))));
151+ alertText .setGravity (Gravity .START );
152+ alertText .setTextColor (
153+ BootstrapDrawableFactory .bootstrapButtonText (getContext (), true , bootstrapBrand ));
154+ alertText .setText (Html .fromHtml (String .format ("<b>%s</b>%s" , strongText ,
155+ (strongText .length () > 0 ?
156+ " " + messageText :
157+ messageText ))));
136158
137159 closeButton .setLayoutParams (closeParams );
138- closeButton .setBackgroundDrawable (BootstrapDrawableFactory .bootstrapAlertCloseIcon (
139- getContext (),
140- (int ) baselineFontSize ,
141- (int ) baselineFontSize ,
142- DimenUtils .dpToPixels (6 )));
143-
144- Drawable bg = BootstrapDrawableFactory .bootstrapAlert (
145- getContext (),
146- bootstrapBrand );
147-
148- if (Build .VERSION .SDK_INT >= 16 ) {
149- setBackground (bg );
150- } else {
151- setBackgroundDrawable (bg );
152- }
160+ Drawable buttonBg = BootstrapDrawableFactory .bootstrapAlertCloseIcon (
161+ getContext (), (int ) baselineFontSize , (int ) baselineFontSize ,
162+ DimenUtils .dpToPixels (6 ));
163+
164+ ViewUtils .setBackgroundDrawable (closeButton , buttonBg );
165+
166+ Drawable bg = BootstrapDrawableFactory .bootstrapAlert (getContext (), bootstrapBrand );
167+ ViewUtils .setBackgroundDrawable (this , bg );
168+
153169 addView (alertText );
154- if (dismissible ) {
170+
171+ if (userDismissible ) {
155172 addView (closeButton );
156173 ((View ) closeButton .getParent ()).post (new Runnable () {
157174 @ Override
158175 public void run () {
159176 Rect bounds = new Rect ();
160177 closeButton .getHitRect (bounds );
161- bounds .top -= DimenUtils .dpToPixels (6 );
178+ bounds .top -= DimenUtils .dpToPixels (6 );
162179 bounds .bottom += DimenUtils .dpToPixels (6 );
163- bounds .left -= DimenUtils .dpToPixels (6 );
164- bounds .right += DimenUtils .dpToPixels (6 );
180+ bounds .left -= DimenUtils .dpToPixels (6 );
181+ bounds .right += DimenUtils .dpToPixels (6 );
165182 TouchDelegate touchDelegate = new TouchDelegate (bounds , closeButton );
166183 if (View .class .isInstance (closeButton .getParent ())) {
167184 ((View ) closeButton .getParent ()).setTouchDelegate (touchDelegate );
168185 }
169186 }
170187 });
171- closeButton .setOnClickListener (
172- new OnClickListener () {
173- @ Override public void onClick (View v ) {
174- hide ();
175- }
176- }
177- );
188+ closeButton .setOnClickListener (new OnClickListener () {
189+ @ Override
190+ public void onClick (View v ) {
191+ dismiss (true );
192+ }
193+ });
178194 }
179195
180196 int vert = (int ) (baselinePadding * 1.5 );
181197 int hori = (int ) (baselinePadding * 1.5 );
182198 setPadding (hori , vert , hori , vert );
183199 }
184200
185- public void hide () {
186- hidden = true ;
187- startAnimation (fadeOutAnimation );
201+ private void setupAnimations () {
202+ fadeInAnimation = new AlphaAnimation (0.0f , 1.0f );
203+ fadeInAnimation .setDuration (300 );
204+ fadeInAnimation .setInterpolator (new AccelerateInterpolator ());
205+ fadeInAnimation .setAnimationListener (this );
206+
207+ fadeOutAnimation = new AlphaAnimation (1.0f , 0.0f );
208+ fadeOutAnimation .setDuration (300 );
209+ fadeOutAnimation .setInterpolator (new AccelerateInterpolator ());
210+ fadeOutAnimation .setAnimationListener (this );
211+ }
212+
213+ /**
214+ * Hides the alert with an animation, setting its visibility to {@link View#GONE}
215+ * @param animated whether the dismissal should be animated or not
216+ */
217+ public void dismiss (boolean animated ) {
218+ if (animated ) {
219+ if (visibilityChangeListener != null ) {
220+ visibilityChangeListener .onAlertDismissStarted (this );
221+ }
222+ startAnimation (fadeOutAnimation );
223+ }
224+ else {
225+ setVisibility (GONE );
226+ }
188227 }
189228
190- public void show () {
191- hidden = false ;
192- startAnimation (fadeInAnimation );
229+ /**
230+ * Shows the alert with an animation, setting its visibility to {@link View#VISIBLE}
231+ * @param animated whether the appearance should be animated or not
232+ */
233+ public void show (boolean animated ) {
234+ if (animated ) {
235+ if (visibilityChangeListener != null ) {
236+ visibilityChangeListener .onAlertAppearStarted (this );
237+ }
238+ startAnimation (fadeInAnimation );
239+ }
240+ else {
241+ setVisibility (VISIBLE );
242+ }
193243 }
194244
195- public boolean isHidden () {
196- return hidden ;
245+ /**
246+ * Retrieves whether the user can dismiss the dialog or not
247+ * @return true if dismissable
248+ */
249+ public boolean isUserDismissible () {
250+ return userDismissible ;
197251 }
198252
199- public void setOnDismissListener (OnDismissListener onDismissListener ) {
200- this .onDismissListener = onDismissListener ;
253+ /**
254+ * Sets whether the user can dismiss the dialog or not.
255+ * @param userDismissible true if dismissable
256+ */
257+ public void setUserDismissible (boolean userDismissible ) {
258+ this .userDismissible = userDismissible ;
259+ updateBootstrapState ();
260+ }
261+
262+ /**
263+ * Sets a {@link VisibilityChangeListener} that will be notified on changes
264+ *
265+ * @param visibilityChangeListener the listener
266+ */
267+ public void setVisibilityChangeListener (VisibilityChangeListener visibilityChangeListener ) {
268+ this .visibilityChangeListener = visibilityChangeListener ;
201269 }
202270
203271 private int generateViewUniqueId () {
204- for (;; ) {
272+ for (; ; ) {
205273 final int result = nextGeneratedId .get ();
206274 // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
207275 int newValue = result + 1 ;
208- if (newValue > 0x00FFFFFF ) newValue = 1 ; // Roll over to 1, not 0.
276+ if (newValue > 0x00FFFFFF ) {
277+ newValue = 1 ; // Roll over to 1, not 0.
278+ }
209279 if (nextGeneratedId .compareAndSet (result , newValue )) {
210280 return result ;
211281 }
212282 }
213283 }
214284
215- public interface OnDismissListener {
216- void onDismiss ();
285+ @ Override
286+ public void setVisibility (int visibility ) {
287+ super .setVisibility (visibility );
288+
289+ if (visibilityChangeListener != null ) {
290+ if (GONE == visibility ) {
291+ visibilityChangeListener .onAlertDismissCompletion (this );
292+ }
293+ else if (VISIBLE == visibility ) {
294+ visibilityChangeListener .onAlertAppearCompletion (this );
295+ }
296+ }
297+ }
298+
299+ // Animation change listener
300+
301+ @ Override
302+ public void onAnimationStart (Animation animation ) {
303+
304+ }
305+
306+ @ Override
307+ public void onAnimationEnd (Animation animation ) {
308+
309+ if (animation == fadeInAnimation ) {
310+ setVisibility (VISIBLE );
311+ }
312+ else if (animation == fadeOutAnimation ) {
313+ setVisibility (GONE );
314+ }
315+ else {
316+ throw new IllegalStateException ("Unsupported animation attempted to use this listener" );
317+ }
318+ }
319+
320+ @ Override
321+ public void onAnimationRepeat (Animation animation ) {
322+
217323 }
218324}
0 commit comments