首页
/ BRPickerView自定义弹框控制方案解析

BRPickerView自定义弹框控制方案解析

2025-06-29 14:33:04作者:吴年前Myrtle

背景介绍

BRPickerView作为iOS平台上常用的选择器组件,在表单选择、日期选择等场景中被广泛使用。在实际开发中,我们经常会遇到这样的需求:在选择完成后需要先对数据进行校验或处理,只有通过验证后才允许关闭选择器界面。然而,BRPickerView默认行为是点击"完成"按钮后立即关闭界面,这给需要前置处理的场景带来了不便。

问题分析

开发者在使用BRPickerView时,通常会遇到以下典型场景:

  1. 用户选择数据后,需要先验证数据有效性
  2. 根据选择结果调用接口,等待接口返回成功后再关闭界面
  3. 在选择完成后需要执行一些耗时操作,完成后才允许关闭

这些场景下,选择器自动关闭的行为会导致用户体验不连贯或业务逻辑无法完整执行。

解决方案

BRPickerView提供了addPickerToView方法,允许开发者自定义弹框的背景视图,通过这种方式可以间接控制选择器的关闭行为。具体实现思路如下:

1. 自定义容器视图

通过addPickerToView方法,我们可以将选择器添加到自定义的容器视图中,而不是直接显示在窗口上。这样我们就获得了对选择器显示/隐藏的完全控制权。

// 创建自定义容器视图
UIView *customContainer = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
customContainer.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];

// 添加选择器到自定义视图
[pickerView addPickerToView:customContainer];

// 显示自定义容器
[self.view addSubview:customContainer];

2. 拦截完成事件

在选择器的完成回调中,我们可以先执行必要的业务逻辑,然后手动控制选择器的关闭:

pickerView.resultBlock = ^(id selectValue) {
    // 1. 处理选择的数据
    if (![self validateData:selectValue]) {
        // 验证失败,保持选择器打开
        return;
    }
    
    // 2. 调用接口等异步操作
    [self submitData:selectValue completion:^(BOOL success) {
        if (success) {
            // 3. 操作成功后再关闭选择器
            [customContainer removeFromSuperview];
        }
    }];
};

3. 完整实现示例

下面是一个完整的实现示例,展示了如何控制选择器的关闭时机:

- (void)showCustomPicker {
    // 1. 创建选择器
    BRStringPickerView *pickerView = [[BRStringPickerView alloc] initWithPickerMode:BRStringPickerComponentSingle];
    pickerView.dataSourceArr = @[@"选项1", @"选项2", @"选项3"];
    
    // 2. 创建自定义容器
    UIView *containerView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    containerView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
    containerView.alpha = 0;
    
    // 3. 添加选择器到容器
    [pickerView addPickerToView:containerView];
    
    // 4. 设置完成回调
    __weak typeof(self) weakSelf = self;
    pickerView.resultBlock = ^(id selectValue) {
        [weakSelf handlePickerResult:selectValue container:containerView];
    };
    
    // 5. 显示容器(带动画)
    [self.view addSubview:containerView];
    [UIView animateWithDuration:0.3 animations:^{
        containerView.alpha = 1;
    }];
}

- (void)handlePickerResult:(id)result container:(UIView *)container {
    // 数据验证
    if (!result) {
        [self showAlert:@"请选择有效选项"];
        return;
    }
    
    // 模拟异步操作
    [self showLoading];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self hideLoading];
        // 操作完成后关闭选择器
        [UIView animateWithDuration:0.3 animations:^{
            container.alpha = 0;
        } completion:^(BOOL finished) {
            [container removeFromSuperview];
        }];
    });
}

进阶技巧

1. 添加取消按钮

在自定义容器中,我们可以添加额外的控制元素,比如取消按钮:

UIButton *cancelBtn = [UIButton buttonWithType:UIButtonTypeSystem];
[cancelBtn setTitle:@"取消" forState:UIControlStateNormal];
[cancelBtn addTarget:self action:@selector(dismissPicker:) forControlEvents:UIControlEventTouchUpInside];
[containerView addSubview:cancelBtn];

2. 自定义动画效果

通过修改容器视图的alpha或transform属性,可以实现各种入场/出场动画:

// 入场动画
containerView.transform = CGAffineTransformMakeScale(0.9, 0.9);
[UIView animateWithDuration:0.3 animations:^{
    containerView.transform = CGAffineTransformIdentity;
    containerView.alpha = 1;
}];

// 出场动画
[UIView animateWithDuration:0.3 animations:^{
    containerView.transform = CGAffineTransformMakeScale(0.9, 0.9);
    containerView.alpha = 0;
} completion:^(BOOL finished) {
    [containerView removeFromSuperview];
}];

3. 处理背景点击

可以通过添加手势识别器来实现点击背景关闭选择器:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleBackgroundTap:)];
[containerView addGestureRecognizer:tap];

// 确保点击事件不会传递给选择器
tap.delegate = self;

#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // 如果点击的是选择器区域,则不响应
    if (CGRectContainsPoint(pickerView.frame, [touch locationInView:containerView])) {
        return NO;
    }
    return YES;
}

注意事项

  1. 内存管理:确保在容器视图被移除时,所有相关的block回调都被正确释放,避免循环引用。

  2. 用户体验:在异步操作期间,应该提供适当的加载指示器,让用户知道操作正在进行中。

  3. 错误处理:当数据验证失败时,应该给用户明确的反馈,而不是静默失败。

  4. 动画协调:如果应用中有多个可能同时显示的选择器,需要协调它们的显示/隐藏动画。

通过这种自定义容器视图的方式,开发者可以完全掌控BRPickerView的显示和隐藏时机,满足各种复杂的业务场景需求,同时保持流畅的用户体验。

登录后查看全文
热门项目推荐

热门内容推荐

最新内容推荐

项目优选

收起
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
176
261
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
860
511
ShopXO开源商城ShopXO开源商城
🔥🔥🔥ShopXO企业级免费开源商城系统,可视化DIY拖拽装修、包含PC、H5、多端小程序(微信+支付宝+百度+头条&抖音+QQ+快手)、APP、多仓库、多商户、多门店、IM客服、进销存,遵循MIT开源协议发布、基于ThinkPHP8框架研发
JavaScript
93
15
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
129
182
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
259
300
kernelkernel
deepin linux kernel
C
22
5
cherry-studiocherry-studio
🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端
TypeScript
596
57
CangjieCommunityCangjieCommunity
为仓颉编程语言开发者打造活跃、开放、高质量的社区环境
Markdown
1.07 K
0
HarmonyOS-ExamplesHarmonyOS-Examples
本仓将收集和展示仓颉鸿蒙应用示例代码,欢迎大家投稿,在仓颉鸿蒙社区展现你的妙趣设计!
Cangjie
398
371
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
332
1.08 K