修改第三方库最简单的是拖入工程直接修改。当然由于库间引用,导致拖入工程修改需要处理很多编译问题。指定版本后修改本地库,若别人使用时下载的库和自己的不一样。那如何不拖入工程,并且别人也能使用我们修改后的库呢?需要指定版本然后用分类。以带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