31

I'm using SDWebView image and i want to show an Activity Indicator as placeholder, while fetching the image from remote.

I tried Malek's answer here How to show an activity indicator in SDWebImage, but it seems that

UIImage *cachedImage = [manager imageWithURL:url];

is deprecated.

Is there anyone using this library that could tell me how can i insert an Activity Indicator while loading the image?

EDIT

Following the indications of Michael Frederick, i ended up with this code and everything's working fine.

UIActivityIndicatorView *activityIndicator = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease];
activityIndicator.hidesWhenStopped = YES;
activityIndicator.hidden = NO;
[activityIndicator startAnimating];
activityIndicator.center = CGPointMake(self.tipImage.frame.size.width /2, self.tipImage.frame.size.height/2);
[imageView setImageWithURL:[NSURL URLWithString:imageString]
          placeholderImage:nil options:SDWebImageProgressiveDownload
                   success:^(UIImage *image) { [activityIndicator stopAnimating];[activityIndicator removeFromSuperview]; }
                   failure:^(NSError *error) {  [activityIndicator stopAnimating];[activityIndicator removeFromSuperview]; }];

[imageView addSubview:activityIndicator];
Community
  • 1
  • 1
Phillip
  • 4,276
  • 7
  • 42
  • 74

18 Answers18

47

This fork has support for this functionality. Take a look at the diff.

But, in general, you can do it rather easily without using that fork:

__block UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:activityStyle];
activityIndicator.center = imageView.center;
activityIndicator.hidesWhenStopped = YES;
[imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
               placeholderImage:[UIImage imageNamed:@"placeholder.png"]
                        success:^(UIImage *image) { [activityIndicator removeFromSuperview]; }
                        failure:^(NSError *error) { [activityIndicator removeFromSuperview]; }];

[imageView addSubview:activityIndicator];
[activityIndicator startAnimating];
Michael Frederick
  • 16,664
  • 3
  • 43
  • 58
  • Thanks, i already checked them out, but something wasn't clear: should i use it WITH or WITHOUT the placeholder? Because that wasn't working! Where should that snippet go into? – Phillip Jul 01 '12 at 18:45
  • It might work with the placeholder if you add the activityIndicator after you do 'setImageWithURL'. The snippet should go wherever you would normally set the imageView's image. – Michael Frederick Jul 01 '12 at 19:05
  • 3
    Unfortunately it's not working. It loads the placeholder etc but not the activityIndicator – Phillip Jul 01 '12 at 19:12
  • For comments above mentioning this solution is not working: You need to add this line after your addSubview: `[activityIndicator startAnimating];` – Allan Jiang Oct 11 '14 at 23:50
  • When should we stop animating? It is working but also it is not stopping after the image is loaded. – Reaper Dec 19 '14 at 09:18
22

This is how you do it:

[imageView setIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[imageView setShowActivityIndicatorView:true];
[imageView sd_setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:@"defaultl_image"]];
Zaldy Bughaw
  • 797
  • 8
  • 16
  • 1
    I confirm this is the current best solution, since the main repository added finally the activity indicator feature in this commit : https://github.com/rs/SDWebImage/commit/c68d585e4957175402c521c52fc72fc932fec86d – AmineG Oct 08 '15 at 14:52
  • @SourabhSharma This not best coz you need to write 3 lines of code for the same functionality. Which also not a good practice. – Deepak Chaudhary May 05 '17 at 19:04
  • @DeepakChaudhary Ok, then what is the best way to show indicator? – Sourabh Sharma May 06 '17 at 04:29
  • @SourabhSharma Create an extension of imageView or override init method of imageview then use these two lines. By this, you have to write these only once for the entire app. :) – Deepak Chaudhary May 06 '17 at 18:45
17

That's my solution. In that file : UIImageView+WebCache.m

Find that method and change like that:

- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder
{
    UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleGray)];
    [activity startAnimating];
    [activity setFrame:CGRectMake(self.frame.origin.x - 20, self.frame.origin.y - 10, self.frame.size.width, self.frame.size.height)];
    [self addSubview:activity];

    //[self setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];

    [self setImageWithURL:url
         placeholderImage:placeholder
                  options:0
                completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType)
     {
             [activity removeFromSuperview];
     }];
}
Can Ürek
  • 641
  • 12
  • 24
15

Last solution

You can download UIActivityIndicator-for-SDWebImage, which is easiest way to add a UIActivityView to your SDWebImage view. Using CocoaPods, just add this line to your podfile:

pod 'UIActivityIndicator-for-SDWebImage'

You can use one of these lines depending on your preferences:

- (void)setImageWithURL:(NSURL *)url usingActivityIndicatorStyle:(UIActivityIndicatorViewStyle)activityStyle;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder usingActivityIndicatorStyle:(UIActivityIndicatorViewStyle)activityStyle;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options usingActivityIndicatorStyle:(UIActivityIndicatorViewStyle)activityStyle;
- (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock usingActivityIndicatorStyle:(UIActivityIndicatorViewStyle)activityStyle;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock usingActivityIndicatorStyle:(UIActivityIndicatorViewStyle)activityStyle;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock usingActivityIndicatorStyle:(UIActivityIndicatorViewStyle)activityStyle;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock usingActivityIndicatorStyle:(UIActivityIndicatorViewStyle)activityStyle;

Example of Use

Just import

#import <UIActivityIndicator-for-SDWebImage/UIImageView+UIActivityIndicatorForSDWebImage.h>

and use this code

[imageView setImageWithURL:[NSURL URLWithString:@"https://media.licdn.com/mpr/mpr/wc_200_200/p/1/005/07f/0a3/30cb8dd.jpg"] placeholderImage:[UIImage imageNamed:@"myImage.jpg"] usingActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
E-Riddie
  • 14,660
  • 7
  • 52
  • 74
7

SDWebImage has a built in Acitvity Indicator that works perfectly. Try this:

Updates: SWIFT 5 SDWebImage 5.x.x

        imgView.sd_imageIndicator = SDWebImageActivityIndicator.gray
        imgView.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder"))

Swift 3:

imgView.setShowActivityIndicator(true)
imgView.setIndicatorStyle(.gray)
imgView.sd_setImage(with: URL(string: urlString), placeholderImage: UIImage(named: "placeholder"))
Ankit Kumar Gupta
  • 3,994
  • 4
  • 31
  • 54
6

For Swift 5.0 and SDWebImage 5.0 :

Replace

imageView.sd_setShowActivityIndicatorView(true)
imageView.sd_setIndicatorStyle(.gray)

By

imageView.sd_imageIndicator = SDWebImageActivityIndicator.gray
BSK-Team
  • 1,750
  • 1
  • 19
  • 37
5

The above code is slightly wrong. The line 'activityIndicator.center = imageView.center' does not give you the correct coordinates to center the progress view. For me, it was showing the indicator below the cell.

Note - I am using the latest version of the SDWebImage code so the method is slightly different. I am also using a UIButton for the imageView

Try this:

NSURL *url = [NSURL URLWithString:@"www.someimageurl.com"];
__block UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.frame = cell.imageView.bounds;
[cell.imageView addSubview:activityIndicator];
[activityIndicator startAnimating];
[cell.imageView setImageWithURL:url forState:UIControlStateNormal completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
    [activityIndicator removeFromSuperview];
}];
JimmyJammed
  • 9,598
  • 19
  • 79
  • 146
  • I've been using the same code as you and the activityIndicator will show for a second then immediatley disappear. I've commented the line that says remove it... Nothing I try will make it stay. It just shows up then promptly disappears. :( – Hackmodford Mar 21 '13 at 14:17
5

I believe with the latest version of sdwebimage this is a better method.

[self.customImageView setImageWithURL:imageURL
                             placeholderImage:nil
                                      options:nil
                                     progress:^(NSUInteger receivedSize, long long expectedSize) { [self.activityIndicator startAnimating]; }
                                    completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) { [self.activityIndicator stopAnimating]; }];

Note: If you don't have a property setup obviously self.activityindicator won't work.

I would use Michael Frederick's example to create the activityindicator instead.

Hackmodford
  • 3,901
  • 4
  • 35
  • 78
3

Same code as above in SWIFT 4:

let activityIndicator = UIActivityIndicatorView.init(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
    activityIndicator.center = addImage.center
    activityIndicator.hidesWhenStopped = true

    addImage.sd_setImage(with: URL(string: feed.image), completed: { (image: UIImage?, error: Error?, cacheType: SDImageCacheType, imageURL: URL?) in
        activityIndicator.removeFromSuperview()
    })

    addImage.addSubview(activityIndicator)
    activityIndicator.startAnimating()
Ignacio Oroná
  • 4,371
  • 1
  • 19
  • 25
3

SdWebImage 5.0

YOUR_IMAGEVIEW.sd_imageIndicator = SDWebImageActivityIndicator.gray
Ahmadreza
  • 6,950
  • 5
  • 50
  • 69
2
[cell.dreamImageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@",dream.thumbnail]] placeholderImage:[UIImage imageNamed:@"dream_bg_2.png"] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {

    CGFloat domandeFloat = [[NSNumber numberWithInt: receivedSize] floatValue];
    CGFloat corretteFloat = [[NSNumber numberWithInt: expectedSize] floatValue];


    float currentProgress = domandeFloat/corretteFloat;

     NSLog(@"progress %f",currentProgress);
    cell.progressView.progress = currentProgress;

    //[self.dreamsTableView reloadData];


} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {

    cell.progressView.hidden = YES;
}];
Waseem Sarwar
  • 2,645
  • 1
  • 21
  • 18
2

Solution updated for Swift 2.0 for using SDWebImage to load image URL

imageView.setShowActivityIndicatorView(true)

imageView.setIndicatorStyle(.White)
Sourabh Sharma
  • 8,222
  • 5
  • 68
  • 78
1

Based on Can Ürek's answer you might wanna create a category to make it easier to use across multiple applications and without modify SDWebImage framework.

Header file:

#import <UIKit/UIKit.h>

#import <SDWebImage/UIImageView+WebCache.h>

@interface UIImageView (WebCacheWithActivityIndicator)

- (void)setImageShowingActivityIndicatorWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock;

@end

Implementation file:

#import "UIImageView+WebCacheWithActivityIndicator.h"

@implementation UIImageView (WebCacheWithActivityIndicator)

- (void)setImageShowingActivityIndicatorWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock
{
    UIActivityIndicatorView* activityIndication = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];

    [activityIndication setFrame:CGRectMake((self.frame.size.width - activityIndication.frame.size.width) / 2 , (self.frame.size.height - activityIndication.frame.size.height) / 2 , activityIndication.frame.size.width , activityIndication.frame.size.width)];
    [self addSubview:activityIndication];

    [activityIndication startAnimating];

    [self setImageWithURL:url completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {

        if(completedBlock)
        {
            completedBlock(image,error,cacheType);
        }

        [activityIndication stopAnimating];
        [activityIndication removeFromSuperview];
    }];
}
@end

Hope it helps you out guys

Cheers

Paulo Miguel Almeida
  • 2,114
  • 31
  • 36
0

Another solution is to use an animated image as the placeholder image by using:

[UIImage animatedImageNamed:@"animated_placeholder" duration:1]

Joseph Toronto
  • 1,882
  • 1
  • 15
  • 29
0

With updated library (Resolved Crash on iOS 8), we have below method -

- (void)sd_setImageWithURL:(NSURL *)url 
{
    [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}

As we can see the option to add progress block and completed block, we can simply add Activity indicator in progress block and remove in completion block.

Customized method to add Activity Indicator here -

- (void)sd_setImageWithURL:(NSURL *)url {

    [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {
        UIActivityIndicatorView *activity = nil;
        activity = (UIActivityIndicatorView *)[self viewWithTag:100000];
        if (!activity) {
            activity = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
            [activity setTag:100000];
            [activity setHidesWhenStopped:YES];
            [activity setCenter:CGPointMake(self.frame.size.width/2.0f,self.frame.size.height/2.0f)];
            [self addSubview:activity];
        }
        else {
            [activity setCenter:CGPointMake(self.frame.size.width/2.0f,self.frame.size.height/2.0f)];
        }
        [activity startAnimating];

    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
        UIActivityIndicatorView *activity = (UIActivityIndicatorView *)[self viewWithTag:100000];
        if ([activity isKindOfClass:[UIActivityIndicatorView class]]) {
            [activity stopAnimating];
        }
    }];
}

This will add UIActivityIndicatorView to the center of UIImageView when image downloading in progress and remove on completion.

Abhishek
  • 995
  • 13
  • 28
0

My list is quite lag when the user scrolling the list up and down repeatedly. I found out that the activityindicator had been added infinitely when the cellForItemAtIndexPath is being repeatedly called.

To solve this, add a tag at your activityindicator:

activityIndicator.tag = 9999;

Before the UIActivityIndicator is being created, add these lines to remove the previous activityindicator before adding the new one:

UIView* toDeleteLoader = [cell viewWithTag:9999];
if(toDeleteLoader != nil){
    [toDeleteLoader removeFromSuperview];
}

Note: tag content can be any numbers that it won't be used in your cell.

0

Best solution that worked for me is below. It is beautiful and encouraging to show progress indicator when image is downloading. I used UICircularSlider as rounded progress view. You can also try it.

    [_imgPost sd_setImageWithURL:urlPost placeholderImage:zeroImage options:SDWebImageContinueInBackground progress:^(NSInteger receivedSize, NSInteger expectedSize)
    {
        CGFloat domandeFloat = [[NSNumber numberWithInteger: receivedSize] floatValue];
        CGFloat corretteFloat = [[NSNumber numberWithInteger: expectedSize] floatValue];


        float currentProgress = (domandeFloat/corretteFloat)*100;

        NSLog(@"progress %.f%%",currentProgress);
        DBG(@"%li, %li", receivedSize, expectedSize);
        [_progress setValue:currentProgress];
    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {

        [_progress setHidden:YES];
    }];

Here _progress is an instance of UICircularSlider

Vaibhav Saran
  • 12,848
  • 3
  • 65
  • 75
0

SDWebImage 5.0 has support of displaying activity indicator using SDWebImageActivityIndicator class.

let imageView = UIImageView()
imageView.sd_imageIndicator = SDWebImageActivityIndicator.gray
RGhate
  • 63
  • 1
  • 6