在后台线程中向 UIScrollView 添加大量按钮 - 按钮不可见

Posted

技术标签:

【中文标题】在后台线程中向 UIScrollView 添加大量按钮 - 按钮不可见【英文标题】:Adding larg number of Buttons to UIScrollView in background thread - Buttons not visible 【发布时间】:2014-10-29 11:13:15 【问题描述】:

用户应该能够从大量不同的图标中选择一个图标。我创建了一个选择器对话框,允许用户进行选择。用于此选取器的 ViewController 仅包含一个 UIScrollView。在viewDidLoad 中,为每个图标添加一个按钮到 ScrollView。要选择一个图标,用户只需点击相应的按钮...

这工作正常,但 ViewController/picker 需要几秒钟才能显示。这是因为viewDidLoad 中有许多分配/添加操作。因此,我试图将这些选项移动到后台线程中。这工作正常,但创建的按钮不再可见:

- (void)viewDidLoad 
    [super viewDidLoad];

    self.iconsScrollView.hidden = true;
    [self.activityIndicator startAnimating];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
        iconContainer = [[UIView alloc] init];
        iconContainer.backgroundColor = [UIColor clearColor];

        iconButtons = [[NSMutableDictionary alloc] init];

        CGRect buttonRect = CGRectMake(5, 5, 40, 40);
        selectedButton = nil;

        NSArray *iconInfos = [[StoreController sharedController] allIcons];

        for (IconInfo* iconInfo in iconInfos) 
            NSString *iconName = iconInfo.name;

            UIButton *iconButton = [UIButton buttonWithType:UIButtonTypeCustom];
            iconButton.frame = buttonRect;

            [iconButton addTarget:self action:@selector(iconSelectionClick:) forControlEvents: UIControlEventTouchUpInside];
            [iconButton setImage:[UIImage imageNamed:iconName] forState:UIControlStateNormal];

            [iconContainer addSubview:iconButton];
            [iconButtons setObject:iconButton forKey:iconInfo.guid];

            buttonRect.origin.x += 50;
            if (buttonRect.origin.x > 205) 
                buttonRect.origin.x = 5;
                buttonRect.origin.y += 50;
            
        

        iconContainer.frame = CGRectMake(0, 0, self.iconsScrollView.frame.size.width, ceil([iconButtons count] / 5.0) * 50);

        dispatch_async(dispatch_get_main_queue(), ^
            [self.iconsScrollView addSubview:iconContainer];
            self.iconsScrollView.contentSize = iconContainer.frame.size;

            [self.activityIndicator stopAnimating];
            self.iconsScrollView.hidden = false;

            [self.view setNeedsDisplay];
        );
    );

这(几乎)没有任何问题:

Picker ViewController 出现 ActivityIndi​​cator 在创建按钮时可见 一旦所有按钮都准备就绪,ActivityIndi​​cator 就会停止并且 ScrollView 变得可见。

唯一的问题:按钮不可见。 ScrollView 可以正常使用(内容大小正确),当我在 ScrollView 内部触摸并点击一个不可见的按钮时,会调用单击选择器。因此所有按钮都在那里但不可见。最终在 10-15 秒后,所有按钮都立即可见。

对 View、ScrollView 或按钮使用 setNeedsDisplaysetNeedsLayout 不会改变任何内容。

知道我能做什么吗?

【问题讨论】:

您只能从主线程有效地更改 UI。 【参考方案1】:

当您不在主线程上时,您正在向子视图添加按钮。

一般来说,UIKit 代码应该只在主队列上运行。

【讨论】:

我已经尝试只在后台线程中创建按钮并将添加到 scrollView 的内容移回主线程。结果都是一样的。据我所知,现有 UI 的所有 UI“交互”(添加、删除、调整大小、属性更改)都必须在主线程中完成。但是与(还)不是视图树一部分的 UI 对象进行交互应该没有问题,不是吗? 好的,不冻结 UI 的正确解决方案是什么? 不要向滚动视图添加按钮,使用更有效的方式同时呈现多个项目 - 类似于集合视图。【参考方案2】:

UIKit 只能从主线程更新

dispatch_async(dispatch_get_main_queue(), ^(void)
    //Run UI Updates
);

【讨论】:

以上是关于在后台线程中向 UIScrollView 添加大量按钮 - 按钮不可见的主要内容,如果未能解决你的问题,请参考以下文章

如何通过滑动向 UIScrollView 添加另一个页面?

我正在尝试在第二个线程中向自身添加一个 int 并且我的主线程中没有任何变化

UIScrollview - 屏幕外按钮不会触发

UIScrollView 动画滞后

R中向具有大量数据集的数据框添加新列的有效方法

在 Eclipse 中向项目添加注释