美文网首页
view层级关系的设计

view层级关系的设计

作者: 传说中的汽水枪 | 来源:发表于2019-06-10 10:44 被阅读0次

    开发App的时候,有的vc非常简单,有的vc就是非常复杂,我目前所在的项目中的VC就是非常复杂,前前后后有将近30多个view,在vc中view管理这些子view的时候就会导致vc极度的膨胀,将来业务扩展的时候,添加新的view的时候也有可能会添加的位置不对,导致view的管理混乱,因此有必要进行拆分。

    也就是说有如下的两个问题:

    1. view的子view太多,导致view代码量增大,
    2. 新的业务需要新的view会导致添加的顺序不对。

    借鉴了window的level概念,我们也初步设计了一个view的level概念。也就是说把这个复杂的view拆分几层,每个层级都有相关的子view。

    结构图如下:

    image.png

    刚开始设计的是每一个层级都是一个view,但是需要解决事件透传的问题(重写level view的hitTest方法),可以通过事件响应链能解决此问题。

    在实际实现的过程中突然想起,我每一层不一定是需要一个view来装各种子view,我可以使用对象,一个占位view和- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview; 来实现同样的效果并且还不用重写view的hitTest方法。

    具体的代码如下:
    VKBaseLevel.h:

    @interface VKBaseLevel : NSObject
    // 一个占位view,frame为zero
    @property (nonatomic, readonly) UIView *placeholderView;
    // 实际显示的view,不包括占位view
    @property (nonatomic, readonly) NSArray *subviews;
    // 此层级是否为空
    @property (nonatomic, readonly) BOOL empty;
    // 需要使用weak,要不然会出现循环引用了
    @property (nonatomic, readonly, weak) UIView *superview;
    // Need Override, 所有可能的view
    @property (nonatomic, readonly) NSArray *possibleSubviews;
    - (id)initWithSuperview:(UIView *)superview;
    - (void)addSubview:(UIView *)view;
    @end
    

    VKBaseLevel.m:

    
    #import "VKBaseLevel.h"
    @interface VKBaseLevel()
    @property (nonatomic, readwrite, strong) UIView *placeholderView;
    @property (nonatomic, readwrite, weak) UIView *superview;
    @end
    @implementation VKBaseLevel
    - (id)initWithSuperview:(UIView *)superview {
        if (self = [super init]) {
            self.placeholderView = [UIView new];
            self.superview = superview;
            [superview addSubview:self.placeholderView];
        }
        return self;
    }
    - (void)addSubview:(UIView *)view {
        [self.superview insertSubview:view belowSubview:self.placeholderView];
    }
    - (NSArray *)possibleSubviews {
        return [NSArray new];
    }
    - (NSArray *)subviews {
        NSMutableArray *mutAry = [NSMutableArray new];
        for (UIView *view in self.possibleSubviews) {
            if (view.superview != nil) {
                [mutAry addObject:view];
            }
        }
        return [mutAry copy];
    }
    - (BOOL)empty {
        return self.subviews.count == 0;
    }
    @end
    

    其中一个level的代码如下:

    @interface VKBGLevel()
    @property (nonatomic, strong) UILabel *pptLabel;
    @property (nonatomic, strong) UILabel *ppt2Label;
    @end
    @implementation VKBGLevel
    - (id)initWithSuperview:(UIView *)superview {
        if (self = [super initWithSuperview:superview]) {
            self.pptLabel = [UILabel new];
            self.pptLabel.text = @"我是背景图";
            self.pptLabel.textAlignment = NSTextAlignmentCenter;
            [self addSubview:self.pptLabel];
            
            self.ppt2Label = [UILabel new];
            self.ppt2Label.text = @"我是背景图2";
            self.ppt2Label.backgroundColor = [UIColor whiteColor];
            self.ppt2Label.textAlignment = NSTextAlignmentCenter;
            [self addSubview:self.ppt2Label];
            
            // 布局代码
        }
        return self;
    }
    
    - (NSArray *)possibleSubviews {
        NSMutableArray *ary = [NSMutableArray new];
        if (self.pptLabel) {
            [ary addObject:self.pptLabel];
        }
        return [ary copy];
    }
    @end
    

    最外层使用的:

    @interface VKRaptorView() <VKNormalLevelDelegate>
    @property (nonatomic, strong) VKBGLevel *bgLevel;
    @property (nonatomic, strong) VKVideoLevel *videoLevel;
    @property (nonatomic, strong) VKNormalLevel *normalLevel;
    @property (nonatomic, strong) VKGuideLevel *guideLevel;
    @property (nonatomic, strong) VKAnimationLevel *animationLevel;
    @end
    
    @implementation VKRaptorView
    
    - (id)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {
            self.bgLevel = [[VKBGLevel alloc] initWithSuperview:self];
            self.videoLevel = [[VKVideoLevel alloc] initWithSuperview:self];
            self.normalLevel = [[VKNormalLevel alloc] initWithSuperview:self];
           // 层级之间是通过delegate交互的
            self.normalLevel.delegate = self;
            self.animationLevel = [[VKAnimationLevel alloc] initWithSuperview:self];
            self.guideLevel = [[VKGuideLevel alloc] initWithSuperview:self];
        }
        return self;
    }
    
    #pragma mark - VKNormalLevelDelegate
    - (void)helpActionInNormalLevel:(VKNormalLevel *)bgLevel {
        [self.guideLevel showHelp];
    }
    @end
    

    重点是:每一层是一个对象,每个对象中含有一个默认的placeholderView,这个view相当于每层view的分割线。
    这样就可以很好的管理一个复杂的view,给vc减负,将来有新来的view,放到指定的层级即可。

    github:ViewLevel

    事件响应链来解决此问题

    直接上代码

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        NSArray *subviews = [self.subviews.reverseObjectEnumerator allObjects];
        for (UIView *view in subviews) {
            if (view.hidden || view.alpha < 0.1) {
                continue;
            }
            BOOL inSubView = CGRectContainsPoint(view.frame, point);
            if (inSubView) {
                NSLog(@"YES: %@", [self class]);
                // 千万不能是  return self;  return self 是让这个类来处理所有的事件
                return [super hitTest:point withEvent:event];
            } else {
                NSLog(@"NO: %@", [self class]);
            }
        }
        return nil;
    }
    

    相关文章

      网友评论

          本文标题:view层级关系的设计

          本文链接:https://www.haomeiwen.com/subject/ewpaxctx.html