You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决MBProgressHUD/SVProgressHUD多个弹窗重叠显示的问题

多请求场景下HUD重叠问题最佳解决方案

核心思路

本质是给HUD增加全局引用计数,避免重复创建实例,同一时间仅保留1个加载态HUD实例,从根源解决重叠导致背景加深的问题。

方案1:适配SVProgressHUD(利用原生单例特性)

SVProgressHUD本身是全局单例,仅需要新增计数逻辑统一管控调用即可:

  • 维护全局的NSInteger hudShowCount计数变量,每次调用加载展示接口时计数+1,仅当计数从0变为1时才真正调用SVProgressHUD原生展示方法
  • 每次请求结束(无论成功失败)调用隐藏接口时计数-1,仅当计数减到0时才真正调用SVProgressHUD原生隐藏方法
  • 错误提示类HUD设置为低优先级:仅当前无加载态HUD展示时才弹出,若有加载态则延迟等待加载消失后再展示

示例代码:

// 全局维护计数变量
static NSInteger kHUDShowCount = 0;

/// 统一加载HUD展示接口
+ (void)showLoading {
    kHUDShowCount++;
    if (kHUDShowCount == 1) {
        // 可在这里统一配置HUD样式
        [SVProgressHUD show];
    }
}

/// 统一加载HUD隐藏接口
+ (void)dismissLoading {
    if (kHUDShowCount <= 0) {
        return;
    }
    kHUDShowCount--;
    if (kHUDShowCount == 0) {
        [SVProgressHUD dismiss];
    }
}

/// 统一错误提示接口
+ (void)showError:(NSString *)msg {
    // 等待所有加载HUD消失后再展示错误
    if (kHUDShowCount > 0) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self showError:msg];
        });
        return;
    }
    [SVProgressHUD showErrorWithStatus:msg];
    [SVProgressHUD dismissWithDelay:2];
}

后续所有业务代码统一调用上述封装接口,禁止直接调用SVProgressHUD原生方法即可解决重叠问题。

方案2:适配MBProgressHUD(封装全局管理单例)

MBProgressHUD默认支持多实例创建,需要额外封装全局管理类管控唯一实例:

  • 封装HUDManager全局单例,内部持有唯一的MBProgressHUD实例,统一添加到当前应用顶层window上
  • 内部维护计数逻辑,规则和上述SVProgressHUD的计数逻辑完全一致
  • 所有HUD的展示、隐藏操作都走HUDManager的统一接口,禁止业务侧直接创建MBProgressHUD实例

示例核心代码:

@interface HUDManager : NSObject
+ (instancetype)shared;
- (void)showLoading;
- (void)dismissLoading;
- (void)showError:(NSString *)msg;
@end

@implementation HUDManager {
    NSInteger _showCount;
    MBProgressHUD *_hud;
}

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

- (instancetype)init {
    self = [super init];
    if (self) {
        _showCount = 0;
        // 统一将HUD添加到顶层window
        _hud = [[MBProgressHUD alloc] initWithView:[UIApplication sharedApplication].keyWindow];
        [[UIApplication sharedApplication].keyWindow addSubview:_hud];
        // 统一配置HUD样式
        _hud.removeFromSuperViewOnHide = NO;
    }
    return self;
}

- (void)showLoading {
    dispatch_async(dispatch_get_main_queue(), ^{
        self->_showCount++;
        if (self->_showCount == 1) {
            self->_hud.mode = MBProgressHUDModeIndeterminate;
            self->_hud.label.text = @"loading";
            [self->_hud showAnimated:YES];
        }
    });
}

- (void)dismissLoading {
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self->_showCount <= 0) return;
        self->_showCount--;
        if (self->_showCount == 0) {
            [self->_hud hideAnimated:YES];
        }
    });
}

- (void)showError:(NSString *)msg {
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self->_showCount > 0) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self showError:msg];
            });
            return;
        }
        self->_hud.mode = MBProgressHUDModeText;
        self->_hud.label.text = msg;
        [self->_hud showAnimated:YES];
        [self->_hud hideAnimated:YES afterDelay:2];
    });
}
@end

注意事项

  • 所有HUD操作必须放在主线程执行,避免多线程操作导致计数不准
  • 页面销毁时要检查当前页面关联请求对应的HUD计数是否正确扣减,避免出现HUD永久不消失的问题
  • 如有更高优先级的全局提示(如登录过期弹窗),可直接重置计数为0,隐藏当前HUD后再展示高优先级内容

内容的提问来源于stack exchange,提问作者jiexishede

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 15:18:00