iOS:在调用 view.hidden = NO 之后,有没有办法确定 UIView 何时出现

Posted

技术标签:

【中文标题】iOS:在调用 view.hidden = NO 之后,有没有办法确定 UIView 何时出现【英文标题】:iOS: Is there a way to determine when an UIView did appear, after calling view.hidden = NO 【发布时间】:2011-05-31 16:37:29 【问题描述】:

我有一个带有 8 到 10 个大图像(每个都加载到 UIImageView 中)作为子视图的 UIView。这些图像彼此相邻对齐,因此它们构成了一个真正的长水平图像。这个视图被放入一个 UIScrollView 中,这样用户就可以沿着这个长长的水平图像滚动。

加载所有这些图像(来自网络)需要相当长的时间,所以我决定将加载代码放入 NSOperation 子类中。在操作的 main 方法中,每个 ImageView 都被添加到容器视图中。

在此过程中视图被隐藏,取而代之的是一个小的旋转图像(很像 UIActivityIndi​​catorView)。这是一些代码:

CategoryViewController.m

- (id)initWithFrame:(CGRect)frame

    self = [super init];
    if(self)
    
        // do some unrelated stuff
        [...]

        loadIndicator = [[UIImageView alloc] initWithImage:img];
        [loadIndicator setFrame:CGRectMake((frame.size.width - width) / 2, (frame.size.height - height) / 2, width, height)];
        [loadIndicator setHidden:YES];

        // this is the view which will contain those large images
        backgroundView = [[UIView alloc] init];
        backgroundView.hidden = YES;

        scrollView = [[UIScrollView alloc] initWithFrame:frame];
        [scrollView setDelegate:(id<UIScrollViewDelegate>)self];
        [scrollView addSubview:backgroundView];  

        [self.view setFrame:frame];
    
    return self;


- (void)viewDidLoad

    // do some unrelated stuff
    [...]

    [self.view addSubview:loadIndicator];
    [self.view addSubview:scrollView];

    // setup a custom activity indicator
    loadIndicator.hidden = NO;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];
    loadIndicatorRotation = 0;
    rotationTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector:@selector(updateRotation:) userInfo: nil repeats: YES];
    [UIView commitAnimations];

    // setup the operation to load all background images
    operationQueue = [[NSOperationQueue alloc] init];
    LoadBackgroundImagesOperation* operation = [[LoadBackgroundImagesOperation alloc] initWithImages:bgImageNames View:backgroundView Frame:frame];

    // register to recieve the finish notification
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onFinishedLoadingBgImages) name:@"BgImagesFinishedLoading" object:operation];

    // Add the operation to the queue
    [operationQueue addOperation:operation];
    [operation release];
    [super viewDidLoad];

LoadBackgroundImagesOperation.m的主要方法

- (void)main

    int left = 0;
    int width, height;

    int i;
    for(i = 0; i < imageNames.count; i++)
    
        if([self isCancelled])
        
            [[NSNotificationCenter defaultCenter] postNotificationName:@"BgImagesCancelled" object:self];
            return;
        

        // code to retrieve the url of current image
        [...]

        NSData* data = [[NSData alloc] initWithContentsOfURL:imgURL];
        UIImage* image = [[UIImage alloc] initWithData:data];
        [data release];

        double scalingFactor = frame.size.height / image.size.height;
        width = image.size.width * scalingFactor;
        height = image.size.height * scalingFactor;

        UIImageView* imgView = [[UIImageView alloc] initWithImage:image];
        [image release];

        [imgView setFrame:CGRectMake(left, 0, width, height)];
        [background addSubview:imgView];
        [imgView release];

        left += width;
        [background setFrame:CGRectMake(0, 0, left, height)];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:@"BgImagesFinishedLoading" object:self];

操作完成后,我隐藏旋转图像并显示包含大图像的视图。

(再次返回 CategoryViewController.m)

- (void) onFinishedLoadingBgImages

    [scrollView setContentSize:backgroundView.frame.size];

    backgroundView.hidden = NO;
    loadIndicator.hidden = YES;

    if(operationQueue != nil)
    
        [operationQueue cancelAllOperations];
        [operationQueue release];
        operationQueue = nil;
    
    [rotationTimer invalidate];
    rotationTimer = nil;

问题是,在调用backgroundView.hidden = NO后,直到图像真正可见,模拟器需要大约 2 秒,而在真实设备上最多需要 5 秒。

在那段时间我会继续显示活动指示器,但我不知道如何检测到 backgroundview 确实出现了以便再次隐藏指示器。

我尝试将backgroundview 放在它自己的 UIViewController 中,并在调用 viewDidAppear 时通知我的父视图控制器,但这不起作用。 (我在嵌套视图控制器中读到过,我必须手动调用 viewDidAppear,但这不是一个选项,因为我不知道它何时出现)。

另外,我不能只做肮脏的把戏,改变backgroundViewloadIndicator 的顺序来隐藏它,因为大多数图像都有一些透明度,所以用户仍然会看到指示器。

所以我真的希望你们中的任何人都对如何检测backgroundview 何时真正可见提出建议。

谢谢, 克里斯

哦,抱歉,如果某些代码与问题无关。只是想向您介绍我正在做的事情。

【问题讨论】:

【参考方案1】:

您可以做的是创建一个 UIViewController 子类,并使其成为该视图的所有者,在该方法中,您可以尝试将所需的代码放入 viewDidLoad 方法中,看看是否更准确,但是我认为真正的问题是您使用的 imageViews 正在花时间加载图像,而不是 UIView。因此,UIView 是可见的,但是 imageViews 还没有加载它们的图像,所以你什么都看不到。

【讨论】:

这就是我所怀疑的。我认为也许有一种方法可以确定 imageViews 何时出现,但我想没有。【参考方案2】:

如果您在滚动视图中显示大量大图像,您应该真正考虑平铺它们,以便可以单独加载部分图像,并且您不必在内存中保留多个大图像同时。查看CATiledLayer 和PhotoScroller 示例代码。

【讨论】:

感谢您提供示例链接。我去看看。

以上是关于iOS:在调用 view.hidden = NO 之后,有没有办法确定 UIView 何时出现的主要内容,如果未能解决你的问题,请参考以下文章

如何用动画取消隐藏 UIView

重新加载表格后 UITableView 编辑设置为 NO

iOS-报错“No visible @interface for ‘NSObject‘ declares the selector ‘XXXX:‘”

iOS Category实现原理 (补充)

linkUserInBackground 返回成功为 NO

ios8调用 - (void) onKeyboardShow:(NSNotification *)通知两次