iOS runtime 應用場景

class_addMethod應用場景

如上圖,右邊彈出的一個毛玻璃視圖,點擊非玻璃區,毛玻璃頁面從右邊消失。這個是分享頁面,其他的還有好多頁面,比如設置,列表。所有右邊彈出的view大小都一樣。

可以寫一個公用的背景,在那個背景上做進入和退出的動作。這裏就要用到 runtimeclass_addMethod了。

直接上代碼:

NS_ASSUME_NONNULL_BEGIN

@protocol LiveBroadsideViewProtocol <NSObject>

///從右邊彈出的view 有默認的實現
@optional
- (void)moveIn;
- (void)moveOut:(dispatch_block_t)completeBlock;
@end

///全屏側邊彈出view
@interface PTVLiveBroadsideView : UIView

///顯示View
- (void)showView:(id<LiveBroadsideViewProtocol> )view;

@end

NS_ASSUME_NONNULL_END

實現部分

#import "PTVLiveBroadsideView.h"
///通用頭文件
#import "PTVMacro.h"

///runtime
#import <objc/runtime.h>

///從右邊彈出的view添加默認的實現
void moveIn(id self, SEL _cmd) {
    if (![self isKindOfClass:[UIView class]]) {
        return;
    }
    
    UIView *view = self;
    
    CGRect frame = CGRectMake(SCREEN_WIDTH, 0, 350, SCREEN_HEIGHT);
    view.frame = frame;
    [UIView animateWithDuration:0.25
                     animations:^{
                         CGRect frame1 = CGRectMake(SCREEN_WIDTH - 350, 0, 350, SCREEN_HEIGHT);
                         view.frame = frame1;
                     } completion:^(BOOL finished) {
                         
                     }];
}

///默認的MoveOut 實現
void moveOut(UIView *self, SEL _cmd, dispatch_block_t completeBlock) {
    [UIView animateWithDuration:0.25
                     animations:^{
                         CGRect frame1 = CGRectMake(SCREEN_WIDTH, 0, 350, SCREEN_HEIGHT);
                         self.frame = frame1;
                     } completion:^(BOOL finished) {
                         [self removeFromSuperview];
                         if (completeBlock) {
                             completeBlock();
                         }
                     }];
}


@interface PTVLiveBroadsideView()

///當前顯示的子View
@property (nonatomic, weak) UIView *currentView;

@end

@implementation PTVLiveBroadsideView

- (void)showView:(id<LiveBroadsideViewProtocol>)view {
    [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [(id<LiveBroadsideViewProtocol>)obj moveOut:^{
            
        }];
    }];
    
    UIView *_v = (UIView *)view;
    if (![_v isKindOfClass:[UIView class]]) return;
    
    
    if (![view respondsToSelector:@selector(moveIn)]) {
        BOOL sucess = class_addMethod([view class], @selector(moveIn), (IMP)moveIn, "i@:@");
        if (!sucess) {
            return;
        }
    }
    
    if (_v.superview != self) {
        [self addSubview:_v];
    }
    
    
    [view moveIn];
    
    _currentView = _v;
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    [super touchesEnded:touches withEvent:event];
    
    UITouch *touch = touches.anyObject;
    CGPoint point = [touch locationInView:self];
    if (CGRectContainsPoint(_currentView.frame, point)) return;
    
    if (![_currentView respondsToSelector:@selector(moveOut:)]) {
        BOOL sucess = class_addMethod([_currentView class], @selector(moveOut:), (IMP)moveOut, "i@:@");
        if (!sucess) {
            [_currentView removeFromSuperview];
            [self removeFromSuperview];
            return;
        }
    }
    
    WeakSelf;
    [(id<LiveBroadsideViewProtocol>)_currentView moveOut:^{
        [weakSelf removeFromSuperview];
    }];
    
}

@end

動態添加方法思路是看看新加入的view 有沒有實現 moveIn 或moveOut 如果沒實現,就動態添加一下:

if (![_currentView respondsToSelector:@selector(moveOut:)]) {
        BOOL sucess = class_addMethod([_currentView class], @selector(moveOut:), (IMP)moveOut, "i@:@");

使用的時候,如下:

    if (!_slideView) {
        PTVLiveBroadsideView *slideView = [PTVLiveBroadsideView new];
        slideView.backgroundColor = [UIColor clearColor];
        _slideView = slideView;
    }
   
    [targetController.view addSubview:_slideView];
    _slideView.frame = targetController.view.bounds;
    
//    PTVCommonShareView *sv = [PTVCommonShareView new];
//    PTVDormancyView *sv = [[PTVDormancyView alloc] initWithViewModel:[PTVDornacyViewModel new]];
    PTVVideoQualityView *sv = [[PTVVideoQualityView alloc] initWithViewModel:[PTVVideoQualityViewModel new]];
//    PTVBarrageOptionView *sv = [[PTVBarrageOptionView alloc] initWithViewModel:[PTVBarrageViewModel new]];
    [_slideView showView:(id<LiveBroadsideViewProtocol>)sv];

要彈出的view都不用實現moveInmoveOut 方法,在 showView方法裏已經動態添加過了。所以在 調用的使用纔會強制轉化 騙一下編譯器

(id<LiveBroadsideViewProtocol>)sv

當然,如果大小不一樣,可以擴展LiveBroadsideViewProtocol 協議。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章