在自定义 UIView 中添加 GifHud
Add GifHud in custom UIView
我正在尝试在屏幕顶部的小视图中显示带有 gif 的 Activity 指示器。为此,我正在使用 class (GifHud):
//
// GiFHUD.m
// GiFHUD
//
// Created by Cem Olcay on 30/10/14.
// Copyright (c) 2014 Cem Olcay. All rights reserved.
//
#import "GiFHUD.h"
#import "AppDelegate.h"
#import <ImageIO/ImageIO.h>
#define Size 70
#define FadeDuration 0.3
#define GifSpeed 0.3
#define APPDELEGATE ((AppDelegate*)[[UIApplication sharedApplication] delegate])
#if __has_feature(objc_arc)
#define toCF (__bridge CFTypeRef)
#define fromCF (__bridge id)
#else
#define toCF (CFTypeRef)
#define fromCF (id)
#endif
#pragma mark - UIImage Animated GIF
@implementation UIImage (animatedGIF)
static int delayCentisecondsForImageAtIndex(CGImageSourceRef const source, size_t const i) {
int delayCentiseconds = 1;
CFDictionaryRef const properties = CGImageSourceCopyPropertiesAtIndex(source, i, NULL);
if (properties) {
CFDictionaryRef const gifProperties = CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
if (gifProperties) {
NSNumber *number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime);
if (number == NULL || [number doubleValue] == 0) {
number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime);
}
if ([number doubleValue] > 0) {
// Even though the GIF stores the delay as an integer number of centiseconds, ImageIO “helpfully” converts that to seconds for us.
delayCentiseconds = (int)lrint([number doubleValue] * 100);
}
}
CFRelease(properties);
}
return delayCentiseconds;
}
static void createImagesAndDelays(CGImageSourceRef source, size_t count, CGImageRef imagesOut[count], int delayCentisecondsOut[count]) {
for (size_t i = 0; i < count; ++i) {
imagesOut[i] = CGImageSourceCreateImageAtIndex(source, i, NULL);
delayCentisecondsOut[i] = delayCentisecondsForImageAtIndex(source, i);
}
}
static int sum(size_t const count, int const *const values) {
int theSum = 0;
for (size_t i = 0; i < count; ++i) {
theSum += values[i];
}
return theSum;
}
static int pairGCD(int a, int b) {
if (a < b)
return pairGCD(b, a);
while (true) {
int const r = a % b;
if (r == 0)
return b;
a = b;
b = r;
}
}
static int vectorGCD(size_t const count, int const *const values) {
int gcd = values[0];
for (size_t i = 1; i < count; ++i) {
// Note that after I process the first few elements of the vector, `gcd` will probably be smaller than any remaining element. By passing the smaller value as the second argument to `pairGCD`, I avoid making it swap the arguments.
gcd = pairGCD(values[i], gcd);
}
return gcd;
}
static NSArray *frameArray(size_t const count, CGImageRef const images[count], int const delayCentiseconds[count], int const totalDurationCentiseconds) {
int const gcd = vectorGCD(count, delayCentiseconds);
size_t const frameCount = totalDurationCentiseconds / gcd;
UIImage *frames[frameCount];
for (size_t i = 0, f = 0; i < count; ++i) {
UIImage *const frame = [UIImage imageWithCGImage:images[i]];
for (size_t j = delayCentiseconds[i] / gcd; j > 0; --j) {
frames[f++] = frame;
}
}
return [NSArray arrayWithObjects:frames count:frameCount];
}
static void releaseImages(size_t const count, CGImageRef const images[count]) {
for (size_t i = 0; i < count; ++i) {
CGImageRelease(images[i]);
}
}
static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) {
size_t const count = CGImageSourceGetCount(source);
CGImageRef images[count];
int delayCentiseconds[count]; // in centiseconds
createImagesAndDelays(source, count, images, delayCentiseconds);
int const totalDurationCentiseconds = sum(count, delayCentiseconds);
NSArray *const frames = frameArray(count, images, delayCentiseconds, totalDurationCentiseconds);
UIImage *const animation = [UIImage animatedImageWithImages:frames duration:(NSTimeInterval)totalDurationCentiseconds / 100.0];
releaseImages(count, images);
return animation;
}
static UIImage *animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceRef CF_RELEASES_ARGUMENT source) {
if (source) {
UIImage *const image = animatedImageWithAnimatedGIFImageSource(source);
CFRelease(source);
return image;
} else {
return nil;
}
}
+ (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)data {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF data, NULL));
}
+ (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)url {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL(toCF url, NULL));
}
@end
#pragma mark - GiFHUD Private
@interface GiFHUD ()
+ (instancetype)instance;
@property (nonatomic, strong) UIView *overlayView;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, assign) BOOL shown;
@end
#pragma mark - GiFHUD Implementation
@implementation GiFHUD
#pragma mark Lifecycle
static GiFHUD *instance;
+ (instancetype)instance {
if (!instance) {
instance = [[GiFHUD alloc] init];
}
return instance;
}
- (instancetype)init {
if ((self = [super initWithFrame:CGRectMake(0, 0, Size, Size)])) {
[self setAlpha:0];
[self setCenter:APPDELEGATE.window.center];
[self setClipsToBounds:NO];
// [self.layer setBackgroundColor:[[UIColor colorWithWhite:0 alpha:0.5] CGColor]];
// [self.layer setCornerRadius:10];
// [self.layer setMasksToBounds:YES];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectInset(self.bounds, 20, 20)];
[self addSubview:self.imageView];
[APPDELEGATE.window addSubview:self];
}
return self;
}
#pragma mark HUD
+ (void)showWithOverlay {
[self dismiss:^{
[APPDELEGATE.window addSubview:[[self instance] overlay]];
[self show];
}];
}
+ (void)show {
[self dismiss:^{
[APPDELEGATE.window bringSubviewToFront:[self instance]];
[[self instance] setShown:YES];
[[self instance] fadeIn];
}];
}
+ (void)dismiss {
if (![[self instance] shown])
return;
[[[self instance] overlay] removeFromSuperview];
[[self instance] fadeOut];
}
+ (void)dismiss:(void(^)(void))complated {
if (![[self instance] shown])
return complated ();
[[self instance] fadeOutComplate:^{
[[[self instance] overlay] removeFromSuperview];
complated ();
}];
}
#pragma mark Effects
- (void)fadeIn {
[self.imageView startAnimating];
[UIView animateWithDuration:FadeDuration animations:^{
[self setAlpha:1];
}];
}
- (void)fadeOut {
[UIView animateWithDuration:FadeDuration animations:^{
[self setAlpha:0];
} completion:^(BOOL finished) {
[self setShown:NO];
[self.imageView stopAnimating];
}];
}
- (void)fadeOutComplate:(void(^)(void))complated {
[UIView animateWithDuration:FadeDuration animations:^{
[self setAlpha:0];
} completion:^(BOOL finished) {
[self setShown:NO];
[self.imageView stopAnimating];
complated ();
}];
}
- (UIView *)overlay {
if (!self.overlayView) {
self.overlayView = [[UIView alloc] initWithFrame:APPDELEGATE.window.frame];
[self.overlayView setBackgroundColor:[UIColor blackColor]];
[self.overlayView setAlpha:0];
[UIView animateWithDuration:FadeDuration animations:^{
[self.overlayView setAlpha:0.3];
}];
}
return self.overlayView;
}
#pragma mark Gif
+ (void)setGifWithImages:(NSArray *)images {
[[[self instance] imageView] setAnimationImages:images];
[[[self instance] imageView] setAnimationDuration:GifSpeed];
}
+ (void)setGifWithImageName:(NSString *)imageName {
[[[self instance] imageView] stopAnimating];
[[[self instance] imageView] setImage:[UIImage animatedImageWithAnimatedGIFURL:[[NSBundle mainBundle] URLForResource:imageName withExtension:nil]]];
}
+ (void)setGifWithURL:(NSURL *)gifUrl {
[[[self instance] imageView] stopAnimating];
[[[self instance] imageView] setImage:[UIImage animatedImageWithAnimatedGIFURL:gifUrl]];
}
@end
在我的自定义视图中,我按如下方式显示 GifHud:
[GiFHUD setGifWithImageName:@"loader-fast-trp48.gif"];
[GiFHUD show];
然而,据我所知,这会在屏幕中央显示 GifHud。但我希望 Hud 出现在屏幕顶部的自定义视图上。我该怎么做?我试过了,但它给出了例外:
[self addSubview:[GiFHUD self]];
- (instancetype)init {
if ((self = [super initWithFrame:CGRectMake(0, 0, Size, Size)])) {
[self setAlpha:0];
[self setCenter:CGPointMake(self.view.window.center.x, Your_HEIGHT)];
[self setClipsToBounds:NO];
//[self.layer setBackgroundColor:[[UIColor colorWithWhite:0 alpha:0.5] CGColor]];
//[self.layer setCornerRadius:10];
//[self.layer setMasksToBounds:YES];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectInset(self.bounds, 20, 20)];
[self addSubview:self.imageView];
[APPDELEGATE.window addSubview:self];
}
return self;
}
尝试在我的回答中使用 [self setCenter:CGPointMake(self.view.window.center.x, Your_HEIGHT)];
调整中心大小。希望对您有所帮助。
我正在尝试在屏幕顶部的小视图中显示带有 gif 的 Activity 指示器。为此,我正在使用 class (GifHud):
//
// GiFHUD.m
// GiFHUD
//
// Created by Cem Olcay on 30/10/14.
// Copyright (c) 2014 Cem Olcay. All rights reserved.
//
#import "GiFHUD.h"
#import "AppDelegate.h"
#import <ImageIO/ImageIO.h>
#define Size 70
#define FadeDuration 0.3
#define GifSpeed 0.3
#define APPDELEGATE ((AppDelegate*)[[UIApplication sharedApplication] delegate])
#if __has_feature(objc_arc)
#define toCF (__bridge CFTypeRef)
#define fromCF (__bridge id)
#else
#define toCF (CFTypeRef)
#define fromCF (id)
#endif
#pragma mark - UIImage Animated GIF
@implementation UIImage (animatedGIF)
static int delayCentisecondsForImageAtIndex(CGImageSourceRef const source, size_t const i) {
int delayCentiseconds = 1;
CFDictionaryRef const properties = CGImageSourceCopyPropertiesAtIndex(source, i, NULL);
if (properties) {
CFDictionaryRef const gifProperties = CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
if (gifProperties) {
NSNumber *number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime);
if (number == NULL || [number doubleValue] == 0) {
number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime);
}
if ([number doubleValue] > 0) {
// Even though the GIF stores the delay as an integer number of centiseconds, ImageIO “helpfully” converts that to seconds for us.
delayCentiseconds = (int)lrint([number doubleValue] * 100);
}
}
CFRelease(properties);
}
return delayCentiseconds;
}
static void createImagesAndDelays(CGImageSourceRef source, size_t count, CGImageRef imagesOut[count], int delayCentisecondsOut[count]) {
for (size_t i = 0; i < count; ++i) {
imagesOut[i] = CGImageSourceCreateImageAtIndex(source, i, NULL);
delayCentisecondsOut[i] = delayCentisecondsForImageAtIndex(source, i);
}
}
static int sum(size_t const count, int const *const values) {
int theSum = 0;
for (size_t i = 0; i < count; ++i) {
theSum += values[i];
}
return theSum;
}
static int pairGCD(int a, int b) {
if (a < b)
return pairGCD(b, a);
while (true) {
int const r = a % b;
if (r == 0)
return b;
a = b;
b = r;
}
}
static int vectorGCD(size_t const count, int const *const values) {
int gcd = values[0];
for (size_t i = 1; i < count; ++i) {
// Note that after I process the first few elements of the vector, `gcd` will probably be smaller than any remaining element. By passing the smaller value as the second argument to `pairGCD`, I avoid making it swap the arguments.
gcd = pairGCD(values[i], gcd);
}
return gcd;
}
static NSArray *frameArray(size_t const count, CGImageRef const images[count], int const delayCentiseconds[count], int const totalDurationCentiseconds) {
int const gcd = vectorGCD(count, delayCentiseconds);
size_t const frameCount = totalDurationCentiseconds / gcd;
UIImage *frames[frameCount];
for (size_t i = 0, f = 0; i < count; ++i) {
UIImage *const frame = [UIImage imageWithCGImage:images[i]];
for (size_t j = delayCentiseconds[i] / gcd; j > 0; --j) {
frames[f++] = frame;
}
}
return [NSArray arrayWithObjects:frames count:frameCount];
}
static void releaseImages(size_t const count, CGImageRef const images[count]) {
for (size_t i = 0; i < count; ++i) {
CGImageRelease(images[i]);
}
}
static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) {
size_t const count = CGImageSourceGetCount(source);
CGImageRef images[count];
int delayCentiseconds[count]; // in centiseconds
createImagesAndDelays(source, count, images, delayCentiseconds);
int const totalDurationCentiseconds = sum(count, delayCentiseconds);
NSArray *const frames = frameArray(count, images, delayCentiseconds, totalDurationCentiseconds);
UIImage *const animation = [UIImage animatedImageWithImages:frames duration:(NSTimeInterval)totalDurationCentiseconds / 100.0];
releaseImages(count, images);
return animation;
}
static UIImage *animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceRef CF_RELEASES_ARGUMENT source) {
if (source) {
UIImage *const image = animatedImageWithAnimatedGIFImageSource(source);
CFRelease(source);
return image;
} else {
return nil;
}
}
+ (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)data {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF data, NULL));
}
+ (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)url {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL(toCF url, NULL));
}
@end
#pragma mark - GiFHUD Private
@interface GiFHUD ()
+ (instancetype)instance;
@property (nonatomic, strong) UIView *overlayView;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, assign) BOOL shown;
@end
#pragma mark - GiFHUD Implementation
@implementation GiFHUD
#pragma mark Lifecycle
static GiFHUD *instance;
+ (instancetype)instance {
if (!instance) {
instance = [[GiFHUD alloc] init];
}
return instance;
}
- (instancetype)init {
if ((self = [super initWithFrame:CGRectMake(0, 0, Size, Size)])) {
[self setAlpha:0];
[self setCenter:APPDELEGATE.window.center];
[self setClipsToBounds:NO];
// [self.layer setBackgroundColor:[[UIColor colorWithWhite:0 alpha:0.5] CGColor]];
// [self.layer setCornerRadius:10];
// [self.layer setMasksToBounds:YES];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectInset(self.bounds, 20, 20)];
[self addSubview:self.imageView];
[APPDELEGATE.window addSubview:self];
}
return self;
}
#pragma mark HUD
+ (void)showWithOverlay {
[self dismiss:^{
[APPDELEGATE.window addSubview:[[self instance] overlay]];
[self show];
}];
}
+ (void)show {
[self dismiss:^{
[APPDELEGATE.window bringSubviewToFront:[self instance]];
[[self instance] setShown:YES];
[[self instance] fadeIn];
}];
}
+ (void)dismiss {
if (![[self instance] shown])
return;
[[[self instance] overlay] removeFromSuperview];
[[self instance] fadeOut];
}
+ (void)dismiss:(void(^)(void))complated {
if (![[self instance] shown])
return complated ();
[[self instance] fadeOutComplate:^{
[[[self instance] overlay] removeFromSuperview];
complated ();
}];
}
#pragma mark Effects
- (void)fadeIn {
[self.imageView startAnimating];
[UIView animateWithDuration:FadeDuration animations:^{
[self setAlpha:1];
}];
}
- (void)fadeOut {
[UIView animateWithDuration:FadeDuration animations:^{
[self setAlpha:0];
} completion:^(BOOL finished) {
[self setShown:NO];
[self.imageView stopAnimating];
}];
}
- (void)fadeOutComplate:(void(^)(void))complated {
[UIView animateWithDuration:FadeDuration animations:^{
[self setAlpha:0];
} completion:^(BOOL finished) {
[self setShown:NO];
[self.imageView stopAnimating];
complated ();
}];
}
- (UIView *)overlay {
if (!self.overlayView) {
self.overlayView = [[UIView alloc] initWithFrame:APPDELEGATE.window.frame];
[self.overlayView setBackgroundColor:[UIColor blackColor]];
[self.overlayView setAlpha:0];
[UIView animateWithDuration:FadeDuration animations:^{
[self.overlayView setAlpha:0.3];
}];
}
return self.overlayView;
}
#pragma mark Gif
+ (void)setGifWithImages:(NSArray *)images {
[[[self instance] imageView] setAnimationImages:images];
[[[self instance] imageView] setAnimationDuration:GifSpeed];
}
+ (void)setGifWithImageName:(NSString *)imageName {
[[[self instance] imageView] stopAnimating];
[[[self instance] imageView] setImage:[UIImage animatedImageWithAnimatedGIFURL:[[NSBundle mainBundle] URLForResource:imageName withExtension:nil]]];
}
+ (void)setGifWithURL:(NSURL *)gifUrl {
[[[self instance] imageView] stopAnimating];
[[[self instance] imageView] setImage:[UIImage animatedImageWithAnimatedGIFURL:gifUrl]];
}
@end
在我的自定义视图中,我按如下方式显示 GifHud:
[GiFHUD setGifWithImageName:@"loader-fast-trp48.gif"];
[GiFHUD show];
然而,据我所知,这会在屏幕中央显示 GifHud。但我希望 Hud 出现在屏幕顶部的自定义视图上。我该怎么做?我试过了,但它给出了例外:
[self addSubview:[GiFHUD self]];
- (instancetype)init {
if ((self = [super initWithFrame:CGRectMake(0, 0, Size, Size)])) {
[self setAlpha:0];
[self setCenter:CGPointMake(self.view.window.center.x, Your_HEIGHT)];
[self setClipsToBounds:NO];
//[self.layer setBackgroundColor:[[UIColor colorWithWhite:0 alpha:0.5] CGColor]];
//[self.layer setCornerRadius:10];
//[self.layer setMasksToBounds:YES];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectInset(self.bounds, 20, 20)];
[self addSubview:self.imageView];
[APPDELEGATE.window addSubview:self];
}
return self;
}
尝试在我的回答中使用 [self setCenter:CGPointMake(self.view.window.center.x, Your_HEIGHT)];
调整中心大小。希望对您有所帮助。