0

I've created custom activity indicator built from three dots and it is not working. It has to work the following way:

nothing appears, one dot appears, two dots appear, three dots appear, nothing appears…

Each dot is a simple UIView with round corners and I have thread which has to show dots in a sequence described (tried timer also). The problem is that after first dot appears, nothing changes until activity indicator dismissed.

LoadingIndicator.h

#import <Foundation/Foundation.h>

@interface LoadingIndicator : NSObject
{
    UIView *loadingIndicator;
     UILabel *loadingLabel;
     UIView *dot1;
     UIView *dot2;
     UIView *dot3;
}

@property (nonatomic, retain) UIView *loadingIndicator;
@property (nonatomic, retain) UILabel *loadingLabel;
@property (nonatomic, retain) UIView *dot1;
@property (nonatomic, retain) UIView *dot2;
@property (nonatomic, retain) UIView *dot3;

 + (LoadingIndicator*)getInstance;

- (UIView*)getLoadingIndicator:(BOOL)withLoadingLabel at:(CGPoint)at;
- (void)removeLoadingIndicator;

@end

@interface LoadingIndicator (Private)

- (id)init;
- (UILabel*)getLoadingLabel;
- (void)startWorking;

@end

LoadingIndicator.m

#import "LoadingIndicator.h"
#import "Utils.h"
#import <QuartzCore/QuartzCore.h>

#define LOADING_INDICATOR_WIDTH 100
#define LOADING_INDICATOR_HEIGHT 50

@implementation LoadingIndicator

@synthesize loadingIndicator;
@synthesize loadingLabel;
@synthesize dot1;
@synthesize dot2;
@synthesize dot3;


static LoadingIndicator *instance;

int numOfDots = 0;
int dotSize = 15;
int effectiveHeight;

+ (LoadingIndicator*)getInstance
{
    if (instance == nil)
        @synchronized(self)
    {
        if (instance == nil)
            instance = [[self alloc ]init];
    }

    return instance;
}

- (UIView*)getLoadingIndicator:(BOOL)withLoadingLabel at:(CGPoint)at
{
    [self removeLoadingIndicator];

    loadingIndicator = [[UIView alloc] init];
    self.loadingIndicator.backgroundColor = RGBA(0, 0, 0, 0.5);
    self.loadingIndicator.frame = CGRectMake(at.x - LOADING_INDICATOR_WIDTH / 2,
                                            at.y - LOADING_INDICATOR_HEIGHT / 2,
                                            LOADING_INDICATOR_WIDTH,
                                            LOADING_INDICATOR_HEIGHT);


    [self.loadingIndicator.layer setCornerRadius:8.0];

    if (withLoadingLabel == YES)
        [self.loadingIndicator addSubview:[self getLoadingLabel]];

    if (loadingLabel)
        effectiveHeight = (self.loadingIndicator.frame.size.height - (loadingLabel.frame.origin.y + loadingLabel.frame.size.height));
    else
        effectiveHeight = self.loadingIndicator.frame.size.height;

    int y = self.loadingIndicator.frame.size.height - effectiveHeight / 2 - dotSize / 2;
    int x;



    x = self.loadingIndicator.frame.size.width / 3 / 2 - dotSize / 2;
    dot1.frame = CGRectMake(x, y, dotSize, dotSize);

    x = self.loadingIndicator.frame.size.width / 2 - dotSize / 2;
    dot2.frame = CGRectMake(x, y, dotSize, dotSize);

    x = self.loadingIndicator.frame.size.width / 2 + self.loadingIndicator.frame.size.width / 3 - dotSize / 2;
    dot3.frame = CGRectMake(x, y, dotSize, dotSize);


    //[self startWorking];
    [NSThread detachNewThreadSelector:@selector(startWorking) toTarget:self withObject:nil];


    return self.loadingIndicator;
}

- (void)removeLoadingIndicator
{
    if (self.loadingIndicator)
    {
        [self.loadingIndicator removeFromSuperview];
        self.loadingIndicator = nil;
        loadingLabel = nil;
    }
}
@end

@implementation LoadingIndicator (Private)

-(id)init
{
    if (self = [super init])
    {
        UIColor *dotsColor = RGB(67, 173, 72);
        dot1 = [[UIView alloc] init];
        dot1.backgroundColor = dotsColor;
        [dot1.layer setCornerRadius:8.0];


        dot2 = [[UIView alloc] init];
        dot2.backgroundColor = dotsColor;
        [dot2.layer setCornerRadius:8.0];

        dot3 = [[UIView alloc] init];
        dot3.backgroundColor = dotsColor;
        [dot3.layer setCornerRadius:8.0];
    }

    self.loadingIndicator = nil;

    return self;
}

- (UILabel*)getLoadingLabel
{
    UILabel *label = [[UILabel alloc] init];
    label.frame = CGRectMake(0,
                            5,
                            LOADING_INDICATOR_WIDTH,
                            15);
    label.backgroundColor = [UIColor clearColor];
    label.text = NSLocalizedString(@"LOADING", @"The data is currently loading (in capital letters)");
    label.textAlignment = NSTextAlignmentCenter;
    label.textColor = [UIColor whiteColor];
    label.font = [UIFont systemFontOfSize:13];

    loadingLabel = label;
    return label;
}

- (void)startWorking
{
    NSLog(@"%@\nWorker thread started.",DEBUG_PLACE);

    while (self.loadingIndicator)
    {
        //[self performSelectorOnMainThread:@selector(updateView) withObject:nil waitUntilDone:NO modes:nil];
        [self updateView];
        [NSThread sleepForTimeInterval:1];
    }

    numOfDots = 0;
}

- (void)updateView
{
    NSLog(@"%@",DEBUG_PLACE);


    if (self.loadingIndicator)
    {
        switch (numOfDots) {
            case 0:
                [self.loadingIndicator addSubview:dot1];
                break;
            case 1:
                [self.loadingIndicator addSubview:dot2];
                break;
            case 2:
                [self.loadingIndicator addSubview:dot3];
                break;
            default:
                [dot1 removeFromSuperview];
                [dot2 removeFromSuperview];
                [dot3 removeFromSuperview];
                break;
        }


        numOfDots = (numOfDots + 1) % 4;

    }
    else
    {
        numOfDots = 0;
        NSLog(@"%@\nWorker thread ended.",DEBUG_PLACE);
    }
}

@end
Misha
  • 5,260
  • 6
  • 35
  • 63
  • Mike, you should have look [here](http://stackoverflow.com/questions/6010237/creating-a-custom-uiactivityindicatorview), that may help you. – swiftBoy Nov 19 '13 at 07:21

1 Answers1

1

You can not update UI in a background thread. Modify your startWorking method like this:

while (self.loadingIndicator)
{
    //[self performSelectorOnMainThread:@selector(updateView) withObject:nil waitUntilDone:NO modes:nil];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateView];
    });
    [NSThread sleepForTimeInterval:1];
}
zaczh
  • 76
  • 1
  • 4