FreeRDP
Loading...
Searching...
No Matches
Toast+UIView.m
1/***************************************************************************
2
3 Toast+UIView.h
4 Toast
5 Version 0.1
6
7 Copyright (c) 2011 Charles Scalesse.
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28 ***************************************************************************/
29
30#import "Toast+UIView.h"
31#import <QuartzCore/QuartzCore.h>
32
33#define kMaxWidth 0.8
34#define kMaxHeight 0.8
35
36#define kHorizontalPadding 10.0
37#define kVerticalPadding 10.0
38#define kCornerRadius 10.0
39#define kOpacity 0.8
40#define kFontSize 16.0
41#define kMaxTitleLines 999
42#define kMaxMessageLines 999
43
44#define kFadeDuration 0.2
45
46#define kDefaultLength 3
47#define kDefaultPosition @"bottom"
48
49#define kImageWidth 80.0
50#define kImageHeight 80.0
51
52@interface UIView (ToastPrivate)
53
54- (CGPoint)getPositionFor:(id)position toast:(UIView *)toast;
55- (UIView *)makeViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image;
56
57@end
58
59@implementation UIView (Toast)
60
61#pragma mark -
62#pragma mark Toast Methods
63
64- (void)makeToast:(NSString *)message
65{
66 [self makeToast:message duration:kDefaultLength position:kDefaultPosition];
67}
68
69- (void)makeToast:(NSString *)message duration:(float)interval position:(id)point
70{
71 UIView *toast = [self makeViewForMessage:message title:nil image:nil];
72 [self showToast:toast duration:interval position:point];
73}
74
75- (void)makeToast:(NSString *)message
76 duration:(float)interval
77 position:(id)point
78 title:(NSString *)title
79{
80 UIView *toast = [self makeViewForMessage:message title:title image:nil];
81 [self showToast:toast duration:interval position:point];
82}
83
84- (void)makeToast:(NSString *)message
85 duration:(float)interval
86 position:(id)point
87 image:(UIImage *)image
88{
89 UIView *toast = [self makeViewForMessage:message title:nil image:image];
90 [self showToast:toast duration:interval position:point];
91}
92
93- (void)makeToast:(NSString *)message
94 duration:(float)interval
95 position:(id)point
96 title:(NSString *)title
97 image:(UIImage *)image
98{
99 UIView *toast = [self makeViewForMessage:message title:title image:image];
100 [self showToast:toast duration:interval position:point];
101}
102
103- (void)showToast:(UIView *)toast
104{
105 [self showToast:toast duration:kDefaultLength position:kDefaultPosition];
106}
107
108- (void)showToast:(UIView *)toast duration:(float)interval position:(id)point
109{
110
111 /****************************************************
112 * *
113 * Displays a view for a given duration & position. *
114 * *
115 ****************************************************/
116
117 CGPoint toastPoint = [self getPositionFor:point toast:toast];
118
119 [toast setCenter:toastPoint];
120 [toast setAlpha:0.0];
121 [self addSubview:toast];
122
123 [UIView animateWithDuration:kFadeDuration
124 delay:0.0
125 options:UIViewAnimationOptionCurveEaseOut
126 animations:^{
127 [toast setAlpha:1.0];
128 }
129 completion:^(BOOL finished) {
130 [UIView animateWithDuration:kFadeDuration
131 delay:interval
132 options:UIViewAnimationOptionCurveEaseIn
133 animations:^{
134 [toast setAlpha:0.0];
135 }
136 completion:^(BOOL finished) {
137 [toast removeFromSuperview];
138 }];
139 }];
140}
141
142#pragma mark -
143#pragma mark Private Methods
144
145- (CGPoint)getPositionFor:(id)point toast:(UIView *)toast
146{
147
148 /*************************************************************************************
149 * *
150 * Converts string literals @"top", @"bottom", @"center", or any point wrapped in an *
151 * NSValue object into a CGPoint *
152 * *
153 *************************************************************************************/
154
155 if ([point isKindOfClass:[NSString class]])
156 {
157
158 if ([point caseInsensitiveCompare:@"top"] == NSOrderedSame)
159 {
160 return CGPointMake(self.bounds.size.width / 2,
161 (toast.frame.size.height / 2) + kVerticalPadding);
162 }
163 else if ([point caseInsensitiveCompare:@"bottom"] == NSOrderedSame)
164 {
165 return CGPointMake(self.bounds.size.width / 2,
166 (self.bounds.size.height - (toast.frame.size.height / 2)) -
167 kVerticalPadding);
168 }
169 else if ([point caseInsensitiveCompare:@"center"] == NSOrderedSame)
170 {
171 return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
172 }
173 }
174 else if ([point isKindOfClass:[NSValue class]])
175 {
176 return [point CGPointValue];
177 }
178
179 NSLog(@"Error: Invalid position for toast.");
180 return [self getPositionFor:kDefaultPosition toast:toast];
181}
182
183- (UIView *)makeViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image
184{
185
186 /***********************************************************************************
187 * *
188 * Dynamically build a toast view with any combination of message, title, & image. *
189 * *
190 ***********************************************************************************/
191
192 if ((message == nil) && (title == nil) && (image == nil))
193 return nil;
194
195 UILabel *messageLabel = nil;
196 UILabel *titleLabel = nil;
197 UIImageView *imageView = nil;
198
199 // create the parent view
200 UIView *wrapperView = [[[UIView alloc] init] autorelease];
201 [wrapperView.layer setCornerRadius:kCornerRadius];
202 [wrapperView setBackgroundColor:[[UIColor blackColor] colorWithAlphaComponent:kOpacity]];
203 wrapperView.autoresizingMask =
204 UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin |
205 UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
206
207 if (image != nil)
208 {
209 imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
210 [imageView setContentMode:UIViewContentModeScaleAspectFit];
211 [imageView
212 setFrame:CGRectMake(kHorizontalPadding, kVerticalPadding, kImageWidth, kImageHeight)];
213 }
214
215 float imageWidth, imageHeight, imageLeft;
216
217 // the imageView frame values will be used to size & position the other views
218 if (imageView != nil)
219 {
220 imageWidth = imageView.bounds.size.width;
221 imageHeight = imageView.bounds.size.height;
222 imageLeft = kHorizontalPadding;
223 }
224 else
225 {
226 imageWidth = imageHeight = imageLeft = 0;
227 }
228
229 if (title != nil)
230 {
231 titleLabel = [[[UILabel alloc] init] autorelease];
232 [titleLabel setNumberOfLines:kMaxTitleLines];
233 [titleLabel setFont:[UIFont boldSystemFontOfSize:kFontSize]];
234 [titleLabel setTextAlignment:NSTextAlignmentLeft];
235 [titleLabel setLineBreakMode:NSLineBreakByWordWrapping];
236 [titleLabel setTextColor:[UIColor whiteColor]];
237 [titleLabel setBackgroundColor:[UIColor clearColor]];
238 [titleLabel setAlpha:1.0];
239 [titleLabel setText:title];
240
241 // size the title label according to the length of the text
242 CGSize maxSizeTitle = CGSizeMake((self.bounds.size.width * kMaxWidth) - imageWidth,
243 self.bounds.size.height * kMaxHeight);
244 NSMutableParagraphStyle *titleStyle = [[[NSMutableParagraphStyle alloc] init] autorelease];
245 titleStyle.lineBreakMode = titleLabel.lineBreakMode;
246 CGRect titleRect = [title boundingRectWithSize:maxSizeTitle
247 options:NSStringDrawingUsesLineFragmentOrigin
248 attributes:@{
249 NSFontAttributeName: titleLabel.font,
250 NSParagraphStyleAttributeName: titleStyle
251 }
252 context:nil];
253 CGSize expectedSizeTitle =
254 CGSizeMake(ceilf(titleRect.size.width), ceilf(titleRect.size.height));
255 [titleLabel setFrame:CGRectMake(0, 0, expectedSizeTitle.width, expectedSizeTitle.height)];
256 }
257
258 if (message != nil)
259 {
260 messageLabel = [[[UILabel alloc] init] autorelease];
261 [messageLabel setNumberOfLines:kMaxMessageLines];
262 [messageLabel setFont:[UIFont systemFontOfSize:kFontSize]];
263 [messageLabel setLineBreakMode:NSLineBreakByWordWrapping];
264 [messageLabel setTextColor:[UIColor whiteColor]];
265 [messageLabel setTextAlignment:NSTextAlignmentCenter];
266 [messageLabel setBackgroundColor:[UIColor clearColor]];
267 [messageLabel setAlpha:1.0];
268 [messageLabel setText:message];
269
270 // size the message label according to the length of the text
271 CGSize maxSizeMessage = CGSizeMake((self.bounds.size.width * kMaxWidth) - imageWidth,
272 self.bounds.size.height * kMaxHeight);
273 NSMutableParagraphStyle *messageStyle =
274 [[[NSMutableParagraphStyle alloc] init] autorelease];
275 messageStyle.lineBreakMode = messageLabel.lineBreakMode;
276 CGRect messageRect = [message boundingRectWithSize:maxSizeMessage
277 options:NSStringDrawingUsesLineFragmentOrigin
278 attributes:@{
279 NSFontAttributeName: messageLabel.font,
280 NSParagraphStyleAttributeName: messageStyle
281 }
282 context:nil];
283 CGSize expectedSizeMessage =
284 CGSizeMake(ceilf(messageRect.size.width), ceilf(messageRect.size.height));
285 [messageLabel
286 setFrame:CGRectMake(0, 0, expectedSizeMessage.width, expectedSizeMessage.height)];
287 }
288
289 // titleLabel frame values
290 float titleWidth, titleHeight, titleTop, titleLeft;
291
292 if (titleLabel != nil)
293 {
294 titleWidth = titleLabel.bounds.size.width;
295 titleHeight = titleLabel.bounds.size.height;
296 titleTop = kVerticalPadding;
297 titleLeft = imageLeft + imageWidth + kHorizontalPadding;
298 }
299 else
300 {
301 titleWidth = titleHeight = titleTop = titleLeft = 0;
302 }
303
304 // messageLabel frame values
305 float messageWidth, messageHeight, messageLeft, messageTop;
306
307 if (messageLabel != nil)
308 {
309 messageWidth = messageLabel.bounds.size.width;
310 messageHeight = messageLabel.bounds.size.height;
311 messageLeft = imageLeft + imageWidth + kHorizontalPadding;
312 messageTop = titleTop + titleHeight + kVerticalPadding;
313 }
314 else
315 {
316 messageWidth = messageHeight = messageLeft = messageTop = 0;
317 }
318
319 // compare the title & message widths and use the longer value to calculate the size of the
320 // wrapper width the same logic applies to the x value (left)
321 float longerWidth = (messageWidth < titleWidth) ? titleWidth : messageWidth;
322 float longerLeft = (messageLeft < titleLeft) ? titleLeft : messageLeft;
323
324 // if the image width is larger than longerWidth, use the image width to calculate the wrapper
325 // width. the same logic applies to the wrapper height
326 float wrapperWidth =
327 ((longerLeft + longerWidth + kHorizontalPadding) < imageWidth + (kHorizontalPadding * 2))
328 ? imageWidth + (kHorizontalPadding * 2)
329 : (longerLeft + longerWidth + kHorizontalPadding);
330 float wrapperHeight =
331 ((messageTop + messageHeight + kVerticalPadding) < imageHeight + (kVerticalPadding * 2))
332 ? imageHeight + (kVerticalPadding * 2)
333 : (messageTop + messageHeight + kVerticalPadding);
334
335 [wrapperView setFrame:CGRectMake(0, 0, wrapperWidth, wrapperHeight)];
336
337 if (titleLabel != nil)
338 {
339 [titleLabel setFrame:CGRectMake(titleLeft, titleTop, titleWidth, titleHeight)];
340 [wrapperView addSubview:titleLabel];
341 }
342
343 if (messageLabel != nil)
344 {
345 [messageLabel setFrame:CGRectMake(messageLeft, messageTop, messageWidth, messageHeight)];
346 [wrapperView addSubview:messageLabel];
347 }
348
349 if (imageView != nil)
350 {
351 [wrapperView addSubview:imageView];
352 }
353
354 return wrapperView;
355}
356
357@end