美文网首页
DZNEmptyDataSet的理解笔记

DZNEmptyDataSet的理解笔记

作者: 起个名字真难啊2015 | 来源:发表于2017-02-13 23:58 被阅读551次
    对第三方框架DZNEmptyDataSet中的UIScrollView+EmptyDataSet的解读

    一, UIScrollView+EmptyDataSet.h文件提供了DZNEmptyDataSetSourceDZNEmptyDataSetDelegate协议中大量的方法,还提供了三个属性和一个公有的方法:
    emptyDataSetSource;emptyDataSetDelegate ;emptyDataSetVisible;-(void)reloadEmptyDataSet(只重新加载empty的数据)
    

    二,UIScrollView+EmptyDataSet.m文件中提供了三个类的实现

    1, UIView+DZNConstraintBasedLayoutExtensions
    只提供了以下一个方法; 用来实现约束

    - (NSLayoutConstraint *)equallyRelatedConstraintWithView:(UIView *)view attribute:(NSLayoutAttribute)attribute
    {
        return [NSLayoutConstraint constraintWithItem:view
                                            attribute:attribute
                                            relatedBy:NSLayoutRelationEqual
                                               toItem:self
                                            attribute:attribute
                                           multiplier:1.0
                                             constant:0.0];
    }
    

    2,DZNWeakObjectContainer : NSObject只提供了一个方法和属性;如下

    @interface DZNWeakObjectContainer : NSObject
    
    @property (nonatomic, readonly, weak) id weakObject;
    
    - (instancetype)initWithWeakObject:(id)object;
    
    @end
    
    @implementation DZNWeakObjectContainer
    
    - (instancetype)initWithWeakObject:(id)object
    {
        self = [super init];
        if (self) {
            _weakObject = object;
        }
        return self;
    }
    
    @end
    

    3,DZNEmptyDataSetView : UIView

    @interface DZNEmptyDataSetView : UIView
    
    @property (nonatomic, readonly) UIView *contentView;
    @property (nonatomic, readonly) UILabel *titleLabel;
    @property (nonatomic, readonly) UILabel *detailLabel;
    @property (nonatomic, readonly) UIImageView *imageView;
    @property (nonatomic, readonly) UIButton *button;
    @property (nonatomic, strong) UIView *customView;
    @property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
    
    @property (nonatomic, assign) CGFloat verticalOffset;
    @property (nonatomic, assign) CGFloat verticalSpace;
    
    @property (nonatomic, assign) BOOL fadeInOnDisplay;
    
    - (void)setupConstraints;
    - (void)prepareForReuse;
    
    @end
    
    //这里的didMoveToSuperView用到的渐变方法我感觉很棒
    - (void)didMoveToSuperview
    {
        self.frame = self.superview.bounds;
        
        void(^fadeInBlock)(void) = ^{_contentView.alpha = 1.0;};
        
        if (self.fadeInOnDisplay) {
            [UIView animateWithDuration:0.25
                             animations:fadeInBlock
                             completion:NULL];
        }
        else {
            fadeInBlock();
        }
    }
    
    /***
    一些视图的懒加载方法,以及相关属性的配置
    ***/
    
    //子视图的按钮点击后如何响应父视图的方法;就像如下操作
    - (void)didTapButton:(id)sender
    {
        SEL selector = NSSelectorFromString(@"dzn_didTapDataButton:");
        
        if ([self.superview respondsToSelector:selector]) {
            [self.superview performSelector:selector withObject:sender afterDelay:0.0f];
        }
    }
    
    //这里给各个视图约束条件,采用的是HVL语法,但真正被调用的时候却是在父视图中被调用此方法
    - (void)setupConstraints
    {
        // First, configure the content view constaints
        // The content view must alway be centered to its superview
        NSLayoutConstraint *centerXConstraint = [self equallyRelatedConstraintWithView:self.contentView attribute:NSLayoutAttributeCenterX];
        NSLayoutConstraint *centerYConstraint = [self equallyRelatedConstraintWithView:self.contentView attribute:NSLayoutAttributeCenterY];
        
        [self addConstraint:centerXConstraint];
        [self addConstraint:centerYConstraint];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:nil views:@{@"contentView": self.contentView}]];
        
        // When a custom offset is available, we adjust the vertical constraints' constants
        if (self.verticalOffset != 0 && self.constraints.count > 0) {
            centerYConstraint.constant = self.verticalOffset;
        }
        
        // If applicable, set the custom view's constraints
        if (_customView) {
            [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[customView]|" options:0 metrics:nil views:@{@"customView":_customView}]];
            [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|" options:0 metrics:nil views:@{@"customView":_customView}]];
        }
        else {
            CGFloat width = CGRectGetWidth(self.frame) ? : CGRectGetWidth([UIScreen mainScreen].bounds);
            CGFloat padding = roundf(width/16.0);
            CGFloat verticalSpace = self.verticalSpace ? : 11.0; // Default is 11 pts
            
            NSMutableArray *subviewStrings = [NSMutableArray array];
            NSMutableDictionary *views = [NSMutableDictionary dictionary];
            NSDictionary *metrics = @{@"padding": @(padding)};
            
            // Assign the image view's horizontal constraints
            if (_imageView.superview) {
                
                [subviewStrings addObject:@"imageView"];
                views[[subviewStrings lastObject]] = _imageView;
                
                [self.contentView addConstraint:[self.contentView equallyRelatedConstraintWithView:_imageView attribute:NSLayoutAttributeCenterX]];
            }
            
            // Assign the title label's horizontal constraints
            if ([self canShowTitle]) {
                
                [subviewStrings addObject:@"titleLabel"];
                views[[subviewStrings lastObject]] = _titleLabel;
                
                [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(padding@750)-[titleLabel(>=0)]-(padding@750)-|"
                                                                                         options:0 metrics:metrics views:views]];
            }
            // or removes from its superview
            else {
                [_titleLabel removeFromSuperview];
                _titleLabel = nil;
            }
            
            // Assign the detail label's horizontal constraints
            if ([self canShowDetail]) {
                
                [subviewStrings addObject:@"detailLabel"];
                views[[subviewStrings lastObject]] = _detailLabel;
                
                [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(padding@750)-[detailLabel(>=0)]-(padding@750)-|"
                                                                                         options:0 metrics:metrics views:views]];
            }
            // or removes from its superview
            else {
                [_detailLabel removeFromSuperview];
                _detailLabel = nil;
            }
            
            // Assign the button's horizontal constraints
            if ([self canShowButton]) {
                
                [subviewStrings addObject:@"button"];
                views[[subviewStrings lastObject]] = _button;
                
                [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(padding@750)-[button(>=0)]-(padding@750)-|"
                                                                                         options:0 metrics:metrics views:views]];
            }
            // or removes from its superview
            else {
                [_button removeFromSuperview];
                _button = nil;
            }
            
            
            NSMutableString *verticalFormat = [NSMutableString new];
            
            // Build a dynamic string format for the vertical constraints, adding a margin between each element. Default is 11 pts.
            for (int i = 0; i < subviewStrings.count; i++) {
                
                NSString *string = subviewStrings[i];
                [verticalFormat appendFormat:@"[%@]", string];
                
                if (i < subviewStrings.count-1) {
                    [verticalFormat appendFormat:@"-(%.f@750)-", verticalSpace];
                }
            }
            
            // Assign the vertical constraints to the content view
            if (verticalFormat.length > 0) {
                [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|%@|", verticalFormat]
                                                                                         options:0 metrics:metrics views:views]];
            }
        }
    }
    

    4,UIScrollView+DZNEmptyDataSet所有的关键就在下面这段代码里,swizzle的使用,让-dzn_reloadData inject reloadDataendUpdates中就可以了

    - (void)setEmptyDataSetSource:(id<DZNEmptyDataSetSource>)datasource
    {
        if (!datasource || ![self dzn_canDisplay]) {
            [self dzn_invalidate];
        }
        
        objc_setAssociatedObject(self, kEmptyDataSetSource, [[DZNWeakObjectContainer alloc] initWithWeakObject:datasource], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        // We add method sizzling for injecting -dzn_reloadData implementation to the native -reloadData implementation
        [self swizzleIfPossible:@selector(reloadData)];
        
        // Exclusively for UITableView, we also inject -dzn_reloadData to -endUpdates
        if ([self isKindOfClass:[UITableView class]]) {
            [self swizzleIfPossible:@selector(endUpdates)];
        }
    }
    

    相关文章

      网友评论

          本文标题:DZNEmptyDataSet的理解笔记

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