zoukankan      html  css  js  c++  java
  • IOS 自动布局-UIStackPanel和UIGridPanel(四)

    为什么说scrollview的自动化布局是难点?

    对scrollview做自动化布局,无非就是想对scrollview里面的subviews来做自动化布局。但是scrollview里面的subviews的自动化布局不是由scrollview的高宽来决定的,而是由scrollview的contentSize共同决定的,这样就出现一个问题了,就算scrollview的高宽是改变了,但是只要contentSize不变,那么对于scrollview里面的subviews的高宽其实是没有影响的。而实现自动化布局的NSLayoutConstraint也无法实现对scrollview的contentSize属性做自动化布局的。那么纯粹的想使用NSLayoutConstraint来对scrollview做自动化布局的方法是行不通的。

    到这里咱再换一个方法,其实我们平常用scrollview更多的场景是用来做上下滚动或左右滚动,很少有上下滚动和左右滚动同时存在的情况。现在假设我们的自动化布局的scrollview就是上下滚动的,在水平方向,subviews的宽度永远跟scrollview的宽度一致,这样的场景是不是能实现?针对这样的场景我们马上就能想到,只要把subviews的宽度用NSLayoutConstraint实现跟scrollview的宽度绑定就可以了啊。

        UIScrollView *scroll=[[UIScrollView alloc] init];
        scroll.backgroundColor=[UIColor blueColor];
        scroll.isBindSizeToSuperView=YES;
        [self.view addSubview:scroll];
        [scroll setContentSize:CGSizeMake(100, 1000)];
        
        UILabel *label = [[UILabel alloc] initWithSize:CGSizeMake(100, 50)];
        label.backgroundColor = [UIColor blackColor];
        label.textColor=[UIColor whiteColor];
        label.font=[UIFont systemFontOfSize:12];
        label.text = @"Label1";
        label.translatesAutoresizingMaskIntoConstraints=NO;
        label.textAlignment = NSTextAlignmentCenter;
        [scroll addSubview:label];
        [scroll addConstraint:[NSLayoutConstraint constraintWithItem:label
                                                           attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:scroll attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0]];

    我们发现这样做可以啊!别急,你试着再添加一个subview看看?你会发现用这样的方法虽然能让subviews实现宽度跟scrollview的宽度保持一致,但是在垂直方向上无法顺序布局。这是为什么呢?

    问题在于translatesAutoresizingMaskIntoConstraints这个属性我们设置了no,为什么要设置no?只要我们使用自动布局,或者更通俗的说,只要我们使用了NSLayoutConstraint,那么必须要把这个属性设置为no。而一旦设置了no,那么这个view的位置和大小也只能是通过NSLayoutConstraint来实现了。说道这里,看过我前三篇博客的同学就能想到,不是有一个UIStackPanel正好可以实现这样的功能的吗?对的。我们可以直接拿来用,把uiStackpanel做未subview添加到scrollView中,然后将本来要添加到scrollvew中的subviews添加到stackpanel中。这样就能实现以上的场景了。但是这样做还是有一个问题,就是stackpanel的宽度我们是可以绑定到scrollview的宽度,但是高度呢?高度必须跟contentSize的height做绑定。而要实现这样的需求我们就得借助IOS的KVO技术来实现,获取scrollview的contentSize属性变化事件,然后再次绑定。这样就能完全的实现以上的需求了。

    为了把以上的实现过程进行一个封装,我们在UIPanel里面添加了一个bindToScrollView的方法。

    NSString *const KVCUIPanelString_ContentSize = @"scrollView_ContentSize";
    -(void)bindToScrollView:(UIScrollView *)scrollView{
        _scrollView=scrollView;
        self.translatesAutoresizingMaskIntoConstraints=NO;
        
        [scrollView addConstraint:[NSLayoutConstraint constraintWithItem:self
                                                               attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0]];
        
        [scrollView addConstraint:[NSLayoutConstraint constraintWithItem:self
                                                               attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0]];
        
        [scrollView addConstraint:[NSLayoutConstraint constraintWithItem:self
                                                               attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]];
        
        [scrollView addObserver:self forKeyPath:KVCUIPanelString_ContentSize options:NSKeyValueObservingOptionNew context:nil];
        [self addConstraint:[NSLayoutConstraint constraintWithItem:self
                                                         attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:[scrollView contentSize].height]];//第一次绑定的时候直接把scrollView的contentSize.height作为panel的高度
    }
    
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
        if([keyPath isEqualToString:KVCUIPanelString_ContentSize]){
            [self removeConstraints:self.constraints];
            [self addConstraint:[NSLayoutConstraint constraintWithItem:self
                                                             attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:[(UIScrollView *)object contentSize].height]];
        }
    }

    使用kvo的时候一定要记得释放。

    -(void)removeFromSuperview{
        [super removeFromSuperview];
        if(_scrollView){
            [_scrollView removeObserver:self forKeyPath:KVCUIPanelString_ContentSize context:nil];
            _scrollView=nil;
        }
    }

    方法已经封装好了,那么后面就是如何使用了。代码如下:

        //初始化UIScrollView
        UIScrollView *scroll=[[UIScrollView alloc] init];
        scroll.backgroundColor=[UIColor blueColor];
        scroll.isBindSizeToSuperView=YES;//把UIScrollView的高宽绑定到父视图
        [self.view addSubview:scroll];
        [scroll setContentSize:CGSizeMake(100, 1000)];//设置UIScrollView的contentSize
        
        UIStackPanel *_panel=[[UIStackPanel alloc] init];
        [scroll addSubview:_panel];
        _panel.backgroundColor=[UIColor yellowColor];
        [_panel bindToScrollView:scroll];//将UIStackPanel绑定到UIScrollView
    
        UILabel *label = [[UILabel alloc] initWithSize:CGSizeMake(100, 50)];
        label.backgroundColor = [UIColor blackColor];
        label.textColor=[UIColor whiteColor];
        label.font=[UIFont systemFontOfSize:12];
        label.text = @"Label1";
        label.textAlignment = NSTextAlignmentCenter;
        [_panel addSubview:label];
    
        label = [[UILabel alloc] initWithSize:CGSizeMake(100, 50)];
        label.backgroundColor = [UIColor blackColor];
        label.textColor=[UIColor whiteColor];
        label.font=[UIFont systemFontOfSize:12];
        label.text = @"Label2";
        label.margin=UIEdgeInsetsMake(10, 0, 0, 0);
        label.textAlignment = NSTextAlignmentCenter;
        [_panel addSubview:label];

    至此,uiscrollview的自动化解决方案已经完成了。

    下一遍介绍UIView在如何停靠在superView中,实现不管superview的高宽如何改变,都不会改变UIView的停靠位置。

    连带本篇的源码都会在下一篇中给出。

  • 相关阅读:
    android 访问SD卡的方法
    android 用Achartengine 作图
    hello
    IIS 7.0 "确认文件是否存在"功能
    test
    收藏:如何在Web页面上直接打开、编辑、创建Office文档
    JavaScript面向对象技术
    正则表达式30分钟入门教程
    JWT有状态登陆与无状态登陆
    20条JavaScript代码简洁的写法
  • 原文地址:https://www.cnblogs.com/dagehaoshuang/p/4039865.html
Copyright © 2011-2022 走看看