如何在旋转开始之前显示 UIActivityIndi​​catorView [英] how to display UIActivityIndicatorView BEFORE rotation begins

查看:24
本文介绍了如何在旋转开始之前显示 UIActivityIndi​​catorView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 willAnimateRotationToInterfaceOrientation:duration: 进行的工作开始之前显示一个活动指示器.在我的应用程序的大部分时间里,这项工作很快完成,不需要活动指示器,但偶尔(第一次轮换,即在我缓存数据之前,处理大文件时)可能会有明显的延迟.与其重新构建我的应用程序以应对这种不常见的情况,我宁愿只显示 UIActivityIndi​​catorView,同时应用程序生成缓存并更新显示.

I'd like to display an activity indicator BEFORE the work undertaken by willAnimateRotationToInterfaceOrientation:duration: begins. Most of the time in my app, this work is quickly completed and there would be no need for an activity indicator, but occasionally (first rotation, i.e. before I have cached data, when working with a large file) there can be a noticeable delay. Rather than re-architect my app to cope with this uncommon case, I'd rather just show the UIActivityIndicatorView while the app generates a cache and updates the display.

问题是(或似乎是)显示未在 willRotateToInterfaceOrientation:duration 和 willAnimateRotationToInterfaceOrientation:duration: 方法之间更新.因此,要求 iOS 在 willRotate 方法中显示 UIActivityIndi​​cator 视图实际上不会影响显示,直到 willAnimateRotation 方法之后.

The problem is (or seems to be) that the display is not updated between the willRotateToInterfaceOrientation:duration and the willAnimateRotationToInterfaceOrientation:duration: method. So asking iOS to show UIActivityIndicator view in willRotate method doesn't actually affect the display until after the willAnimateRotation method.

以下代码说明了该问题.运行时,活动指示器仅在 simulateHardWorkNeededToGetDisplayInShapeBeforeRotation 方法完成后非常短暂地出现.

The following code illustrates the issue. When run, the activity indicator appears only very briefly and AFTER the simulateHardWorkNeededToGetDisplayInShapeBeforeRotation method has completed.

我是否遗漏了一些明显的东西?如果没有,关于我如何解决这个问题的任何聪明的想法?

Am I missing something obvious? And if not, any smart ideas as to how I could work around this issue?

更新:虽然关于将繁重的工作转移到另一个线程等方面的建议通常很有帮助,但在我的特殊情况下,我有点确实想阻塞主线程做我的举重.在应用程序中,我有一个 tableView,所有的高度都需要重新计算.当 - 这不是一个非常常见的用例,或者我什至不会考虑这种方法 - 有很多行,所有新高度都在 [tableView reloadData] 期间计算(然后缓存).如果我完成提升并让旋转继续进行,那么在旋转之后和提升之前,我的 tableView 还没有被重新加载.例如,在纵向到横向的情况下,它不会占据整个宽度.当然,还有其他解决方法,例如在旋转之前构建一个只有几行的 tableView,然后重新加载真实的等等.

Update: While suggestions about farming the heavy lifting off to another thread etc. are generally helpful, in my particular case I kind of do want to block the main thread to do my lifting. In the app, I have a tableView all of whose heights need to be recalculated. When - which is not a very common use case or I wouldn't even be considering this approach - there are very many rows, all the new heights are calculated (and then cached) during a [tableView reloadData]. If I farm the lifting off and let the rotate proceed, then after the rotate and before the lifting, my tableView hasn't been re-loaded. In the portrait to landscape case, for example, it doesn't occupy the full width. Of course, there are other workarounds, e.g. building a tableView with just a few rows prior to the rotate and then reloading the real one over that etc.

说明问题的示例代码:

@implementation ActivityIndicatorViewController

@synthesize activityIndicatorView = _pgActivityIndicatorView;
@synthesize label = _pgLabel;

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}


- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
{
    NSLog(@"willRotate");

    [self showActivityIndicatorView];
}


- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
{
    NSLog(@"willAnimateRotation");
    [self simulateHardWorkNeededToGetDisplayInShapeBeforeRotation];
}


- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;
{
    NSLog(@"didRotate");
    [self hideActivityIndicatorView];
}


- (void) simulateHardWorkNeededToGetDisplayInShapeBeforeRotation;
{
    NSLog(@"Starting simulated work");
    NSDate* date = [NSDate date];

    while (fabs([date timeIntervalSinceNow]) < 2.0)
    {
        //
    }
    NSLog(@"Finished simulated work");
}


- (void) showActivityIndicatorView;
{
    NSLog(@"showActivity");
    if (![self activityIndicatorView])
    {
        UIActivityIndicatorView* activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        [self setActivityIndicatorView:activityIndicatorView];
        [[self activityIndicatorView] setCenter:[[self view] center]];
        [[self activityIndicatorView] startAnimating];
        [[self view] addSubview: [self activityIndicatorView]];
    }

    // in shipping code, an animation with delay would be used to ensure no indicator would show in the good cases
    [[self activityIndicatorView] setHidden:NO];
}

- (void) hideActivityIndicatorView;
{
    NSLog(@"hideActivity");
    [[self activityIndicatorView] setHidden:YES];
}


- (void) dealloc;
{
    [_pgActivityIndicatorView release];
    [super dealloc];
}


- (void) viewDidLoad;
{
    UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(50.0, 50.0, 0.0, 0.0)];
    [label setText:@"Activity Indicator and Rotate"];
    [label setTextAlignment: UITextAlignmentCenter];
    [label sizeToFit];
    [[self view] addSubview:label];
    [self setLabel:label];
    [label release];
}

@end

推荐答案

更多挖掘(首先在 Matt Neuberg 的 iPhone 4 编程中)然后 这个关于强制核心动画从 stackoverflow 运行其线程的有用问题,我有一个似乎运行良好的解决方案.Neuberg 和 Apple 都对这种方法提出了强烈的警告,因为它可能会产生不受欢迎的副作用.到目前为止的测试中,对于我的特殊情况似乎没问题.

More digging (first in Matt Neuberg's Programming iPhone 4) and then this helpful question on forcing Core Animation to run its thread from stackoverflow and I have a solution that seems to be working well. Both Neuberg and Apple issue strong caution about this approach because of the potential for unwelcome side effects. In testing so far, it seems to be OK for my particular case.

对上面的代码进行如下更改,即可实现更改.关键的添加是 [CATransaction flush],强制 UIActivityIndi​​catorView 开始显示,即使运行循环直到 willAnimateRotationToInterfaceOrientation:duration 方法完成后才会结束.>

Changing the code above as follows implements the change. The key addition is [CATransaction flush], forcing the UIActivityIndicatorView to start displaying even though the run loop won't be ended until after the willAnimateRotationToInterfaceOrientation:duration method completes.

- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
{
    NSLog(@"willRotate");

    [self showActivityIndicatorView];
    [CATransaction flush];  // this starts the animation right away, w/o waiting for end of the run loop
}

- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
{
    NSLog(@"willAnimateRotation");
    [self simulateHardWorkNeededToGetDisplayInShapeBeforeRotation];
    [self hideActivityIndicatorView];
}


- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;
{
    NSLog(@"didRotate");
}

这篇关于如何在旋转开始之前显示 UIActivityIndi​​catorView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆