明日安在,無人能允。
前言
彈窗在交互上是個好東西,但是如果一個view有很多彈窗且產(chǎn)品要求按照一定的順序彈出,emmm...很好,就很棒!
先上需求
目前有三個彈窗A、B、C(以后會不會加誰知道呢),現(xiàn)在彈窗要按照A -> B -> C這個順序來,每次只能彈一個,三個都是網(wǎng)絡請求,不知道哪個結(jié)果先回來。分析一下,有如下場景:
-
理想型
數(shù)據(jù)順序返回,順序展示。期間通過彈窗跳轉(zhuǎn)其他頁面,返回后繼續(xù)順序展示。 -
進階型
B數(shù)據(jù)先回,B顯示ing時,A、C數(shù)據(jù)返回,緩存數(shù)據(jù)。不管誰數(shù)據(jù)先回來,B消失后都從A開始展示。期間通過彈窗跳轉(zhuǎn)其他頁面,返回后繼續(xù)順序展示。 -
高端型
A先回來,B是定時任務。通過A跳轉(zhuǎn)到其他頁面后B數(shù)據(jù)回來,正常情況下, 返回后會彈B。特別的,在其他頁面某項操作后,B不用彈了,返回后B不彈。
刺激?。?!
正題
簡單分析一下:
- 1、標識一個彈窗要有三元素:彈窗類型、彈窗狀態(tài)(參考線程生命周期)、彈窗展示用的數(shù)據(jù)。
所以創(chuàng)建以下任務類:
.h
typedef NS_ENUM(NSInteger, MQRoomAlertTaskType) {
MQRoomAlertTaskType_Runnable = 0, //就緒
MQRoomAlertTaskType_Running, //執(zhí)行中
MQRoomAlertTaskType_end, //完成
};
typedef NS_ENUM(NSInteger, MQRoomAlertType) {
MQRoomAlertType_HongBao = 0, //紅包
MQRoomAlertType_GrowGift, //成長禮包
MQRoomAlertType_Addention, //關(guān)注
};
@interface MQRoomAlertOrderTask : NSObject
/** 彈窗種類 */
@property (nonatomic, assign) MQRoomAlertType alertType;
@property (nonatomic, strong) id taskData;
/** 任務狀態(tài) */
@property (nonatomic, assign) MQRoomAlertTaskType taskType;
@end
- 2、 順序展示,簡單點用數(shù)組。有跨頁面操作,用單例。創(chuàng)建以下管理類:
.h
@interface MQRoomAlertOrderManager : NSObject
+ (instancetype)shareInstance;
//當前可執(zhí)行任務
@property (nonatomic, strong, readonly, nullable) MQRoomAlertOrderTask *curTask;
/** 是否正在執(zhí)行 */
@property (nonatomic, assign, readonly) BOOL isExecuting;
/** 緩存 */
- (void)setTasKWithData:(id)data taskType:(MQRoomAlertType)alertType;
/** 執(zhí)行 */
- (void)execute;
/** 是否正在執(zhí)行 */
- (BOOL)executing;
/** 完成 */
- (void)complete;
/** 清空 */
- (void)clear;
/** 根據(jù)任務類型獲取任務 */
- (MQRoomAlertOrderTask *)getTaskWithAlertType:(MQRoomAlertType)alertType;
/** 銷毀單例 */
- (void)destroy;
@end
- 3、使用的時候采用遞歸方式
核心代碼
- (void)orderAlert {
MQRoomAlertOrderManager *manager = [MQRoomAlertOrderManager shareInstance];
if (manager.isExecuting) {//正在執(zhí)行任務,既有彈窗在顯示
return;
}
if (manager.curTask) {
switch (manager.curTask.alertType) {
case MQRoomAlertType_HongBao: {
NSLog(@">>>>>>MQRoomAlertType_HongBao");
//標記執(zhí)行
[manager execute];
dispatch_async(self.queue, ^{
//模擬彈窗時間
sleep(arc4random() % 5 + 1);
//取當前任務數(shù)據(jù)
// id data = [MQRoomAlertOrderManager shareInstance].curTask.taskData;
[self nextAlert];
});
break;
}case MQRoomAlertType_GrowGift: {
NSLog(@">>>>>>MQRoomAlertType_GrowGift");
//標記執(zhí)行
[manager execute];
dispatch_async(self.queue, ^{
//模擬彈窗時間
sleep(arc4random() % 5 + 1);
//取當前任務數(shù)據(jù)
// id data = [MQRoomAlertOrderManager shareInstance].curTask.taskData;
[self nextAlert];
});
break;
}case MQRoomAlertType_Addention: {
NSLog(@">>>>>>MQRoomAlertType_Addention");
//標記執(zhí)行
[manager execute];
dispatch_async(self.queue, ^{
//模擬彈窗時間
sleep(arc4random() % 5 + 1);
//取當前任務數(shù)據(jù)
// id data = [MQRoomAlertOrderManager shareInstance].curTask.taskData;
[self nextAlert];
});
break;
}
default:
break;
}
}else {
self.hadTask = NO;
NSLog(@">>>all task completed");
}
}
- (void)nextAlert {
//當前任務完成
[[MQRoomAlertOrderManager shareInstance] complete];
//遞歸執(zhí)行下一任務
[self orderAlert];
}
該管理類只是用來緩存彈窗數(shù)據(jù)、標記彈窗狀態(tài),不要把業(yè)務邏輯代碼寫到這里面來。
注意
若是那種跳轉(zhuǎn)到其它頁面后,改變某個任務的狀態(tài),這時候只需要獲取對應task,然后把taskType設置為MQRoomAlertTaskType_end就可以了。
//根據(jù)類型獲取某一任務
MQRoomAlertOrderTask *task = [[MQRoomAlertOrderManager shareInstance] getTaskWithAlertType:MQRoomAlertType_GrowGift];
//改變?nèi)蝿諣顟B(tài)
task.taskType = MQRoomAlertTaskType_end;
Demo地址 傳送門
后記
邏輯比較復雜的,還是思維導圖好用,單在那想容易掉頭發(fā)。