Как программно создать индикатор активности в середине представления?

Я работаю с приложением, которое анализирует ленту онлайн. Когда я нажимаю кнопку обновления, требуется некоторое время для повторного анализа файла и отображения его данных. Мне нужен индикатор активности в середине представления, когда я нажимаю кнопку обновления. И когда синтаксический анализ завершен, этот индикатор должен скрыться.

Я использую этот код, но он не работает:

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

   [spinner startAnimating];

   // parsing code code
    
   [spinner release];
}

person Piscean    schedule 24.02.2011    source источник
comment
индикатор активности не появляется. это приложение на основе навигации. и refreshFeed находится в rootViewController.   -  person Piscean    schedule 24.02.2011


Ответы (13)


UIActivityIndicator обычно должен быть помещен в отдельный поток из длинного процесса (синтаксический канал), чтобы он отображался.

Если вы хотите держать все в одном потоке, то вам нужно дать индикатору время, чтобы появиться. Этот вопрос 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];
        });
    });
}
person Walter    schedule 24.02.2011
comment
Ну, нет. Вы добавляете индикатор в основной поток и выполняете свою работу в фоновом потоке. Пользовательский интерфейс должен затрагиваться только основным потоком. - person dwery; 30.10.2013
comment
Да, два года назад я не был таким умным, как сейчас. Я обновил ответ. - person Walter; 08.01.2014

Я думаю, что не могу объяснить это хорошо. Хорошо, давайте попробуем еще раз. это приложение на основе навигации. у меня есть таблицавиев. каждая ячейка создает DetailView. в RootView, который представляет собой табличное представление, есть кнопка обновления. когда я нажимаю эту кнопку, он снова анализирует канал. и это занимает некоторое время. за это время программа не отвечает. и синтаксический анализ завершен, он снова работает. теперь мне нужен индикатор активности за это время. я не знаю, как добавить в xib. bcz, когда я открываю main.xib и помещаю индикатор активности в RootViewController. он появляется перед всей таблицей. теперь может быть я объяснил хорошо. если нет, дайте мне знать, я попробую еще раз.

из того, что вы говорите выше, программа не отвечает во время синтаксического анализа, что является проблемой. Если графический интерфейс зависает во время анализа данных, вы должны перенести эту операцию во вторичный поток. Таким образом, ваш графический интерфейс остается отзывчивым, и вы сможете увидеть индикатор активности.

в основном потоке у вас должно быть что-то похожее на это, чтобы показать индикатор активности:

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];
person Sorin Antohi    schedule 24.02.2011

Измените центр индикатора активности как

activityIndicator.center = self.view.center;
person visakh7    schedule 24.02.2011
comment
это не работает. это приложение на основе навигации. и refreshFeed находится в rootViewController. я должен написать self.view.center; - person Piscean; 24.02.2011
comment
Что не работает?. Напишите подробнее, что происходит. Вы видите спиннер или его нет вообще. - person xxcv; 24.02.2011
comment
спиннера нет вообще. это приложение на основе навигации. а функция refreshFeed находится в rootViewController. - person Piscean; 24.02.2011
comment
Обратите внимание, что вы должны включить следующую строку кода: - person Edwin O.; 04.01.2016

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 stopAnimating] в соответствующем месте

person Hardik Thakkar    schedule 14.03.2015
comment
Должно быть activityIndicator.center = CGPointMake([[UIScreen mainScreen]bounds].size.width/2, [[UIScreen mainScreen]bounds].size.height/2); - person Poles; 20.08.2015

Добавьте этот код перед запуском задачи:

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];
person iphondroid    schedule 05.11.2013

В 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()
person Juan Carlos Moreno    schedule 20.02.2016

/ 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 и заставить его скрывать/показывать в зависимости от ваших требований.

person Swastik    schedule 24.02.2011
comment
это не работает. это приложение на основе навигации. и refreshFeed находится в RootViewController. я должен написать self.view или self.tableView; - person Piscean; 24.02.2011
comment
он может быть не виден, может быть, у вас есть какой-то вид перед ним. если вы добавляете его через xib, убедитесь, что когда вы показываете его, вы можете написать - person Swastik; 24.02.2011
comment
[self.view BringSubviewToFront:spinner]; - person Swastik; 24.02.2011
comment
где вы добавляете счетчик на таблицу / представление? - person Swastik; 24.02.2011
comment
что все у вас есть в вашем xib? - person Swastik; 24.02.2011
comment
Я думаю, что не могу объяснить это хорошо. Хорошо, давайте попробуем еще раз. это приложение на основе навигации. у меня есть таблицавиев. каждая ячейка создает DetailView. в RootView, который представляет собой табличное представление, есть кнопка обновления. когда я нажимаю эту кнопку, он снова анализирует канал. и это занимает некоторое время. за это время программа не отвечает. и синтаксический анализ завершен, он снова работает. теперь мне нужен индикатор активности за это время. я не знаю, как добавить в xib. bcz, когда я открываю main.xib и помещаю индикатор активности в RootViewController. он появляется перед всей таблицей. теперь может быть я объяснил хорошо. если нет, дайте мне знать, я попробую еще раз - person Piscean; 24.02.2011
comment
как я понимаю, вы должны добавить индикатор, где у вас есть кнопка обновления. - person Swastik; 24.02.2011
comment
это приложение на основе навигации. который анализирует фид и показывает элементы фида в tableView. теперь в RootViewController у меня есть кнопка обновления. когда я нажимаю эту кнопку, она удаляет все данные, снова анализирует xml и затем отображает новые данные в tableView. работает нормально. Единственная проблема в том, что когда я нажимаю кнопку обновления, для обновления данных требуется некоторое время. и за это время приложение не отвечает. мне нужен индикатор активности, который появляется каждый раз, когда пользователь нажимает кнопку обновления. пока приложение не отвечает. я объяснил свой вопрос или нет? - person Piscean; 24.02.2011
comment
вы можете поместить индикатор в табличное представление в xib, сначала сделать его скрытым и отобразить при нажатии кнопки btn. когда вы отобразите, выведите его на передний план - person Swastik; 24.02.2011

spinner.center = self.view.center;

Чтобы показать счетчик из rootController, попробуйте:

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

or

[self.navigationController.view addSubview:spinner];
person xxcv    schedule 24.02.2011
comment
это не работает. это приложение на основе навигации. и refreshFeed находится в rootViewController. я должен написать self.view.center; - person Piscean; 24.02.2011
comment
индикатор активности вообще не появляется - person Piscean; 24.02.2011

попробуй так

activityIndicator.center = CGPointMake(160,240);
person visakh7    schedule 24.02.2011

Проблема с некоторыми другими ответами заключается в том, что каждый раз добавляется новый индикатор активности, поэтому подпредставления начинают накапливаться. Вот полный пример, в котором используется только один UIActivityIndicator.

введите здесь описание изображения

Это весь код проекта выше:

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()
            })
        })
    }
}
person Suragch    schedule 08.07.2016

Вы можете написать быстрый 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()
    })
}
person Sameer Saif    schedule 26.04.2018
comment
Добро пожаловать в SO, пожалуйста, полностью отформатируйте исходный код и опишите его более подробно. - person cSteusloff; 26.04.2018

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

Если вы нажмете на другой viewController, пока анимация активна, а затем вернетесь назад, вы все равно увидите анимацию индикатора активности, поэтому вы должны сделать это

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

Мистер Пошчан, мой код работает. Но если вы хотите показать большое появление индикатора активности, вы можете его использовать....

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)
person Sameer Saif    schedule 30.04.2018