美文网首页
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