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的停靠位置。

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

时间: 2024-08-04 14:03:48

IOS 自动布局-UIStackPanel和UIGridPanel(四)的相关文章

IOS 自动布局-UIStackPanel和UIGridPanel

我以前是做windows phone开发的,后来转做IOS的开发,因此很多windows phone上面的开发经验也被我带到了IOS中.其实有些经验本身跟平台无关,跟平台有关的无非就是实现方法而已.好了,废话不多说. 我今天给大家介绍一个IOS自动华布局的辅助类(UIPanel   UIStackPanel  UIGridPanel),做过windows phone开发的同学看到这三个类肯定很眼熟,没错,这三个类正是windows phone布局的核心,只是名称稍微有点不一样而已. 我先介绍下我

IOS 自动布局-UIStackPanel和UIGridPanel(三)

在这一篇了我将继续讲解UIGridPanel. 在iphone的app里面可以经常看到一些九宫格布局的应用,做过html开发的对这类布局应该是很熟悉的.在IOS中要实现这样的布局方法还是蛮多的,但是我这次主要是讲解直接通过控件来实现,我直接指定某个subview处于gridpanel的某行某列.甚至我要求该subview跨多行多列来显示. 要实现以上的需求,那么首先就得要求该panel具有行和列的属性,也就是该panel可以被拆分成多少行多少列.用代码表示如下: @interface UIGri

IOS 自动布局-UIStackPanel和UIGridPanel(五)

试想这样的一个需求场合,一个button靠右显示,并且距离superView的顶部和右边间距分别为10和5.如下图所示: 要实现这样的需求,如果不用自动布局技术,那么我们能想到的就是老老实实的使用绝对布局的坐标计算来实现了,假如这个button宽高都是100,父视图的宽是300,那么这个button的坐标就是:(300-100-5,10).但要是父视图的宽度变了,我们还得重新计算一遍.颇为麻烦. 幸好我们有自动布局技术.要实现这样的需求还是相对比较简单的. 既然我们要实现这样的需求,而且这个需求

iOS自动布局——Masonry详解

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由鹅厂新鲜事儿发表于云+社区专栏 作者:oceanlong | 腾讯 移动客户端开发工程师 前言 UI布局是整个前端体系里不可或缺的一环.代码的布局是设计语言与用户视觉感受沟通的桥梁,不论它看起来多么简单或是琐碎,但不得不承认,绝大部分软件开发的问题,都是界面问题.那么,如何高效的完成UI开发,也是软件行业一直在克服的问题. 所以,软件界面开发的核心点即是:如何减少UI设计稿的建模难度和减少建模转化到代码的实现难度 最初iOS提供了

线程同步-iOS多线程编程指南(四)-08-多线程

首页 编程指南 Grand Central Dispatch 基本概念 多核心的性能 Dispatch Sources 完结 外传:dispatch_once(上) Block非官方编程指南 基础 内存管理 揭开神秘面纱(上) 揭开神秘面纱(下) iOS多线程编程指南 关于多线程编程 线程管理 Run Loop 线程同步 附录 Core Animation编程指南 Core Animation简介 基本概念 渲染架构 几何变换 查看目录 中文手册/API ASIHTTPRequest Openg

iOS 自动布局

自动布局框架 Masonry PureLayout FLKAutoLayout KeepLayout UIView+Autolayout 相关教程: iOS 开发实践之 Auto Layout Masonry介绍与使用实践(快速上手Autolayout) IOS自动布局之Autoresizing iOS中的相对布局:AutoLayout

IOS数据本地存储的四种方式--

注:借鉴于:http://blog.csdn.net/jianjianyuer/article/details/8556024 在IOS开发过程中,不管是做什么应用,都会碰到数据保存问题.将数据保存到本地,能够让程序更加流畅,不会出现让人厌恶的菊花状,使得用户的体验更好.下面是介绍数据保存的方式 第一.NSKeyedArchiver:采用归档的形式来保存数据.(归档——解档)———大量数据和频繁读写不合适使用 1.归档器的作用是将任意的对象集合转换为字节流.这听起来像是NSPropertyLis

ios页面间传递参数四种方式

ios页面间传递参数四种方式 1.使用SharedApplication,定义一个变量来传递. 2.使用文件,或者NSUserdefault来传递 3.通过一个单例的class来传递 4.通过Delegate来传递. IOS开发使用委托delegate在不同窗口之间传递数据是本文要介绍的内容,主要是来讲解如何使用委托delegate在不同窗口之间传递数据,具体内容来看详细内容.在IOS开发里两个UIView窗口之间传递参数方法有很多,比如 前面3种方法,暂且不说,这次主要学习如何使用通过Dele

iOS 导出 ipa 包时 四个选项的意义

iOS 导出 ipa 包时 四个选项的意义 摘要:如图 正在 iOS 随处 ipa包的时间 会有四个选项 1.Save for iOS App Store Deployment 保管到当地 预备上传App Store 或正在逃狱的iOS装备上应用 2.Save ] 如图 在 iOS 到处 ipa包的时候 会有四个选项 1.Save for iOS App Store Deployment 保存到本地 准备上传App Store 或者在越狱的iOS设备上使用 2.Save for Ad Hoc D