如何以编程方式在视图中间创建活动指示器?

发布于 2024-10-19 13:03:24 字数 447 浏览 5 评论 0原文

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

我正在使用这段代码,但它不起作用:

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

   [spinner startAnimating];

   // parsing code code
    
   [spinner release];
}

I am working with an app which parses an feed online. When I click the refresh button, it takes some time to re parse the file and show its data. I want an activity indicator in the middle of the view when I click refresh button. And when parsing is done, that indicator should hide.

I am using this code but it is not working:

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

   [spinner startAnimating];

   // parsing code code
    
   [spinner release];
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

你的往事 2024-10-26 13:03:24

UIActivityIndi​​cator 通常需要放置在长进程(解析提要)之外的单独线程中才能显示。

如果您想将所有内容保留在同一个线程中,那么您需要给指示器时间来显示。 此 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];
        });
    });
}

A UIActivityIndicator generally needs to be placed into a separate thread from the long process (parsing feed) in order to appear.

If you want to keep everything in the same thread, then you need to give the indicator time to appear. This Stackoverflow question addresses placing a delay in the code.

EDIT: Two years later, I think that any time you are using a delay to make something happen you are probably doing it wrong. Here is how I would do this task now:

- (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];
        });
    });
}
因为看清所以看轻 2024-10-26 13:03:24

我想我无法解释它
好吧,让我们再试一次。它是一个导航
基于应用程序。我有表视图。每一个
单元格创建一个详细视图。在根视图上
这是一个表格视图,有一个
刷新按钮。当我点击那个时
按钮它会再次解析提要。和
这需要一些时间。那时
程序没有响应。解析是
完成它再次工作。现在我需要
当时的活动指示器。我
不知道如何添加到xib中。 BCZ 当
我打开 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];

I think i am not able to explain it
well.ok lets try again. its a nav
based app. i have tableView. every
cell creates a detailView. on RootView
which is a tableview there is a
refresh button. when i click that
button it parses the feed again. and
it takes some time. for that time
program doesnt respond. and parsing is
complete it works again. now i need
activity indicator for that time. i
dont know how to add in xib. bcz when
i open main.xib and put activity
indicator in RootViewController. it
comes infront of whole tableView. now
may be i explained well. if not let me
know i ll try again.

from what you are saying above the program is not responding during the parsing which is a problem. If the GUI freezes while you are parsing the data you should move that operation to a secondary thread. That way your GUI remains responsive and you will be able to see the activity indicator.

on the main thread you should have something similar to this in order to show the activity indicator:

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];

after the secondary thread is finished, this is the thread where you parse the data, you should call on the main thread something like this to remove the activity indicator:

UIActivityIndicatorView *tmpimg = (UIActivityIndicatorView *)[yourView viewWithTag:1];
[tmpimg removeFromSuperview];
给妤﹃绝世温柔 2024-10-26 13:03:24

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

activityIndicator.center = self.view.center;

Change the center of the activity indicator as

activityIndicator.center = self.view.center;
刘备忘录 2024-10-26 13:03:24
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()

在适当的位置停止 ActivityIndi​​cator wirte [activityIndi​​cator stopAnimating]

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

For 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()

To stop activityIndicator wirte [activityIndicator stopAnimating] on appropriate place

裸钻 2024-10-26 13:03:24
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);
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);
疏忽 2024-10-26 13:03:24

在开始任务之前添加此代码:

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];

Add this code before starting your task:

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];    

After completion of the task add:

[spinner stopAnimating];
花落人断肠 2024-10-26 13:03:24

在 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()

In Swift, this worked for my app

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()
小巷里的女流氓 2024-10-26 13:03:24
/ 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 & 上添加指标根据您的要求使其隐藏/取消隐藏

/ 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];

Better approach would be you add indicatore on xib & make it hide/unhide basedon your requirement

锦爱 2024-10-26 13:03:24
spinner.center = self.view.center;

要从 rootController 显示微调器,请尝试:

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

[self.navigationController.view addSubview:spinner];
spinner.center = self.view.center;

To show spinner from rootController try:

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

or

[self.navigationController.view addSubview:spinner];
廻憶裏菂餘溫 2024-10-26 13:03:24

尝试这样

activityIndicator.center = CGPointMake(160,240);

try like this

activityIndicator.center = CGPointMake(160,240);
属性 2024-10-26 13:03:24

其他一些答案的问题是每次都会添加一个新的活动指示器,因此子视图开始堆积。这是一个仅使用单个 UIActivityIndi​​cator 的完整示例。

输入图片这里的描述

这是上面项目的完整代码:

import UIKit
class ViewController: UIViewController {

    // only using a single spinner instance
    let spinner = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)

    override func viewDidLoad() {
        super.viewDidLoad()

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

    @IBAction func startSpinnerButtonTapped(sender: UIButton) {

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

        let qualityOfServiceClass = QOS_CLASS_BACKGROUND
        let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
        dispatch_async(backgroundQueue, {       

            // do something that takes a long time
            sleep(2)

            // stop spinner when background task finishes
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.spinner.stopAnimating()
            })
        })
    }
}

The problem with some of the other answers is that a new activity indicator gets added every time so the subviews start piling up. Here is a complete example that only uses a single UIActivityIndicator.

enter image description here

This is the entire code for the project above:

import UIKit
class ViewController: UIViewController {

    // only using a single spinner instance
    let spinner = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)

    override func viewDidLoad() {
        super.viewDidLoad()

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

    @IBAction func startSpinnerButtonTapped(sender: UIButton) {

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

        let qualityOfServiceClass = QOS_CLASS_BACKGROUND
        let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
        dispatch_async(backgroundQueue, {       

            // do something that takes a long time
            sleep(2)

            // stop spinner when background task finishes
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.spinner.stopAnimating()
            })
        })
    }
}
萌酱 2024-10-26 13:03:24

你可以写 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()
    })
}

You can write 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()
    })
}
噩梦成真你也成魔 2024-10-26 13:03:24

SWIFT 5

声明

let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(style: UIActivityIndicatorView.Style.medium)
//if you want a bigger activity indicator, change style from .medium to .large

ViewDidLoad

activityIndicator.alpha = 1.0
view.addSubview(activityIndicator)
activityIndicator.center = view.center

Activate activity indicator, in my case it is in `didSelectRowAt` method

activityIndicator.startAnimating()

如果您在动画处于活动状态时推送到另一个视图控制器,然后弹出回来,您仍然会看到活动指示器动画,因此您应该这样做

override func viewWillAppear(_ animated: Bool) {
        if activityIndicator.isAnimating {
            activityIndicator.stopAnimating()
        }
    }

SWIFT 5

Declaration

let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(style: UIActivityIndicatorView.Style.medium)
//if you want a bigger activity indicator, change style from .medium to .large

ViewDidLoad

activityIndicator.alpha = 1.0
view.addSubview(activityIndicator)
activityIndicator.center = view.center

Activate activity indicator, in my case it is in `didSelectRowAt` method

activityIndicator.startAnimating()

If you push to another viewController while animation is active, and then pop back, you will still see activity indicator animating, so you should do this

override func viewWillAppear(_ animated: Bool) {
        if activityIndicator.isAnimating {
            activityIndicator.stopAnimating()
        }
    }
沦落红尘 2024-10-26 13:03:24

Poscean 先生我的代码正在运行。但是如果您想显示活动指示器的大外观,您可以使用它......

var activityIndicator = UIActivityIndicatorView()
    activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
    activityIndicator.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
    let transform: CGAffineTransform = CGAffineTransform(scaleX: 1.5, y: 1.5)
    activityIndicator.transform = transform
    activityIndicator.center = self.view.center
    activityIndicator.startAnimating()
    self.view.addSubview(activityIndicator)

Mr Poscean my code is working. But is you want show big appearing of activity indicator you can use it....

var activityIndicator = UIActivityIndicatorView()
    activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
    activityIndicator.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
    let transform: CGAffineTransform = CGAffineTransform(scaleX: 1.5, y: 1.5)
    activityIndicator.transform = transform
    activityIndicator.center = self.view.center
    activityIndicator.startAnimating()
    self.view.addSubview(activityIndicator)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文