iOS下的界面布局利器-MyLayout布局框架

- Swift:TangramKit: https://github.com/youngsoft/TangramKit
- OC:MyLayout: https://github.com/youngsoft/MyLinearLayout
简介
MyLayout是一套iOS界面视图布局框架。其内核是基于对UIView的layoutSubviews方法的重载以及对子视图的bounds和center属性的设置而实现的。MyLayout功能强大而且简单易用,它集成了iOS Autolayout和Size Classes、android的5大布局体系、HTML/CSS的浮动定位技术以及flex-box和bootstrap框架等市面上主流的平台的界面布局功能,同时提供了一套非常简单和完备的多屏幕尺寸适配的解决方案。MyLayout还提供了Swift版本TangramKit
MyLayout的优势
- MyLayout的实现内核是基于frame的设置,而不是对AutoLayout的封装。因此在使用上不会受到任何操作系统版本的限制。
- 有文章表明用frame进行布局的性能要高于用AutoLayout进行布局的性能,尤其是当界面内视图数量增加时效果更加明显。
- AutoLayout的思想是通过视图之间的约束依赖来完成布局,但是约束依赖的结果是造成视图之间的耦合性高而增大了界面更新的成本。而MyLayout则除了提供约束依赖外,还提供了根据视图添加顺序自动建立约束的功能,从而减少了这种显示依赖关系建立的问题,最终的结果是简化了布局的代码量,以及减少了布局更新时的代码修改量。
- AutoLayout只是一种相对约束的布局,而MyLayout除了同时提供具有和AutoLayout相同能力的相对布局外、还提供了线性布局、框架布局、表格布局、流式布局、浮动布局、路径布局7大布局体系,你完全可以根据你的界面需求来选择一种最简易的布局容器来实现你的功能,同时MyLayout还支持Size classes的机制,以及提供了一些实现屏幕尺寸完美适配的方法。
- MyLayout主要是一种通过代码进行布局的解决方案,但是框架一样可以支持和XIB以及SB结合布局的方式。并提供了视图隐藏和显示时会自动激发布局、布局视图的高度自适应(UITableviewCell动态高度)、标签云实现、左右内容宽度自适应、按比例分配尺寸和间距、整体停靠控制等等各种强大的功能。
AutoLayout和frame布局的性能比较


参考的文章地址:http://floriankugler.com/2013/04/22/auto-layout-performance-on-ios/
应用场景
举例下面一个应用场景:
- 有一个容器视图S的宽度是100而高度则是由四个从上到下依次排列的子视图A,B,C,D的高度总和。
- 视图A的左边距占用父视图宽度的20%,而右边距则占用父视图宽度的30%,高度则等于自身的宽度。
- 视图B的左边距是40,宽度则占用父视图的剩余宽度,高度是40。
- 视图C的宽度占用父视图的所有宽度,高度是40。
- 视图D的右边距是20,宽度是父视图宽度的50%,高度是40。
最终的效果图如下:

MyLinearLayout *S = [MyLinearLayout linearLayoutWithOrientation:MyLayoutViewOrientation_Vert];
S.subviewMargin = ;
S.myWidth = ; UIView *A = UIView.new;
A.leftPos.equalTo(@0.2);
A.rightPos.equalTo(@0.3);
A.heightDime.equalTo(A.widthDime);
[S addSubview:A]; UIView *B = UIView.new;
B.leftPos.equalTo(@);
B.widthDime.equalTo(@);
B.heightDime.equalTo(@);
[S addSubview:B]; UIView *C = UIView.new;
C.widthDime.equalTo(S.widthDime);
C.heightDime.equalTo(@);
[S addSubview:C]; UIView *D = UIView.new;
D.rightPos.equalTo(@);
D.widthDime.equalTo(S.widthDime).multiply(0.5);
D.heightDime.equalTo(@);
[S addSubview:D];
系统结构

布局位置类MyLayoutPos
MyLayoutPos类是用来描述一个视图所在的位置的类。UIView中扩展出了leftPos,topPos,bottomPos,rightPos,centerXPos,centerYPos这六个变量来实现视图的定位操作。您可以用这些变量的equalTo
方法来设置视图之间的边距和间距。 equalTo
方法可以设置NSNumber, MyLayoutPos, NSArray<MyLayoutPos*>这几种值,分别用于不同的场景。同时系统提供了6个简单的变量myLeftMargin, myTopMargin, myBottomMargin, myRightMargin, myCenterXOffset, mYCenterYOffset来设置NSNumber类型的值,比如 A.leftPos.equalTo(@10); 等价于 A.myLeftMargin = 10;
.
布局尺寸类MyLayoutSize
MyLayoutSize类是用来描述一个视图的尺寸的类。UIView中扩展出了widthDime,heightDime这两个变量来实现视图的宽度和高度尺寸的设置。您可以用其中的equalTo
方法来设置视图的宽度和高度。equalTo
方法可以设置NSNumber, MyLayoutSize, NSArray<MyLayoutSize*>这几种值,分别用于不同的场景。同时系统提供了2个简单的变量myWidth,myHeight来设置NSNumber类型的值,比如A.widthDime.equalTo(@10); 等价于A.myWidth = 10;
.
线性布局MyLinearLayout
等价于iOS的UIStackView和android的LinearLayout布局。
线性布局是一种里面的子视图按添加的顺序从上到下或者从左到右依次排列的单列(单行)布局视图,因此里面的子视图是通过添加的顺序建立约束和依赖关系的。 子视图从上到下依次排列的线性布局视图称为垂直线性布局视图,而子视图从左到右依次排列的线性布局视图则称为水平线性布局。

示例代码:
-(void)loadView
{
[super loadView]; MyLinearLayout *S = [MyLinearLayout linearLayoutWithOrientation:MyLayoutViewOrientation_Vert];
S.myWidth = ;
S.subviewMargin = ; UIView *A = [UIView new];
A.myLeftMargin = A.myRightMargin = ;
A.myHeight = ;
[S addSubview:A]; UIView *B = [UIView new];
B.myLeftMargin = ;
B.myWidth = B.myHeight = ;
[S addSubview:B]; UIView *C = [UIView new];
C.myRightMargin = ;
C.myWidth = ;
C.myHeight = ;
[S addSubview:C]; UIView *D = [UIView new];
D.myLeftMargin = D.myRightMargin = ;
D.myHeight = ;
[S addSubview:D]; [self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
}
相对布局MyRelativeLayout
等价于iOS的AutoLayout 和 Android的RelativeLayout布局。
相对布局是一种里面的子视图通过相互之间的约束和依赖来进行布局和定位的布局视图。相对布局里面的子视图的布局位置和添加的顺序无关,而是通过设置子视图的相对依赖关系来进行定位和布局的。

示例代码:
-(void)loadView
{
[super loadView]; MyRelativeLayout *S = [MyRelativeLayout new];
S.widthDime.equalTo(@);
S.heightDime.equalTo(@); UIView *A = [UIView new];
A.leftPos.equalTo(@);
A.topPos.equalTo(@);
A.widthDime.equalTo(@);
A.heightDime.equalTo(A.widthDime);
[S addSubview:A]; UIView *B = [UIView new];
B.leftPos.equalTo(A.centerXPos);
B.topPos.equalTo(A.bottomPos).offset();
B.widthDime.equalTo(@);
B.heightDime.equalTo(A.heightDime);
[S addSubview:B]; UIView *C = [UIView new];
C.leftPos.equalTo(B.rightPos).offset();
C.bottomPos.equalTo(B.bottomPos);
C.widthDime.equalTo(@);
C.heightDime.equalTo(B.heightDime).multiply(0.5);
[S addSubview:C]; UIView *D = [UIView new];
D.bottomPos.equalTo(C.topPos).offset();
D.rightPos.equalTo(@);
D.heightDime.equalTo(A.heightDime);
D.widthDime.equalTo(D.heightDime);
[S addSubview:D]; UIView *E = [UIView new];
E.centerYPos.equalTo(@);
E.centerXPos.equalTo(@);
E.heightDime.equalTo(@);
E.widthDime.equalTo(S.widthDime).add(-);
[S addSubview:E];
//.. F, G [self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
E.backgroundColor = [UIColor magentaColor];
}
框架布局MyFrameLayout
等价于Android的FrameLayout布局。
框架布局是一种里面的子视图停靠在父视图特定方位并且可以重叠的布局视图。框架布局里面的子视图的布局位置和添加的顺序无关,只跟父视图建立布局约束依赖关系。框架布局将垂直方向上分为上、中、下三个方位,而水平方向上则分为左、中、右三个方位,任何一个子视图都只能定位在垂直方向和水平方向上的一个方位上。

示例代码:
-(void)loadView
{
[super loadView]; MyFrameLayout *S = [MyFrameLayout new];
S.mySize = CGSizeMake(,); UIView *A = [UIView new];
A.mySize = CGSizeMake(,);
[S addSubview:A]; UIView *B = [UIView new];
B.mySize = CGSizeMake(,);
B.myRightMargin = ;
[S addSubview:B]; UIView *C = [UIView new];
C.mySize = CGSizeMake(,);
C.myCenterYOffset = ;
[S addSubview:C]; UIView *D = [UIView new];
D.mySize = CGSizeMake(,);
D.myCenterOffset = CGPointZero;
[S addSubview:D]; //..E,F,G [self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
}
表格布局MyTableLayout
等价于Android的TableLayout布局和HTML的table元素。
表格布局是一种里面的子视图可以像表格一样多行多列排列的布局视图。子视图添加到表格布局视图前必须先要建立并添加行视图,然后再将子视图添加到行视图里面。如果行视图在表格布局里面是从上到下排列的则表格布局为垂直表格布局,垂直表格布局里面的子视图在行视图里面是从左到右排列的;如果行视图在表格布局里面是从左到右排列的则表格布局为水平表格布局,水平表格布局里面的子视图在行视图里面是从上到下排列的。

示例代码:
-(void)loadView
{
[super loadView]; MyTableLayout *S = [MyTableLayout tableLayoutWithOrientation:MyLayoutViewOrientation_Vert];
S.wrapContentWidth = YES;
S.rowSpacing = ;
S.colSpacing = ; [S addRow:MTLSIZE_WRAPCONTENT colSize:MTLSIZE_WRAPCONTENT]; UIView *A = [UIView new];
A.mySize = CGSizeMake(,);
[S addSubview:A]; UIView *B = [UIView new];
B.mySize = CGSizeMake(,);
[S addSubview:B]; UIView *C = [UIView new];
C.mySize = CGSizeMake(,);
[S addSubview:C]; [S addRow:MTLSIZE_WRAPCONTENT colSize:MTLSIZE_WRAPCONTENT]; UIView *D = [UIView new];
D.mySize = CGSizeMake(,);
[S addSubview:D]; //...E,F [self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
}
流式布局MyFlowLayout
等价于CSS3的flex-box。
流式布局是一种里面的子视图按照添加的顺序依次排列,当遇到某种约束限制后会另起一行再重新排列的多行展示的布局视图。这里的约束限制主要有数量约束限制和内容尺寸约束限制两种,而换行的方向又分为垂直和水平方向,因此流式布局一共有垂直数量约束流式布局、垂直内容约束流式布局、水平数量约束流式布局、水平内容约束流式布局。流式布局主要应用于那些子视图有规律排列的场景,在某种程度上可以作为UICollectionView的替代品。

示例代码:
-(void)loadView
{
[super loadView]; MyFlowLayout *S = [MyFlowLayout flowLayoutWithOrientation:MyLayoutViewOrientation_Vert arrangedCount:];
S.wrapContentHeight = YES;
S.myWidth = ;
S.padding = UIEdgeInsetsMake(, , , );
S.gravity = MyMarginGravity_Horz_Fill;
S.subviewMargin = ; for (int i = ; i < ; i++)
{
UIView *A = [UIView new];
A.heightDime.equalTo(A.widthDime);
[S addSubview:A]; A.backgroundColor = [UIColor greenColor]; } [self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
}
浮动布局MyFloatLayout
等价于css中的float定位。
浮动布局是一种里面的子视图按照约定的方向浮动停靠,当尺寸不足以被容纳时会自动寻找最佳的位置进行浮动停靠的布局视图。浮动布局的理念源于HTML/CSS中的浮动定位技术,因此浮动布局可以专门用来实现那些不规则布局或者图文环绕的布局。根据浮动的方向不同,浮动布局可以分为左右浮动布局和上下浮动布局。

示例代码:
-(void)loadView
{
[super loadView]; MyFloatLayout *S = [MyFloatLayout floatLayoutWithOrientation:MyLayoutViewOrientation_Vert];
S.wrapContentHeight = YES;
S.padding = UIEdgeInsetsMake(, , , );
S.subviewMargin = ;
S.myWidth = ; UIView *A = [UIView new];
A.mySize = CGSizeMake(,);
[S addSubview:A]; UIView *B = [UIView new];
B.mySize = CGSizeMake(,);
[S addSubview:B]; UIView *C = [UIView new];
C.mySize = CGSizeMake(,);
[S addSubview:C]; UIView *D = [UIView new];
D.mySize = CGSizeMake(,);
[S addSubview:D]; UIView *E = [UIView new];
E.mySize = CGSizeMake(,);
E.reverseFloat = YES;
[S addSubview:E]; UIView *F = [UIView new];
F.mySize = CGSizeMake(,);
[S addSubview:F]; [self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
A.backgroundColor = [UIColor greenColor];
B.backgroundColor = [UIColor blueColor];
C.backgroundColor = [UIColor orangeColor];
D.backgroundColor = [UIColor cyanColor];
E.backgroundColor = [UIColor blackColor];
F.backgroundColor = [UIColor whiteColor];
}
路径布局MyPathLayout
布局库独有
路径布局是一种里面的子视图根据您提供的一条特定的曲线函数形成的路径来进行布局的布局视图。您需要提供一个实现曲线路径的函数、一个特定的坐标体系、一种特定的子视图在曲线上的距离设置这三个要素来实现界面布局。当曲线路径形成后,子视图将按相等的距离依次环绕着曲线进行布局。路径布局主要应用于那些具有特定规律的不规则排列,而且效果很酷炫的的界面布局。

示例代码:
-(void)loadView
{
[super loadView]; MyPathLayout *S = [MyPathLayout new];
S.mySize = CGSizeMake(,);
S.coordinateSetting.isReverse = YES;
S.coordinateSetting.origin = CGPointMake(0.5, 0.2); S.polarEquation = ^(CGFloat angle)
{
return * ( + cos(angle));
}; for (int i = ; i < ; i++)
{
UIView *A = [UIView new];
A.mySize = CGSizeMake(,);
[S addSubview:A]; A.backgroundColor = [UIColor greenColor];
} [self.view addSubview:S];
S.backgroundColor = [UIColor redColor];
}
Size Classes的支持
等价于iOS的Size Classes
MyLayout布局体系为了实现对不同屏幕尺寸的设备进行适配,提供了对Size Classes的支持。您可以将Size Classes和上述的6种布局搭配使用,以便实现各种设备界面的完美适配。系统提供2个UIView的扩展方法:
-(instancetype)fetchLayoutSizeClass:(MySizeClass)sizeClass;
-(instancetype)fetchLayoutSizeClass:(MySizeClass)sizeClass copyFrom:(MySizeClass)srcSizeClass;
来实现对Size Classes的支持。比如下面的例子:
//默认所有设备的设置。
MyLinearLayout *rootLayout = [MyLinearLayout linearLayoutWithOrientation:MyLayoutViewOrientation_Vert];
rootLayout.padding = UIEdgeInsetsMake(, , , );
rootLayout.wrapContentHeight = NO;
rootLayout.gravity = MyMarginGravity_Horz_Fill; //MySizeClass_wAny | MySizeClass_hCompact 表明的是iPhone设备的横屏.
MyLinearLayout *lsc = [rootLayout fetchLayoutSizeClass:MySizeClass_wAny | MySizeClass_hCompact copyFrom:MySizeClass_wAny | MySizeClass_hAny]; lsc.orientation = MyLayoutViewOrientation_Horz;
lsc.wrapContentWidth = NO;
lsc.gravity = MyMarginGravity_Vert_Fill;
使用方法
直接拷贝
- 将github工程中的Lib文件夹下的所有文件复制到您的工程中。
- 将
#import "MyLayout.h"
头文件放入到您的pch文件中,或者在需要使用界面布局的源代码位置。
CocoaPods安装
如果您还没有安装cocoapods则请先执行如下命令:
$ gem install cocoapods
为了用CocoaPods整合MyLayout到您的Xcode工程, 请建立如下的Podfile:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '7.0'
pod 'MyLayout', '~> 1.3.4'
然后运行如下命令:
$ pod install
演示效果图

链接:
- Swift:TangramKit: https://github.com/youngsoft/TangramKit
- OC:MyLayout: https://github.com/youngsoft/MyLinearLayout
iOS下的界面布局利器-MyLayout布局框架的更多相关文章
- iOS学习——布局利器Masonry框架源码深度剖析
iOS开发过程中很大一部分内容就是界面布局和跳转,iOS的布局方式也经历了 显式坐标定位方式 --> autoresizingMask --> iOS 6.0推出的自动布局(Auto La ...
- IOS开发之绝对布局和相对布局(屏幕适配)
之前如果做过Web前端页面的小伙伴们,看到绝对定位和相对定位并不陌生,并且使用起来也挺方便.在IOS的UI设计中也有绝对定位和相对定位,和我们的web前端的绝对定位和相对定位有所不同但又有相似之处.下 ...
- Flex:CSS3布局利器
实习以来做了三个小控件,都是用的CSS2.1里传统的DIV+CSS布局方式,综合使用position.margin.float.BFC等属性或特性将元素放到指定的位置上.然而面对日益复杂的界面,这些来 ...
- 十. 图形界面(GUI)设计5.布局设计
在界面设计中,一个容器要放置许多组件,为了美观,为组件安排在容器中的位置,这就是布局设计.java.awt中定义了多种布局类,每种布局类对应一种布局的策略.常用的有以下布局类: FlowLayout, ...
- Qt编写数据可视化大屏界面电子看板5-恢复布局
一.前言 恢复布局这个功能在整个数据可视化大屏界面电子看板系统中非常有用,很多时候不小心把现有布局拖动乱了,(当然如果不想布局被拖动改动,可以修改配置文件中的MoveEnable参数来控制,默认为真表 ...
- Qt编写数据可视化大屏界面电子看板3-新建布局
一.前言 能够新建布局,也是数据可视化大屏界面电子看板系统中的必备功能之一,新建布局这样的功能一般做到右键菜单中,单击新建布局菜单,弹出输入框要求输入新的布局的名称,为了更符合国情,直接支持中文名称, ...
- 三十三、Java图形化界面设计——布局管理器之null布局(空布局)
摘自http://blog.csdn.net/liujun13579/article/details/7774267 三十三.Java图形化界面设计--布局管理器之null布局(空布局) 一般容器都有 ...
- 表格布局扩展/DW设计界面中快速整体布局页面的操作
DW设计界面中快速整体布局页面的操作流程: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &q ...
- iOS系列译文:自定义Collection View布局
原文出处: Ole Begemann 译文出处: 黄爱武(@answer-huang).欢迎加入技术翻译小组. UICollectionView在iOS6中第一次被介绍,也是UIKit视图类中的一 ...
随机推荐
- InnoDB的表类型,逻辑存储结构,物理存储结构
表类型 对比Oracle支持的各种表类型,InnoDB存储引擎表更像是Oracle中的索引组织表(index organized table).在InnoDB存储引擎表中,每张表都有个主键,如果在创建 ...
- 滚动视图(ScrollView)的功能与用法
滚动视图ScrollView由FrameLayout派生而出,它就是一个用于为普通组件添加滚动条的组件.ScrollView里最多只能包含一个组件,而ScrollVew的作用就是为该组件添加垂直滚动条 ...
- Mongoose与bluebird结合使用实例
nodejs的所有调用几乎是全异步的,而所有的IO操作也都是通过回调函数才能知道结果. 如果一个异步调用依赖另一个异步调用,如果没有Promise的话,有可能陷入传说中的回调地狱. bluebird实 ...
- ubuntu linux 设置环境变量
添加环境变量 1.添加临时变量 终端中输入: PATH="$PATH:yourpath" :yourpath是要添加的环境变量(即要添加目录的绝对路径,例:/home/myprog ...
- JavaScript 语法
一.JavaScript简介 1.JavaScript是个什么东西? 它是个脚本语言,需要有宿主文件,它的宿主文件是HTML文件. 2.它与Java什么关系? 没有什么直接的联系,Java是Sun公司 ...
- CSS中:visited的隐私保护
CSS 伪类 (Pseudo-classes) 锚伪类:在支持 CSS 的浏览器中,链接的不同状态都可以不同的方式显示,这些状态包括:活动状态,已被访问状态,未被访问状态,和鼠标悬停状态. a:lin ...
- for语句输出图形
一.输出以下图形 ******************************** 用for...for...嵌套循环,内循环控制每一行的个数(即列数),外循环控制行数 class ForDraw { ...
- 【Java】Objects 源码学习
2017-02-10 by 安静的下雪天 http://www.cnblogs.com/quiet-snowy-day/p/6387321.html 本篇概要 Objects 与 Object ...
- java GUI简单记事本
代码: import java.awt.*; import java.awt.event.*; import java.io.*; class MyMenu { //定义该窗体所需的组件,方便其他函数 ...
- C# 类型和变量
C# 中的类型有两种:值类型 (value type) 和引用类型 (reference type).值类型的变量直接包含它们的数据,而引用类型的变量存储对它们的数据的引用,后者称为对象.对于引用类型 ...