20
20
import com .beardedhen .androidbootstrap .api .attributes .BootstrapBrand ;
21
21
import com .beardedhen .androidbootstrap .api .defaults .DefaultBootstrapBrand ;
22
22
import com .beardedhen .androidbootstrap .utils .DimenUtils ;
23
+ import com .beardedhen .androidbootstrap .utils .ViewUtils ;
23
24
24
25
import java .util .concurrent .atomic .AtomicInteger ;
25
26
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
+ }
27
62
28
63
private ImageView closeButton ;
29
- private TextView alertText ;
30
64
31
65
private BootstrapBrand bootstrapBrand ;
32
66
@@ -39,10 +73,9 @@ public class BootstrapAlert extends RelativeLayout {
39
73
private AlphaAnimation fadeInAnimation ;
40
74
private AlphaAnimation fadeOutAnimation ;
41
75
42
- private boolean dismissible ;
43
- private boolean hidden ;
76
+ private boolean userDismissible ;
44
77
45
- private OnDismissListener onDismissListener ;
78
+ private VisibilityChangeListener visibilityChangeListener ;
46
79
47
80
private static final AtomicInteger nextGeneratedId = new AtomicInteger (1 );
48
81
@@ -71,148 +104,221 @@ private void initialise(AttributeSet attrs) {
71
104
72
105
strongText = a .getString (R .styleable .BootstrapAlert_strongText );
73
106
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
+
75
109
if (strongText == null ) {
76
110
strongText = "" ;
77
111
}
78
112
if (messageText == null ) {
79
113
messageText = "" ;
80
114
}
81
- } finally {
115
+ }
116
+ finally {
82
117
a .recycle ();
83
118
}
84
119
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 ();
88
125
updateBootstrapState ();
89
126
}
90
127
91
128
private void updateBootstrapState () {
92
- alertText = new TextView (getContext ());
129
+ TextView alertText = new TextView (getContext ());
93
130
closeButton = new ImageView (getContext ());
131
+
94
132
if (Build .VERSION .SDK_INT < Build .VERSION_CODES .JELLY_BEAN_MR1 ) {
95
133
alertText .setId (generateViewUniqueId ());
96
134
closeButton .setId (generateViewUniqueId ());
97
- } else {
135
+ }
136
+ else {
98
137
alertText .setId (View .generateViewId ());
99
138
closeButton .setId (View .generateViewId ());
100
139
}
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 ());
107
140
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
- });
122
141
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 );
125
146
textParams .addRule (RelativeLayout .LEFT_OF , closeButton .getId ());
126
147
closeParams .addRule (RelativeLayout .ALIGN_PARENT_RIGHT , RelativeLayout .TRUE );
127
148
128
149
alertText .setLayoutParams (textParams );
129
150
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 ))));
136
158
137
159
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
+
153
169
addView (alertText );
154
- if (dismissible ) {
170
+
171
+ if (userDismissible ) {
155
172
addView (closeButton );
156
173
((View ) closeButton .getParent ()).post (new Runnable () {
157
174
@ Override
158
175
public void run () {
159
176
Rect bounds = new Rect ();
160
177
closeButton .getHitRect (bounds );
161
- bounds .top -= DimenUtils .dpToPixels (6 );
178
+ bounds .top -= DimenUtils .dpToPixels (6 );
162
179
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 );
165
182
TouchDelegate touchDelegate = new TouchDelegate (bounds , closeButton );
166
183
if (View .class .isInstance (closeButton .getParent ())) {
167
184
((View ) closeButton .getParent ()).setTouchDelegate (touchDelegate );
168
185
}
169
186
}
170
187
});
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
+ });
178
194
}
179
195
180
196
int vert = (int ) (baselinePadding * 1.5 );
181
197
int hori = (int ) (baselinePadding * 1.5 );
182
198
setPadding (hori , vert , hori , vert );
183
199
}
184
200
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
+ }
188
227
}
189
228
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
+ }
193
243
}
194
244
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 ;
197
251
}
198
252
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 ;
201
269
}
202
270
203
271
private int generateViewUniqueId () {
204
- for (;; ) {
272
+ for (; ; ) {
205
273
final int result = nextGeneratedId .get ();
206
274
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
207
275
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
+ }
209
279
if (nextGeneratedId .compareAndSet (result , newValue )) {
210
280
return result ;
211
281
}
212
282
}
213
283
}
214
284
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
+
217
323
}
218
324
}
0 commit comments