MBProgressHUD的备忘录模式:保存指示器的历史状态
在移动应用开发中,用户经常需要在执行耗时操作时看到清晰的进度反馈。然而,当应用需要显示多个连续任务的进度时,频繁创建和销毁指示器不仅繁琐,还可能导致界面闪烁和状态丢失。本文将介绍如何使用备忘录模式(Memento Pattern)为MBProgressHUD实现状态保存功能,让你轻松管理多个进度指示器的显示与切换。
为什么需要状态保存?
想象以下场景:用户在文件上传过程中需要同时下载数据,两个操作都需要显示进度指示器。如果直接切换指示器的属性(如模式、进度值、文本),不仅代码逻辑混乱,还可能丢失前一个任务的状态信息。备忘录模式通过捕获对象内部状态并在外部存储,完美解决了这一问题。
MBProgressHUD作为iOS开发中最常用的指示器库,其核心类MBProgressHUD.h提供了丰富的可配置属性,但原生并不支持状态保存功能。我们将通过扩展该类实现备忘录模式,主要涉及以下步骤:
实现备忘录模式
1. 定义备忘录类
首先创建一个存储HUD状态的类MBProgressHUDMemento,用于保存关键属性:
@interface MBProgressHUDMemento : NSObject
@property (nonatomic, assign) MBProgressHUDMode mode;
@property (nonatomic, assign) float progress;
@property (nonatomic, copy) NSString *labelText;
@property (nonatomic, copy) NSString *detailsLabelText;
@property (nonatomic, strong) UIView *customView;
@end
@implementation MBProgressHUDMemento
// 实现自动生成的getter/setter
@end
2. 扩展MBProgressHUD
在MBProgressHUD.h中添加备忘录相关方法声明:
@interface MBProgressHUD (Memento)
- (MBProgressHUDMemento *)saveState;
- (void)restoreState:(MBProgressHUDMemento *)memento;
@end
在MBProgressHUD.m中实现这些方法:
@implementation MBProgressHUD (Memento)
- (MBProgressHUDMemento *)saveState {
MBProgressHUDMemento *memento = [[MBProgressHUDMemento alloc] init];
memento.mode = self.mode;
memento.progress = self.progress;
memento.labelText = self.label.text;
memento.detailsLabelText = self.detailsLabel.text;
memento.customView = self.customView;
return memento;
}
- (void)restoreState:(MBProgressHUDMemento *)memento {
self.mode = memento.mode;
self.progress = memento.progress;
self.label.text = memento.labelText;
self.detailsLabel.text = memento.detailsLabelText;
self.customView = memento.customView;
[self updateIndicators]; // 关键:更新UI显示
}
@end
注意:
updateIndicators方法来自MBProgressHUD.m,用于根据当前属性重新布局UI组件。
3. 管理多个状态
创建状态管理类MBProgressHUDStateManager,使用栈结构存储多个备忘录:
@interface MBProgressHUDStateManager : NSObject
- (void)pushStateForHUD:(MBProgressHUD *)hud;
- (void)popStateForHUD:(MBProgressHUD *)hud;
@end
@implementation MBProgressHUDStateManager {
NSMutableDictionary<MBProgressHUD *, NSMutableArray<MBProgressHUDMemento *> *> *_stateStacks;
}
- (instancetype)init {
self = [super init];
if (self) {
_stateStacks = [NSMutableDictionary dictionary];
}
return self;
}
- (void)pushStateForHUD:(MBProgressHUD *)hud {
if (!_stateStacks[hud]) {
_stateStacks[hud] = [NSMutableArray array];
}
[_stateStacks[hud] addObject:[hud saveState]];
}
- (void)popStateForHUD:(MBProgressHUD *)hud {
NSMutableArray *stack = _stateStacks[hud];
if (stack.count == 0) return;
MBProgressHUDMemento *memento = [stack lastObject];
[stack removeLastObject];
[hud restoreState:memento];
if (stack.count == 0) {
[_stateStacks removeObjectForKey:hud];
}
}
@end
实际应用场景
文件上传下载示例
以下代码演示如何在文件上传和下载任务间切换HUD状态:
// 创建HUD
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeDeterminate;
hud.label.text = @"上传中";
// 创建状态管理器
MBProgressHUDStateManager *manager = [[MBProgressHUDStateManager alloc] init];
// 保存上传状态
[manager pushStateForHUD:hud];
// 切换到下载状态
hud.mode = MBProgressHUDModeAnnularDeterminate;
hud.label.text = @"下载中";
hud.progress = 0.3;
// 恢复上传状态
[manager popStateForHUD:hud];
// 此时HUD将恢复为上传模式,进度值和文本也会回到之前的状态
自定义视图切换
利用备忘录模式保存包含自定义视图的状态:
// 创建带对勾图标的完成状态
UIImageView *checkmarkView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Checkmark"]];
hud.mode = MBProgressHUDModeCustomView;
hud.customView = checkmarkView;
hud.label.text = @"完成";
// 保存完成状态
[manager pushStateForHUD:hud];
// 切换到加载状态
hud.mode = MBProgressHUDModeIndeterminate;
hud.label.text = @"加载中";
// 恢复完成状态
[manager popStateForHUD:hud];
项目中提供了示例图标Checkmark.png,可直接用于自定义视图。
高级扩展
1. 持久化存储
通过归档将备忘录保存到本地,实现应用重启后恢复HUD状态:
// 归档
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:memento requiringSecureCoding:NO error:nil];
[data writeToFile:path atomically:YES];
// 解档
NSData *data = [NSData dataWithContentsOfFile:path];
MBProgressHUDMemento *memento = [NSKeyedUnarchiver unarchiveObjectOfClass:[MBProgressHUDMemento class] fromData:data error:nil];
2. 动画过渡效果
在restoreState:方法中添加过渡动画:
- (void)restoreState:(MBProgressHUDMemento *)memento animated:(BOOL)animated {
if (animated) {
[UIView animateWithDuration:0.3 animations:^{
self.bezelView.alpha = 0;
} completion:^(BOOL finished) {
[self restoreState:memento];
[UIView animateWithDuration:0.3 animations:^{
self.bezelView.alpha = 1;
}];
}];
} else {
[self restoreState:memento];
}
}
动画实现参考了MBProgressHUD.m中的animateIn:withType:completion:方法。
3. 与NSProgress集成
利用MBProgressHUD的progressObject属性(定义在MBProgressHUD.h),可以将备忘录与系统进度对象结合:
// 在备忘录中添加NSProgress引用
@property (nonatomic, strong) NSProgress *progressObject;
// 保存/恢复进度对象
memento.progressObject = self.progressObject;
self.progressObject = memento.progressObject;
总结
通过备忘录模式,我们为MBProgressHUD添加了状态保存与恢复功能,主要解决了以下问题:
- 状态丢失:避免直接修改HUD属性导致的状态混乱
- 代码复杂度:将状态管理逻辑与UI逻辑分离
- 用户体验:实现任务切换时的平滑过渡
完整代码可参考项目Demo目录中的示例HudDemoViewController.m,该文件包含了多种HUD样式的使用示例,可作为扩展功能的基础。
使用此模式时需注意:
- 避免保存过大的自定义视图,以免影响性能
- 状态栈深度不宜过大,建议不超过5层
- 确保在主线程调用状态恢复方法,避免UI异常
通过这种设计,我们不仅增强了MBProgressHUD的功能,还保持了原库的简洁API设计风格,让复杂的状态管理变得简单直观。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



