Commit fb23d058 by jianhua zhang

Fixed iOS queue display

Toast can be displayed in order on iOS
parent 44dc3fe7
......@@ -2,7 +2,7 @@
// UIView+Toast.h
// Toast
//
// Copyright (c) 2011-2017 Charles Scalesse.
// Copyright (c) 2011-2015 Charles Scalesse.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
......@@ -89,26 +89,6 @@ extern const NSString * CSToastPositionBottom;
@param duration The toast duration
@param position The toast's center point. Can be one of the predefined CSToastPosition
constants or a `CGPoint` wrapped in an `NSValue` object.
@param style The style. The shared style will be used when nil
@param completion The completion block, executed after the toast view disappears.
didTap will be `YES` if the toast view was dismissed from a tap.
*/
- (void)makeToast:(NSString *)message
duration:(NSTimeInterval)duration
position:(id)position
style:(CSToastStyle *)style
completion:(void(^)(BOOL didTap))completion;
/**
Creates and presents a new toast view with a message, title, and image. Duration,
position, and style can be set explicitly. The completion block executes when the
toast view completes. `didTap` will be `YES` if the toast view was dismissed from
a tap.
@param message The message to be displayed
@param duration The toast duration
@param position The toast's center point. Can be one of the predefined CSToastPosition
constants or a `CGPoint` wrapped in an `NSValue` object.
@param title The title
@param image The image
@param style The style. The shared style will be used when nil
......@@ -143,46 +123,6 @@ extern const NSString * CSToastPositionBottom;
style:(CSToastStyle *)style;
/**
Hides the active toast. If there are multiple toasts active in a view, this method
hides the oldest toast (the first of the toasts to have been presented).
@see `hideAllToasts` to remove all active toasts from a view.
@warning This method has no effect on activity toasts. Use `hideToastActivity` to
hide activity toasts.
*/
- (void)hideToast;
/**
Hides an active toast.
@param toast The active toast view to dismiss. Any toast that is currently being displayed
on the screen is considered active.
@warning this does not clear a toast view that is currently waiting in the queue.
*/
- (void)hideToast:(UIView *)toast;
/**
Hides all active toast views and clears the queue.
*/
- (void)hideAllToasts;
/**
Hides all active toast views, with options to hide activity and clear the queue.
@param includeActivity If `true`, toast activity will also be hidden. Default is `false`.
@param clearQueue If `true`, removes all toast views from the queue. Default is `true`.
*/
- (void)hideAllToasts:(BOOL)includeActivity clearQueue:(BOOL)clearQueue;
/**
Removes all toast views from the queue. This has no effect on toast views that are
active. Use `hideAllToasts` to hide the active toasts views and clear the queue.
*/
- (void)clearToastQueue;
/**
Creates and displays a new toast activity indicator view at a specified position.
@warning Only one toast activity indicator view can be presented per superview. Subsequent
......@@ -226,6 +166,8 @@ extern const NSString * CSToastPositionBottom;
position:(id)position
completion:(void(^)(BOOL didTap))completion;
- (void)hideAllToasts;
@end
/**
......@@ -383,7 +325,7 @@ extern const NSString * CSToastPositionBottom;
with with a nil style. By default, this is set to `CSToastStyle`'s default
style.
@param sharedStyle the shared style
@param sharedStyle
*/
+ (void)setSharedStyle:(CSToastStyle *)sharedStyle;
......@@ -398,7 +340,7 @@ extern const NSString * CSToastPositionBottom;
/**
Enables or disables tap to dismiss on toast views. Default is `YES`.
@param tapToDismissEnabled YES or NO
@param allowTapToDismiss
*/
+ (void)setTapToDismissEnabled:(BOOL)tapToDismissEnabled;
......@@ -406,7 +348,7 @@ extern const NSString * CSToastPositionBottom;
Returns `YES` if tap to dismiss is enabled, otherwise `NO`.
Default is `YES`.
@return BOOL YES or NO
@return BOOL
*/
+ (BOOL)isTapToDismissEnabled;
......@@ -415,15 +357,15 @@ extern const NSString * CSToastPositionBottom;
toast views will appear one after the other. When `NO`, multiple Toast
views will appear at the same time (potentially overlapping depending
on their positions). This has no effect on the toast activity view,
which operates independently of normal toast views. Default is `NO`.
which operates independently of normal toast views. Default is `YES`.
@param queueEnabled YES or NO
@param queueEnabled
*/
+ (void)setQueueEnabled:(BOOL)queueEnabled;
/**
Returns `YES` if the queue is enabled, otherwise `NO`.
Default is `NO`.
Default is `YES`.
@return BOOL
*/
......@@ -463,4 +405,5 @@ extern const NSString * CSToastPositionBottom;
*/
+ (id)defaultPosition;
@end
......@@ -2,7 +2,7 @@
// UIView+Toast.m
// Toast
//
// Copyright (c) 2011-2017 Charles Scalesse.
// Copyright (c) 2011-2015 Charles Scalesse.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
......@@ -27,7 +27,6 @@
#import <QuartzCore/QuartzCore.h>
#import <objc/runtime.h>
// Positions
NSString * CSToastPositionTop = @"CSToastPositionTop";
NSString * CSToastPositionCenter = @"CSToastPositionCenter";
NSString * CSToastPositionBottom = @"CSToastPositionBottom";
......@@ -40,6 +39,7 @@ static const NSString * CSToastCompletionKey = @"CSToastCompletionKey";
// Keys for values associated with self
static const NSString * CSToastActiveKey = @"CSToastActiveKey";
static const NSString * CSToastActiveToastViewKey = @"CSToastActiveToastViewKey";
static const NSString * CSToastActivityViewKey = @"CSToastActivityViewKey";
static const NSString * CSToastQueueKey = @"CSToastQueueKey";
......@@ -80,11 +80,6 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
[self showToast:toast duration:duration position:position completion:nil];
}
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position style:(CSToastStyle *)style completion:(void(^)(BOOL didTap))completion {
UIView *toast = [self toastViewForMessage:message title:nil image:nil style:style];
[self showToast:toast duration:duration position:position completion:completion];
}
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position title:(NSString *)title image:(UIImage *)image style:(CSToastStyle *)style completion:(void(^)(BOOL didTap))completion {
UIView *toast = [self toastViewForMessage:message title:title image:image style:style];
[self showToast:toast duration:duration position:position completion:completion];
......@@ -103,7 +98,7 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
// store the completion block on the toast view
objc_setAssociatedObject(toast, &CSToastCompletionKey, completion, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if ([CSToastManager isQueueEnabled] && [self.cs_activeToasts count] > 0) {
if ([CSToastManager isQueueEnabled] && objc_getAssociatedObject(self, &CSToastActiveToastViewKey) != nil) {
// we're about to queue this toast view so we need to store the duration and position as well
objc_setAssociatedObject(toast, &CSToastDurationKey, @(duration), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(toast, &CSToastPositionKey, position, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
......@@ -116,41 +111,6 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
}
}
#pragma mark - Hide Toast Methods
- (void)hideToast {
[self hideToast:[[self cs_activeToasts] firstObject]];
}
- (void)hideToast:(UIView *)toast {
// sanity
if (!toast || ![[self cs_activeToasts] containsObject:toast]) return;
[self cs_hideToast:toast];
}
- (void)hideAllToasts {
[self hideAllToasts:NO clearQueue:YES];
}
- (void)hideAllToasts:(BOOL)includeActivity clearQueue:(BOOL)clearQueue {
if (clearQueue) {
[self clearToastQueue];
}
for (UIView *toast in [self cs_activeToasts]) {
[self hideToast:toast];
}
if (includeActivity) {
[self hideToastActivity];
}
}
- (void)clearToastQueue {
[[self cs_toastQueue] removeAllObjects];
}
#pragma mark - Private Show/Hide Methods
- (void)cs_showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position {
......@@ -165,6 +125,8 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
}
[[self cs_activeToasts] addObject:toast];
// set the active toast
objc_setAssociatedObject(self, &CSToastActiveToastViewKey, toast, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self addSubview:toast];
......@@ -185,9 +147,6 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
}
- (void)cs_hideToast:(UIView *)toast fromTap:(BOOL)fromTap {
NSTimer *timer = (NSTimer *)objc_getAssociatedObject(toast, &CSToastTimerKey);
[timer invalidate];
[UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration]
delay:0.0
options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState)
......@@ -196,8 +155,8 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
} completion:^(BOOL finished) {
[toast removeFromSuperview];
// remove
[[self cs_activeToasts] removeObject:toast];
// clear the active toast
objc_setAssociatedObject(self, &CSToastActiveToastViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// execute the completion block, if necessary
void (^completion)(BOOL didTap) = objc_getAssociatedObject(toast, &CSToastCompletionKey);
......@@ -222,7 +181,7 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
- (UIView *)toastViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image style:(CSToastStyle *)style {
// sanity
if (message == nil && title == nil && image == nil) return nil;
if(message == nil && title == nil && image == nil) return nil;
// default to the shared style
if (style == nil) {
......@@ -343,16 +302,7 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
return wrapperView;
}
#pragma mark - Storage
- (NSMutableArray *)cs_activeToasts {
NSMutableArray *cs_activeToasts = objc_getAssociatedObject(self, &CSToastActiveKey);
if (cs_activeToasts == nil) {
cs_activeToasts = [[NSMutableArray alloc] init];
objc_setAssociatedObject(self, &CSToastActiveKey, cs_activeToasts, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return cs_activeToasts;
}
#pragma mark - Queue
- (NSMutableArray *)cs_toastQueue {
NSMutableArray *cs_toastQueue = objc_getAssociatedObject(self, &CSToastQueueKey);
......@@ -362,7 +312,14 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
}
return cs_toastQueue;
}
- (NSMutableArray *)cs_activeToasts {
NSMutableArray *cs_activeToasts = objc_getAssociatedObject(self, &CSToastActiveKey);
if (cs_activeToasts == nil) {
cs_activeToasts = [[NSMutableArray alloc] init];
objc_setAssociatedObject(self, &CSToastActiveKey, cs_activeToasts, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return cs_activeToasts;
}
#pragma mark - Events
- (void)cs_toastTimerDidFinish:(NSTimer *)timer {
......@@ -432,32 +389,48 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
}];
}
}
- (void)hideAllToasts{
[self hideAllToasts:NO clearQueue:YES];
}
- (void)hideAllToasts:(BOOL)includeActivity clearQueue:(BOOL)clearQueue {
if (clearQueue) {
[self clearToastQueue];
}
for (UIView *toast in [self cs_activeToasts]) {
[self hideToast:toast];
}
if (includeActivity) {
[self hideToastActivity];
}
}
- (void)clearToastQueue {
[[self cs_toastQueue] removeAllObjects];
}
- (void)hideToast:(UIView *)toast {
// sanity
if (!toast || ![[self cs_activeToasts] containsObject:toast]) return;
[self cs_hideToast:toast];
}
#pragma mark - Helpers
- (CGPoint)cs_centerPointForPosition:(id)point withToast:(UIView *)toast {
CSToastStyle *style = [CSToastManager sharedStyle];
UIEdgeInsets safeInsets = UIEdgeInsetsZero;
if (@available(iOS 11.0, *)) {
safeInsets = self.safeAreaInsets;
}
CGFloat topPadding = style.verticalPadding + safeInsets.top;
CGFloat bottomPadding = style.verticalPadding + safeInsets.bottom;
if([point isKindOfClass:[NSString class]]) {
if([point caseInsensitiveCompare:CSToastPositionTop] == NSOrderedSame) {
return CGPointMake(self.bounds.size.width / 2.0, (toast.frame.size.height / 2.0) + topPadding);
return CGPointMake(self.bounds.size.width/2, (toast.frame.size.height / 2) + style.verticalPadding);
} else if([point caseInsensitiveCompare:CSToastPositionCenter] == NSOrderedSame) {
return CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0);
return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
}
} else if ([point isKindOfClass:[NSValue class]]) {
return [point CGPointValue];
}
// default to bottom
return CGPointMake(self.bounds.size.width / 2.0, (self.bounds.size.height - (toast.frame.size.height / 2.0)) - bottomPadding);
return CGPointMake(self.bounds.size.width/2, (self.bounds.size.height - (toast.frame.size.height / 2)) - style.verticalPadding);
}
@end
......@@ -475,14 +448,14 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
self.maxWidthPercentage = 0.8;
self.maxHeightPercentage = 0.8;
self.horizontalPadding = 10.0;
self.verticalPadding = 8.0;
self.verticalPadding = 10.0;
self.cornerRadius = 10.0;
self.titleFont = [UIFont boldSystemFontOfSize:16.0];
self.messageFont = [UIFont systemFontOfSize:16.0];
self.titleAlignment = NSTextAlignmentLeft;
self.messageAlignment = NSTextAlignmentLeft;
self.titleNumberOfLines = 0;
self.messageNumberOfLines = 1;
self.messageNumberOfLines = 0;
self.displayShadow = NO;
self.shadowOpacity = 0.8;
self.shadowRadius = 6.0;
......@@ -537,9 +510,9 @@ static const NSString * CSToastQueueKey = @"CSToastQueueKey";
if (self) {
self.sharedStyle = [[CSToastStyle alloc] initWithDefaultStyle];
self.tapToDismissEnabled = YES;
self.queueEnabled = NO;
self.queueEnabled = YES;
self.defaultDuration = 3.0;
self.defaultPosition = CSToastPositionBottom;
self.defaultPosition = CSToastPositionCenter;
}
return self;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment