修改第三方库最简单的是拖入工程直接修改。当然由于库间引用,导致拖入工程修改需要处理很多编译问题。指定版本后修改本地库,若别人使用时下载的库和自己的不一样。那如何不拖入工程,并且别人也能使用我们修改后的库呢?需要指定版本然后用分类。以带SceneDelegate的工程SVProgressHUD弹出框显示在左上角为例子进行解说。
一般的分类是指重载方法,不定义属性。其实分类也可以定义并使用属性。只是要想分类定义属性要自己实现setter方法和getter方法。
//给刷新控件设置 setter getter 方法 static char * HudView = "HudView";
设置getter方法:
- (UIVisualEffectView *)hudView { //如果属性值是非id类型,可以通过属性值先构造OC的id对象,再通过对象获取非id类型属性 return objc_getAssociatedObject(self, HudView); }
//运行时实现setter方法 - (void)setHudView:(UIVisualEffectView*)hudView{ objc_setAssociatedObject(self, HudView, hudView, OBJC_ASSOCIATION_RETAIN); }
具体完整例子如下:
指定SVProgressHUD版本号:pod 'SVProgressHUD', '2.2.5'
SVProgressHUD+DYExtension.h文件:
#import <UIKit/UIKit.h> #import "SVProgressHUD.h" @interface SVProgressHUD (DYExtension) @property (nonatomic, strong) UIVisualEffectView *hudView; - (void)positionHUD:(NSNotification*)notification; @end
SVProgressHUD+DYExtension.m文件:
#import "SVProgressHUD+DYExtension.h" #import "SVIndefiniteAnimatedView.h" #import "SVProgressAnimatedView.h" #import "SVRadialGradientLayer.h" #import<objc/runtime.h> //给刷新控件设置 setter getter 方法 static char * HudView = "HudView"; static const CGFloat SVProgressHUDParallaxDepthPoints = 10.0f; static const CGFloat SVProgressHUDUndefinedProgress = -1; static const CGFloat SVProgressHUDDefaultAnimationDuration = 0.15f; static const CGFloat SVProgressHUDVerticalSpacing = 12.0f; static const CGFloat SVProgressHUDHorizontalSpacing = 12.0f; static const CGFloat SVProgressHUDLabelSpacing = 8.0f; @implementation SVProgressHUD (DYExtension) - (UIVisualEffectView *)hudView { //如果属性值是非id类型,可以通过属性值先构造OC的id对象,再通过对象获取非id类型属性 return objc_getAssociatedObject(self, HudView); } //运行时实现setter方法 - (void)setHudView:(UIVisualEffectView*)hudView{ objc_setAssociatedObject(self, HudView, hudView, OBJC_ASSOCIATION_RETAIN); } - (void)positionHUD:(NSNotification*)notification { CGFloat keyboardHeight = 0.0f; double animationDuration = 0.0; #if !defined(SV_APP_EXTENSIONS) && TARGET_OS_IOS self.frame = [UIApplication sharedApplication].keyWindow.bounds; UIInterfaceOrientation orientation = UIApplication.sharedApplication.statusBarOrientation; #elif !defined(SV_APP_EXTENSIONS) && !TARGET_OS_IOS self.frame= [UIApplication sharedApplication].keyWindow.bounds; #else if (self.viewForExtension) { self.frame = self.viewForExtension.frame; } else { self.frame = UIScreen.mainScreen.bounds; } #if TARGET_OS_IOS UIInterfaceOrientation orientation = CGRectGetWidth(self.frame) > CGRectGetHeight(self.frame) ? UIInterfaceOrientationLandscapeLeft : UIInterfaceOrientationPortrait; #endif #endif #if TARGET_OS_IOS // Get keyboardHeight in regard to current state if(notification) { NSDictionary* keyboardInfo = [notification userInfo]; CGRect keyboardFrame = [keyboardInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; animationDuration = [keyboardInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; if(notification.name == UIKeyboardWillShowNotification || notification.name == UIKeyboardDidShowNotification) { keyboardHeight = CGRectGetWidth(keyboardFrame); if(UIInterfaceOrientationIsPortrait(orientation)) { keyboardHeight = CGRectGetHeight(keyboardFrame); } } } else { keyboardHeight = self.visibleKeyboardHeight; } #endif // Get the currently active frame of the display (depends on orientation) CGRect orientationFrame = self.bounds; #if !defined(SV_APP_EXTENSIONS) && TARGET_OS_IOS CGRect statusBarFrame = UIApplication.sharedApplication.statusBarFrame; #else CGRect statusBarFrame = CGRectZero; #endif #if TARGET_OS_IOS // Update the motion effects in regard to orientation [self updateMotionEffectForOrientation:orientation]; #else [self updateMotionEffectForXMotionEffectType:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis yMotionEffectType:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis]; #endif // Calculate available height for display CGFloat activeHeight = CGRectGetHeight(orientationFrame); if(keyboardHeight > 0) { activeHeight += CGRectGetHeight(statusBarFrame) * 2; } activeHeight -= keyboardHeight; CGFloat posX = CGRectGetMidX(orientationFrame); CGFloat posY = floorf(activeHeight*0.45f); CGFloat rotateAngle = 0.0; CGPoint newCenter = CGPointMake(posX, posY); if(notification) { // Animate update if notification was present [UIView animateWithDuration:animationDuration delay:0 options:(UIViewAnimationOptions) (UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState) animations:^{ [self moveToPoint:newCenter rotateAngle:rotateAngle]; [[self getHudView] setNeedsDisplay]; } completion:nil]; } else { [self moveToPoint:newCenter rotateAngle:rotateAngle]; } } - (void)moveToPoint:(CGPoint)newCenter rotateAngle:(CGFloat)angle { [self getHudView].transform = CGAffineTransformMakeRotation(angle); if (self.containerView) { [self getHudView].center = CGPointMake(self.containerView.center.x + self.offsetFromCenter.horizontal, self.containerView.center.y + self.offsetFromCenter.vertical); } else { [self getHudView].center = CGPointMake(newCenter.x + self.offsetFromCenter.horizontal, newCenter.y + self.offsetFromCenter.vertical); } } #if TARGET_OS_IOS - (void)updateMotionEffectForOrientation:(UIInterfaceOrientation)orientation { UIInterpolatingMotionEffectType xMotionEffectType = UIInterfaceOrientationIsPortrait(orientation) ? UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis : UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis; UIInterpolatingMotionEffectType yMotionEffectType = UIInterfaceOrientationIsPortrait(orientation) ? UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis : UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis; [self updateMotionEffectForXMotionEffectType:xMotionEffectType yMotionEffectType:yMotionEffectType]; } #endif - (void)updateMotionEffectForXMotionEffectType:(UIInterpolatingMotionEffectType)xMotionEffectType yMotionEffectType:(UIInterpolatingMotionEffectType)yMotionEffectType { UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:xMotionEffectType]; effectX.minimumRelativeValue = @(-SVProgressHUDParallaxDepthPoints); effectX.maximumRelativeValue = @(SVProgressHUDParallaxDepthPoints); UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:yMotionEffectType]; effectY.minimumRelativeValue = @(-SVProgressHUDParallaxDepthPoints); effectY.maximumRelativeValue = @(SVProgressHUDParallaxDepthPoints); UIMotionEffectGroup *effectGroup = [UIMotionEffectGroup new]; effectGroup.motionEffects = @[effectX, effectY]; // Clear old motion effect, then add new motion effects [self getHudView].motionEffects = @[]; [[self getHudView] addMotionEffect:effectGroup]; } - (UIVisualEffectView*)getHudView { if(!self.hudView) { self.hudView = [UIVisualEffectView new]; self.hudView.layer.masksToBounds = YES; self.hudView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin; } if(!self.hudView.superview) { [self addSubview:self.hudView]; } // Update styling self.hudView.layer.cornerRadius = self.cornerRadius; return self.hudView; } - (CGFloat)visibleKeyboardHeight { #if !defined(SV_APP_EXTENSIONS) UIWindow *keyboardWindow = nil; for (UIWindow *testWindow in UIApplication.sharedApplication.windows) { if(![testWindow.class isEqual:UIWindow.class]) { keyboardWindow = testWindow; break; } } for (__strong UIView *possibleKeyboard in keyboardWindow.subviews) { NSString *viewName = NSStringFromClass(possibleKeyboard.class); if([viewName hasPrefix:@"UI"]){ if([viewName hasSuffix:@"PeripheralHostView"] || [viewName hasSuffix:@"Keyboard"]){ return CGRectGetHeight(possibleKeyboard.bounds); } else if ([viewName hasSuffix:@"InputSetContainerView"]){ for (__strong UIView *possibleKeyboardSubview in possibleKeyboard.subviews) { viewName = NSStringFromClass(possibleKeyboardSubview.class); if([viewName hasPrefix:@"UI"] && [viewName hasSuffix:@"InputSetHostView"]) { CGRect convertedRect = [possibleKeyboard convertRect:possibleKeyboardSubview.frame toView:self]; CGRect intersectedRect = CGRectIntersection(convertedRect, self.bounds); if (!CGRectIsNull(intersectedRect)) { return CGRectGetHeight(intersectedRect); } } } } } } #endif return 0; } @end