我如何通过编程在视图中间创建一个活动指示器?

13

我正在使用一款应用程序来解析在线提要。当我点击刷新按钮时,它需要一些时间来重新解析文件并显示其数据。我希望在单击刷新按钮时在视图中央有一个活动指示器。而当解析完成后,该指示器应该隐藏。

我正在使用以下代码,但它不起作用:

- (IBAction)refreshFeed:(id)sender
{
   UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
   [self.view addSubview:spinner];

   [spinner startAnimating];

   // parsing code code
    
   [spinner release];
}

活动指示器没有出现。这是一个基于导航的应用程序。refreshFeed在rootViewController中。 - Piscean
14个回答

17

为了让UIActivityIndicator出现,通常需要将其放置在与长时间进程(解析feed)不同的线程中。

如果您想将所有内容保持在同一个线程中,则需要给指示器一些时间来出现。 这篇Stackoverflow问题 解决了在代码中加入延迟的问题。

编辑:两年后,我认为如果您使用延迟来使某些事情发生,那么您可能做错了。现在,我会这样完成此任务:

- (IBAction)refreshFeed:(id)sender {
    //main thread
    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; [self.view addSubview:spinner];

    //switch to background thread
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

        //back to the main thread for the UI call
        dispatch_async(dispatch_get_main_queue(), ^{
            [spinner startAnimating];
        });
        // more on the background thread

        // parsing code code

        //back to the main thread for the UI call
        dispatch_async(dispatch_get_main_queue(), ^{
            [spinner stopAnimating];
        });
    });
}

不是这样的。您需要在主线程上添加指示器,并在后台线程中执行工作。UI 只能由主线程触摸。 - dwery
2
是的,两年前我不像现在聪明。我已经更新了答案。 - Walter

13
我觉得我无法很好地解释它。嗯,让我们再试一次。这是一个基于导航的应用程序。我有一个tableView。每个单元格创建一个detailView。在根视图上(即tableView),有一个刷新按钮。当我点击该按钮时,它会重新解析反馈,并需要一些时间。在此期间,程序不会响应。解析完成后,它才能够正常工作。现在我需要一个活动指示器。我不知道如何在 xib 中添加它。因为当我打开 main.xib 并将活动指示器放入 RootViewController 时,它会出现在整个 tableView 的前面。现在可能我解释得更清楚了,如果还不行,请告诉我,我会再试一次。
根据你上述所说,当程序在解析数据时出现卡顿是一个问题。如果GUI在解析数据时冻结,你应该将操作移至辅助线程。这样,您的 GUI 保持响应,并且您将能够看到活动指示器。
在主线程上,您应该编写类似以下内容以显示活动指示器:
UIActivityIndicatorView  *av = [[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray] autorelease];
av.frame = CGRectMake(round((yourView.frame.size.width - 25) / 2), round((yourView.frame.size.height - 25) / 2), 25, 25);
av.tag  = 1;
[yourView addSubview:av];
[av startAnimating];

在次要线程完成后,这是您解析数据的线程,您应该在主线程中调用类似以下内容以删除活动指示器:

UIActivityIndicatorView *tmpimg = (UIActivityIndicatorView *)[yourView viewWithTag:1];
[tmpimg removeFromSuperview];

7

将活动指示器的中心位置更改为

activityIndicator.center = self.view.center;

它不起作用。这是一个基于导航的应用程序。refreshFeed在rootViewController中。我应该写self.view.center吗? - Piscean
什么出了问题?请详细描述发生了什么。您是否看到旋转器或根本没有旋转器? - xxcv
根本没有旋转器。这是一个基于导航的应用程序。函数refreshFeed位于rootViewController中。 - Piscean
注意:您必须包含下面的代码行activityIndicator.autoresizingMask = (UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin) - Edwin O.

7
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.alpha = 1.0;
[collectionVwSearch addSubview:activityIndicator];
activityIndicator.center = CGPointMake([[UIScreen mainScreen]bounds].size.width/2, [[UIScreen mainScreen]bounds].size.height/2);
[activityIndicator startAnimating];//to start animating

针对Swift语言

let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
activityIndicator.alpha = 1.0
collectionVwSearch.addSubview(activityIndicator)
activityIndicator.center = CGPointMake(UIScreen.mainScreen().bounds.size.width / 2, UIScreen.mainScreen().bounds.size.height / 2)
activityIndicator.startAnimating()

为了停止 activityIndicator,请在适当位置写入 [activityIndicator stopAnimating]

1
它应该是 activityIndicator.center = CGPointMake([[UIScreen mainScreen]bounds].size.width/2, [[UIScreen mainScreen]bounds].size.height/2); - Poles

2
self.activity.center = CGPointMake(self.view.bounds.size.width / 2.0f, self.view.bounds.size.height / 2.0f);
self.activity.autoresizingMask = (UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin);

1
在Swift中,这对我的应用程序有效。
let activity_view = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
activity_view.frame =  CGRectMake(0.0, 0.0, 40.0,40.0)
activity_view.center = self.view.center
self.view.addSubview(activity_view)
activity_view.bringSubviewToFront(self.view)
activity_view.startAnimating()

1
在开始任务之前,请添加以下代码:

UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[self.view addSubview:spinner];
[spinner setFrame:CGRectMake((self.view.frame.size.width/2)-(spinner.frame.size.width/2), (self.view.frame.size.height/2)-(spinner.frame.size.height/2), spinner.frame.size.width, spinner.frame.size.height)];
[spinner startAnimating];    

完成任务后,请添加以下内容:

[spinner stopAnimating];

0

你可以写Swift 4

let spinner = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)

override func viewDidLoad() {
    super.viewDidLoad()

    spinner.backgroundColor = UIColor(white: 0, alpha: 0.2) // make bg darker for greater contrast
    self.view.addSubview(spinner)
}

@IBAction func foodActionBtn(_ sender: Any) {

    // start spinner
    spinner.frame = self.view.frame // center it
    spinner.startAnimating()

    let qualityOfServiceClass = QOS_CLASS_BACKGROUND
    let backgroundQueue = DispatchQueue.global(qos: .background)
    backgroundQueue.async(execute: {
        sleep(2)
        self.spinner.stopAnimating()
    })
}

欢迎来到SO,请完整格式化您的源代码并详细描述。 - cSteusloff

0
/ create activity indicator 
activityIndicator = [[UIActivityIndicatorView alloc] 
    initWithFrame:CGRectMake(0.0f, 0.0f, 20.0f, 20.0f)];
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite];

...
 [self.view addSubview:activityIndicator];
// release it
[activityIndicator release];

更好的方法是在xib上添加指示器,并根据您的要求进行隐藏/显示。

它不起作用。这是一个基于导航的应用程序。refreshFeed在RootViewController中。我应该写self.view还是self.tableView? - Piscean
可能您的视图前面有一些遮挡,所以它可能不可见。如果您是通过XIB添加视图,请确保在取消隐藏后可以编写它。 - Swastik
[self.view bringSubviewToFront:spinner]; [self.view bringSubviewToFront:spinner]; - Swastik
据我理解,您应该在刷新按钮所在的位置添加指示器。 - Swastik
这是一个基于导航的应用程序。它解析一个源并在tableView中显示源项目。现在在RootViewController中有一个刷新按钮。当我点击该按钮时,它会删除所有数据,重新解析XML,然后再在tableView中显示新数据。只是问题在于当我点击刷新按钮时,需要一些时间来刷新数据。而在此期间,应用程序无法响应。我需要一个活动指示器,当用户点击刷新按钮时,它将显示在前面。以便在应用程序无法响应时使用。我是否解释清楚了我的问题? - Piscean
显示剩余4条评论

0
spinner.center = self.view.center;

如果要从根视图控制器显示旋转器,请尝试以下操作:

[self.navigationController.visibleViewController.view addSubview:spinner];

或者

[self.navigationController.view addSubview:spinner];

它不起作用。这是一个基于导航的应用程序。refreshFeed在rootViewController中。我应该写self.view.center吗? - Piscean
活动指示器根本没有出现。 - Piscean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接