IOS开发之自动布局框架设计(二)

【上集剧情概要:上集我们主要剖析了原生的NSLayoutConstraint实现自动布局的方式,我们知道是通过constraintWithItem这个初始化的方法来配备所需要的7个参数,然后通过addConstraint方法将布局添加进去,并且定义了

NSLayoutAttribute,NSLayoutRelation这些枚举】

如果我们自己设计一款布局框架可以怎么设计呢?

1.封装原有的NSLayoutConstraint类,可以将代码的实现更加简洁化。例如:Masonry,SDAutoLayout。

2.封装坐标布局,并且实现自有的布局方式,至于用什么方式展现给用户,可以自行天马行空,方便易用就行。

3.使用CSS/XML等方式,将布局文件放到一个统一的文件里面,然后初始化的时候进行加载布局。

4.开发一款软件,来实现拖拽好布局之后,自动生成代码,并且有面板可以设置微调当前的参数。

5.还可以将UI动画封装到布局里面,以及控件的交互的封装。

好吧,我们来看看如何封装好NSLayoutConstraint,其实它的核心代码是:

 1 NSLayoutConstraint *constaintTop = [NSLayoutConstraint
 2                                         constraintWithItem:self.tableView
 3                                         attribute:NSLayoutAttributeTop
 4                                         relatedBy:NSLayoutRelationEqual
 5                                         toItem:self.view
 6                                         attribute:NSLayoutAttributeTop
 7                                         multiplier:1.0
 8                                         constant:20];
 9
10     [_tableView addConstraint:constaintTop];

那我们其实就是要封装这一层代码,并且实现更好地接口展现给用户。

1.实现链式调用

首先我们写一个最简单地实现UI布局的代码,功能:实现上下左右四个属性,使用链式调用。

如果我们要实现链式调用,怎么实现呢?

IOS中调用方法的实现使用的是【】,只有属性访问的时候才用点得方式,那么可以通过Setter方法吗?

比如返回值我们设置为当前的view

@property(nonatomic, readonly) UIView *leftSpace;

-(UIView *)leftSpace
{
    return self;
}

那后面的参数怎么传给它呢,所以它不能满足要求。

橘子君又想到一个问题,使用Block呢,因为block作为属性的时候是可以用这种方式的:

blockLeft(10);

也是可以通过.语法来访问的比如:

self.blockLeft(10);

那我们怎么来实现连续的链式点语法的操作呢

如果self.blockLeft(10);返回的是self的话,那就可以实现了:

self.blockLeft(10).blockTop(10).blockRight(10).blockBottom(10);

ok, 这样的话我们可以模拟实现一下这种链式调用的方式:

#import <UIKit/UIKit.h>

@interface UIView (GCFAdditions)

@property(nonatomic, readonly) UIView *(^left)(NSInteger space);
@property(nonatomic, readonly) UIView *(^right)(NSInteger space);
@property(nonatomic, readonly) UIView *(^top)(NSInteger space);
@property(nonatomic, readonly) UIView *(^bottom)(NSInteger space);

@end

首先简单模拟写了left,right,top,bottom四个block属性,返回值都为self

#import "UIView+GCFAdditions.h"

@implementation UIView (GCFAdditions)

- (UIView *(^)(NSInteger space))left
{
    return ^(NSInteger space) {
        //code
        if (space) {
            NSLog(@"%ld",(long)space);
        } else {
            NSLog(@"%ld",(long)space);
        }
        return self;
    };
}

- (UIView *(^)(NSInteger space))right
{
    return ^(NSInteger space) {
        //code
        if (space) {
            NSLog(@"%ld",(long)space);
        } else {
            NSLog(@"%ld",(long)space);
        }

        return self;
    };
}

- (UIView *(^)(NSInteger space))top
{
    return ^(NSInteger space) {
        //code
        if (space) {
            NSLog(@"%ld",(long)space);
        } else {
            NSLog(@"%ld",(long)space);
        }

        return self;
    };
}

- (UIView *(^)(NSInteger space))bottom
{
    return ^(NSInteger space) {
        //code
        if (space) {
            NSLog(@"%ld",(long)space);
        } else {
            NSLog(@"%ld",(long)space);
        }

        return self;
    };
}

@end

好,我们来仔细分析下上面的代码:

首先在属性里面声明一个block,返回类型为UIView,保证下一步的调用,给了一个参数,测试用的。

然后在实现里面,返回self,这时候就可以完成链式调用

#define SCREEN_WIDTH   [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT  [UIScreen mainScreen].bounds.size.height

#import "ViewController.h"
#import "Masonry.h"
#import "UIView+GCFAdditions.h"

@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    self.tableView.left(50).right(50).top(50).bottom(50);

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(UITableView *)tableView
{
    if (!_tableView) {
        _tableView=[[UITableView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        _tableView.backgroundColor=[UIColor redColor];
        [self.view addSubview:_tableView];
    }
    return _tableView;
}

打印结果:

2016-09-08 11:22:31.214 TestMansonry[298:16133] 50
2016-09-08 11:22:31.215 TestMansonry[298:16133] 50
2016-09-08 11:22:31.216 TestMansonry[298:16133] 50
2016-09-08 11:22:31.216 TestMansonry[298:16133] 50

2.实现最简单的布局

上面我们实现了链式调用,那么我们如何运用它来实现布局呢,请看如下代码:

 NSLayoutConstraint *constaintRight = [NSLayoutConstraint
                                             constraintWithItem:self
                                             attribute:NSLayoutAttributeRight
                                             relatedBy:NSLayoutRelationEqual
                                             toItem:self.superview
                                             attribute:NSLayoutAttributeRight
                                             multiplier:1.0
                                             constant:-space];

[self.superview addConstraint:constaintRight];

我们知道实现布局的核心代码是这一段,我们直接移到之前的分类里面就会实现这种效果

- (UIView *(^)(NSInteger space))left
{
    return ^(NSInteger space) {
        if (space) {
            NSLog(@"%ld",(long)space);
        } else {
            NSLog(@"%ld",(long)space);
        }

        NSLayoutConstraint *constaintLeft = [NSLayoutConstraint
                                            constraintWithItem:self
                                            attribute:NSLayoutAttributeLeft
                                            relatedBy:NSLayoutRelationEqual
                                            toItem:self.superview
                                            attribute:NSLayoutAttributeLeft
                                            multiplier:1.0
                                            constant:space];

        [self.superview addConstraint:constaintLeft];

        return self;
    };
}

在实现里面加入

self.tableView.left(50).right(50).top(50).bottom(50);

就可以实现上下左右各50的间距了,哈哈!

时间: 2024-08-04 04:37:19

IOS开发之自动布局框架设计(二)的相关文章

IOS开发之自动布局框架设计(四)

[上集剧情概要:上集我们主要实现了一个完整的自动布局的框架,这集我们主要研究下比较流行的开源布局框架Masonry的布局思路] 我们先来看看是如何开始使用Masonry的,一般我们使用这个布局框架的时候,都会调用以下代码..... [self.view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(50); make.right.mas_equalTo(-50); make.top.mas_equ

IOS开发之自动布局框架设计(三)

[上集剧情概要:上集我们主要试着用连式结构写了一个简单地布局的设计的demo,首先通过block方式实现链式调用,然后封装添加布局的约束到block里面,实现了上下左右的简单布局] 好吧,各位观众,接下来抛砖引玉,逐渐去添加一些布局功能的时候到了..... 首先,我们考虑一个问题,因为上集我们主要是默认相对视图为superview,而且都是用默认偏移量constant,并没有倍数关系,那么我们如何加入toItem和multiplier这两个参数呢??? 用什么方式展示给用户更为好的呢??? 思考

iOS 开发之照片框架详解之二 —— PhotoKit 详解(下)

这里接着前文<iOS 开发之照片框架详解之二 —— PhotoKit 详解(上)>,主要是干货环节,列举了如何基于 PhotoKit 与 AlAssetLibrary 封装出通用的方法. 三. 常用方法的封装 虽然 PhotoKit 的功能强大很多,但基于兼容 iOS 8.0 以下版本的考虑,暂时可能仍无法抛弃 ALAssetLibrary,这时候一个比较好的方案是基于 ALAssetLibrary 和 PhotoKit 封装出一系列模拟系统 Asset 类的自定义类,然后在其中封装好兼容 A

iOS 开发之照片框架详解之二 —— PhotoKit 详解(上)

一. 概况 本文接着 iOS 开发之照片框架详解,侧重介绍在前文中简单介绍过的 PhotoKit 及其与 ALAssetLibrary 的差异,以及如何基于 PhotoKit 与 AlAssetLibrary 封装出通用的方法. 这里引用一下前文中对 PhotoKit 基本构成的介绍: PHAsset: 代表照片库中的一个资源,跟 ALAsset 类似,通过 PHAsset 可以获取和保存资源 PHFetchOptions: 获取资源时的参数,可以传 nil,即使用系统默认值 PHAssetCo

【iOS开发每日小笔记(二)】gitHub上的开源“瀑布流”使用心得

这篇文章是我的[iOS开发每日小笔记]系列中的一片,记录的是今天在开发工作中遇到的,可以用很短的文章或很小的demo演示解释出来的小心得小技巧.该分类的文章,内容涉及的知识点可能是很简单的.或是用很短代码片段就能实现的,但在我看来它们可能会给用户体验.代码效率得到一些提升,或是之前自己没有接触过的技术,很开心的学到了,放在这里得瑟一下(^_^).其实,90%的作用是帮助自己回顾.记忆.复习.如果看官觉得太easy,太碎片,则可以有两个选择:1,移步[iOS探究]分类,对那里的文章进行斧正:2,在

【IOS】IOS开发问题解决方法索引(二)

IOS开发问题解决方法索引(二) 1       不使用ARC编译,-fno-objc-arc ios5 选择了ARC但是不使用ARC编译,-fno-objc-arc http://leobluewing.iteye.com/blog/1384797 http://blog.cnrainbird.com/index.php/2012/03/13/object-c_kai_fa_zhong_hun_he_shi_yong_huo_bu_shi_yong_arc/ 2       SIGABRT错误

[转] iOS --- ReactiveCocoa - iOS开发的新框架

转载唐巧的博客:ReactiveCocoa - iOS开发的新框架

iOS开发网络篇—文件下载(二&#183;合理)

iOS开发网络篇—文件下载(二·合理) 一.边下载,边写入 1.思路 把下载的data追加到文件的尾部,直到所有的数据下载完为止. 1.在连通了服务器的时候,创建一个空的文件到沙盒中NSFileManager(文件管理类) 2.创建写数据的文件句柄 3.在接收到服务器返回的数据后,把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖) 3.1移动到文件的尾部 3.2从当前移动的位置,写入数据 4.服务器的数据加载完毕后关闭连接,不再输入数据在文件中 二.代码示例 1 //

【iOS】小项目框架设计(ReactiveCocoa+MVVM+AFNetworking+FMDB)

网址: http://www.saitjr.com/ios/ios-framework-reactivecocoa-mvvmafnetworking-fmdb.html 上一个项目使用到了ReactiveCocoa+MVVM+AFNetworking+FMDB框架设计,从最初的尝试,到后来不断思考和学习,现在对这样一个整体设计还是有了一定了理解与心得.在此与大家分享下. 本文将不再过多的描述ReactiveCocoa.MVVM.FMDB的使用细节.关于ReactiveCocoa,我有一篇实用案例