web-dev-qa-db-ja.com

IOS:UITableView上のActivityIndi​​cator ...方法は?

(別のスレッドで)データをロードしている間、uitableview上にアクティビティインジケーターを表示したい。したがって、UITableViewControllerのViewDidLoadメソッドでは次のようになります。

-(void)viewDidLoad
 {
    [super viewDidLoad];

    //I create the activity indicator
    UIActivityIndicatorView *ac = [[UIActivityIndicatorView alloc]  
                      initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    [ac startAnimating];

    //Create the queue to download data from internet
    dispatch_queue_t downloadQueue = dispatch_queue_create("PhotoDownload",NULL); 
    dispatch_async(downloadQueue, ^{
      //Download photo
      .......
      .......
      dispatch_async(dispatch_get_main_queue(), ^{
         ......
         ......
         [ac stopAnimating];
      });
    });
   .......

アクティビティインジケーターがテーブルビューに表示されないのはなぜですか?どうすればそれを達成できますか?

18
Tom

UIActivityIndi​​catorViewを何かに追加する必要があります。 UITableViewヘッダービューに追加できます。これを行うには、独自のカスタムビューを提供する必要があります。

...
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
[view addSubview:ac]; // <-- Your UIActivityIndicatorView
self.tableView.tableHeaderView = view;
...
21
bbarnhart

私はその解決策を見つけようとしていて、たくさんのフォーラムを読んだことがありますが、私は望むものを手に入れることができませんでした。アクティビティインジケーターとテーブルビューコントローラーのしくみを理解した後、次の解決策を思いつきました。

何らかの理由で、tableReloadまたは他の負荷の高いプロセスと同じスレッドでアクティビティインジケーターを開始しようとすると、アクティビティインジケーターが実行されません。別のスレッドでテーブルの再読み込みやその他の操作を実行しようとすると、安全ではなく、エラーや望ましくない結果が生じる可能性があります。そのため、アクティビティインジケーターを表示するメソッドを別のスレッドで実行できます。

また、このソリューションをMBProgressHUDと組み合わせて、アクティビティインジケーター付きのビューよりも見栄えのするものを提示しました。いずれの場合も、activityViewの外観はカスタマイズできます。

-(void)showActivityViewer
{
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    UIWindow *window = delegate.window;
    activityView = [[UIView alloc] initWithFrame: CGRectMake(0, 0, window.bounds.size.width, window.bounds.size.height)];
    activityView.backgroundColor = [UIColor blackColor];
    activityView.alpha = 0.5;

    UIActivityIndicatorView *activityWheel = [[UIActivityIndicatorView alloc] initWithFrame: CGRectMake(window.bounds.size.width / 2 - 12, window.bounds.size.height / 2 - 12, 24, 24)];
    activityWheel.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite;
    activityWheel.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin |
                                      UIViewAutoresizingFlexibleRightMargin |
                                      UIViewAutoresizingFlexibleTopMargin |
                                      UIViewAutoresizingFlexibleBottomMargin);
    [activityView addSubview:activityWheel];
    [window addSubview: activityView];

    [[[activityView subviews] objectAtIndex:0] startAnimating];
}

-(void)hideActivityViewer
{
    [[[activityView subviews] objectAtIndex:0] stopAnimating];
    [activityView removeFromSuperview];
    activityView = nil;
}

- (IBAction)reloadDataAction:(id)sender {
    [NSThread detachNewThreadSelector:@selector(showActivityViewer) toTarget:self withObject:nil];  
    //... do your reload or expensive operations
    [self hideActivityViewer];
}
12
zirinisp

[iOS 5 +]
親ビューを追加せずにactivityWheelを表示するだけの場合は、activityWheelをtableViewに直接追加し、tableViewscontentOffsetを使用してフレームのy値を計算することもできます。

@interface MyTableViewController ()
@property (nonatomic, strong) UIActivityIndicatorView *activityView;
@end

// ....

- (void) showActivityView {
    if (self.activityView==nil) {
        self.activityView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero];
        [self.tableView addSubview:self.activityView];
        self.activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
        self.activityView.hidesWhenStopped = YES;
        // additional setup...
        // self.activityView.color = [UIColor redColor]; 
    }
    // Center 
    CGFloat x = UIScreen.mainScreen.applicationFrame.size.width/2;
    CGFloat y = UIScreen.mainScreen.applicationFrame.size.height/2;
    // Offset. If tableView has been scrolled
    CGFloat yOffset = self.tableView.contentOffset.y;
    self.activityView.frame = CGRectMake(x, y + yOffset, 0, 0);

    self.activityView.hidden = NO;
    [self.activityView startAnimating];
}

- (void) hideActivityView {
    [self.activityView stopAnimating];
}

ActivityViewがすぐに表示されない(または表示されない)場合は、zirinispの回答を参照するか、バックグラウンドで重い作業を行ってください。

6
MatthiasFranz

UIViewControllerには回避策があります。 (UIViewControllerをテーブルビューとともに使用して、UITableViewControllerを実現できます。)ストーリーボードで、UIViewControllerのビューにactivityIndi​​catorを追加します。次に、viewDidLoadに次を追加します。

[self.activityIndicator layer].zPosition = 1;

ActivityIndi​​catorがテーブルビューの上に表示されます。

4
DianeZhou