Show activity indicator in SDWebImage

2019-03-08 02:35发布

问题:

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

回答1:

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


回答2:

This is how you do it:

[imageView setIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[imageView setShowActivityIndicatorView:true];
[imageView sd_setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:@"defaultl_image"]];



回答3:

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


回答4:

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


回答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];
}];


回答6:

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.



回答7:

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

Swift 3:

imgView.setShowActivityIndicator(true)
imgView.setIndicatorStyle(.gray)
imgView.sd_setImage(with: URL(string: urlString), placeholderImage: UIImage(named: "placeholder"))


回答8:

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


回答9:

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



回答10:

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

imageView.setShowActivityIndicatorView(true)

imageView.setIndicatorStyle(.White)


回答11:

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


回答12:

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

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



回答13:

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.



回答14:

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.



回答15:

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