iOS弹窗顺序弹出管理

希望弹窗顺序弹出,但是又关心弹出的优先级。下面是自己简单的实现,不足之处,请指出。
.h

/**
 ⚠️⚠️⚠️:PRPopupManager
 此管理类不关心弹窗的show和hide
 只约束弹窗是否被拦截一个一个展示、或者某几个同时展示
 */
#import <Foundation/Foundation.h>

///优先级枚举
typedef NS_ENUM(NSUInteger, PRPopupPriority) {
    PRPopupPriorityLow = 1,     /// 低
    PRPopupPriorityMedium,      /// 中
    PRPopupPriorityHigh         /// 高
};

/// 回调
typedef void (^PRPopupBlock)(void);

// MARK: - PRPopupConfig 弹出内容配置信息
@interface PRPopupConfig : NSObject

/// 是否被拦截:默认YES
@property (nonatomic, assign) BOOL isIntercept;
/// 当前弹窗是否在展示
@property (nonatomic, assign) BOOL isShowing;
/// 弹窗优先级:默认为High
@property (nonatomic, assign) PRPopupPriority priority;
/// 弹窗标识:以类名为标识,便于排查
@property (nonatomic, copy, nonnull) NSString *popupClassName;
/// 展示回调
@property (nonatomic, copy, nonnull) PRPopupBlock showBlock;
/// 隐藏回调
@property (nonatomic, copy, nullable) PRPopupBlock dismissBlock;

@end




// MARK: - PRPopupManager 弹出内容管理类
@interface PRPopupManager : NSObject

/// 单例对象
+ (instancetype _Nonnull)shared;

/// 展示弹窗
/// @param popupClass 弹出内容class
/// @param showBlock 展示回调
/// @param dismissBlock 隐藏回调
- (void)popupWithClass:(_Nonnull Class)popupClass show:(_Nonnull PRPopupBlock)showBlock dismiss:(_Nullable PRPopupBlock)dismissBlock;

/// 展示弹窗
/// @param popupClass 弹出内容class
/// @param priority 优先级
/// @param showBlock 展示回调
/// @param dismissBlock 隐藏回调
- (void)popupWithClass:(_Nonnull Class)popupClass priority:(PRPopupPriority)priority show:(_Nonnull PRPopupBlock)showBlock dismiss:(_Nullable PRPopupBlock)dismissBlock;

/// 展示弹窗
/// @param popupClass 弹出内容class
/// @param priority 优先级
/// @param isIntercept 是否需要被拦截
/// @param showBlock 展示回调
/// @param dismissBlock 隐藏回调
- (void)popupWithClass:(_Nonnull Class)popupClass priority:(PRPopupPriority)priority isIntercept:(BOOL)isIntercept show:(_Nonnull PRPopupBlock)showBlock dismiss:(_Nullable PRPopupBlock)dismissBlock;

/// 隐藏弹窗
- (void)dismissPopup;

@end

.m


#import "PRPopupManager.h"

// MARK: - PRAlertViewConfig
@implementation PRPopupConfig

- (instancetype)init {
    self = [super init];
    if (self) {
        self.isIntercept = YES;
        self.popupClassName = @"defaultName";
        self.priority = PRPopupPriorityHigh;
    }
    return self;
}

@end




// MARK: - PRPopupManager
@interface PRPopupManager()

/// 弹出池:key:弹窗className、value:config对象
@property (nonatomic, strong) NSMutableDictionary *popupPool;
/// 当前弹窗内容
@property (nonatomic, strong) PRPopupConfig *currnetPopup;

@end

@implementation PRPopupManager

static PRPopupManager *_instance = nil;

+ (instancetype)shared {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[PRPopupManager alloc] init];
    });
    return _instance;
}

// MARK: - Public Methods
- (void)popupWithClass:(Class)popupClass show:(PRPopupBlock)showBlock dismiss:(PRPopupBlock)dismissBlock{
    [self popupWithClass:popupClass priority:PRPopupPriorityHigh isIntercept:YES show:showBlock dismiss:dismissBlock];
}

- (void)popupWithClass:(Class)popupClass priority:(PRPopupPriority)priority show:(PRPopupBlock)showBlock dismiss:(PRPopupBlock)dismissBlock {
    [self popupWithClass:popupClass priority:priority isIntercept:YES show:showBlock dismiss:dismissBlock];
}

- (void)popupWithClass:(Class)popupClass priority:(PRPopupPriority)priority isIntercept: (BOOL)isIntercept show:(PRPopupBlock)showBlock dismiss:(PRPopupBlock)dismissBlock {
    PRPopupConfig *config = [[PRPopupConfig alloc] init];
    config.popupClassName = NSStringFromClass(popupClass);
    config.priority = priority;
    config.isIntercept = isIntercept;
    [self popupWithConfig:config show:showBlock dismiss:dismissBlock];
    
}

// MARK: - Private Methods
- (void)popupWithConfig:(PRPopupConfig *)config show:(PRPopupBlock)showBlock dismiss:(PRPopupBlock)dismissBlock {
    config.showBlock = showBlock;
    config.dismissBlock = dismissBlock;
    config.isShowing = YES;
    
    // 加入弹出池,同一个弹窗避免重复添加
    [self.popupPool setObject:config forKey:config.popupClassName];
    
    // 当前有弹窗在显示:self.popupPool.allKeys.count > 1
    // 当前弹窗被拦截:isIntercept == YES
    if (config.isIntercept && self.popupPool.allKeys.count > 1) {
        config.isShowing = NO;
        return;
    }
    
    self.currnetPopup = config;
    showBlock ? showBlock() : nil;
}


/// 清除弹出内容
- (void)dismissPopup {
    // 获取到当前弹出内容并删除
    [self deletePopupWithConfig:self.currnetPopup];
    
    // 是否有弹窗在显示 是:拦截其他未显示弹窗;否:查看是否有下一个可显示弹窗并显示
    if ([self isShowingSomeAlert]) {
        return;
    } else {
        // 优先级排序
        NSArray * values = [self.popupPool allValues];
        values = [self sortByPriority:values];
        
        // 当前没有正在展示的弹窗,则展示被拦截的弹窗
        if (values.count > 0) {
            // 查询是否有可以展示的弹窗:条件:1.已加入缓存、2.被拦截 3、实现了展示回调
            // 优先级 1 > 2 > 3
            // 找到一个立即展示,并退出循环
            for (PRPopupConfig *config in values) {
                PRPopupBlock showBlock = config.showBlock;
                if (config.isIntercept && showBlock) {
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        config.isShowing = YES;
                        self.currnetPopup = config;
                        showBlock();
                    });
                    break;
                }
            }
        }
    }
}

/// 是否正在展示某个弹窗
- (BOOL)isShowingSomeAlert{
    __block BOOL isShowSomeAlert = NO;
    [self.popupPool enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        PRPopupConfig *config = obj;
        if (config.isShowing) {
            isShowSomeAlert = YES;
            *stop = YES;
        }
    }];
    return isShowSomeAlert;
}

/// 根据优先级排序
/// @param configArray 弹窗配置数组
- (NSArray *)sortByPriority:(NSArray *)configArray {
    NSComparator comparator = ^(PRPopupConfig *obj1, PRPopupConfig *obj2) {
        if (obj1.priority > obj2.priority) {
            return NSOrderedAscending;
        }
        if (obj1.priority < obj2.priority) {
            return NSOrderedDescending;
        }
        return NSOrderedSame;
    };
    return [configArray sortedArrayUsingComparator:comparator];
}

/// 根据配置删除指定弹出内容
/// @param config 弹出配置
- (void)deletePopupWithConfig:(PRPopupConfig *)config {
    if (config == nil) return;
    PRPopupBlock dismissBlock = config.dismissBlock;
    dismissBlock ? dismissBlock() : nil;
    if ([self.popupPool.allKeys containsObject:config.popupClassName]) {
        [self.popupPool removeObjectForKey:config.popupClassName];
    }
    self.currnetPopup = nil;
}
 
// MARK: - Getters
- (NSMutableDictionary *)popupPool {
    if (!_popupPool) {
        _popupPool = [[NSMutableDictionary alloc] init];
    }
    return _popupPool;
}

@end

调用:包裹一层,但是需要在弹窗消失的时候调用dismissPopup方法,将弹窗从数据源中移除。

[[PRPopupManager shared] popupWithClass:[PRPopPayerViewController class] priority:PRPopupPriorityLow show:^{
                   // 弹窗的展示
                } dismiss:nil];
  // 弹窗消失
 [[PRPopupManager shared] dismissPopup];
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值