简介

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;

使用方法

直接拷贝

  1. 将github工程中的Lib文件夹下的所有文件复制到您的工程中。
  2. #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

演示效果图

 

链接:

欢迎大家访问我的github站点,并关注@欧阳大哥

iOS下的界面布局利器-MyLayout布局框架的更多相关文章

  1. iOS学习——布局利器Masonry框架源码深度剖析

    iOS开发过程中很大一部分内容就是界面布局和跳转,iOS的布局方式也经历了 显式坐标定位方式 --> autoresizingMask --> iOS 6.0推出的自动布局(Auto La ...

  2. IOS开发之绝对布局和相对布局(屏幕适配)

    之前如果做过Web前端页面的小伙伴们,看到绝对定位和相对定位并不陌生,并且使用起来也挺方便.在IOS的UI设计中也有绝对定位和相对定位,和我们的web前端的绝对定位和相对定位有所不同但又有相似之处.下 ...

  3. Flex:CSS3布局利器

    实习以来做了三个小控件,都是用的CSS2.1里传统的DIV+CSS布局方式,综合使用position.margin.float.BFC等属性或特性将元素放到指定的位置上.然而面对日益复杂的界面,这些来 ...

  4. 十. 图形界面(GUI)设计5.布局设计

    在界面设计中,一个容器要放置许多组件,为了美观,为组件安排在容器中的位置,这就是布局设计.java.awt中定义了多种布局类,每种布局类对应一种布局的策略.常用的有以下布局类: FlowLayout, ...

  5. Qt编写数据可视化大屏界面电子看板5-恢复布局

    一.前言 恢复布局这个功能在整个数据可视化大屏界面电子看板系统中非常有用,很多时候不小心把现有布局拖动乱了,(当然如果不想布局被拖动改动,可以修改配置文件中的MoveEnable参数来控制,默认为真表 ...

  6. Qt编写数据可视化大屏界面电子看板3-新建布局

    一.前言 能够新建布局,也是数据可视化大屏界面电子看板系统中的必备功能之一,新建布局这样的功能一般做到右键菜单中,单击新建布局菜单,弹出输入框要求输入新的布局的名称,为了更符合国情,直接支持中文名称, ...

  7. 三十三、Java图形化界面设计——布局管理器之null布局(空布局)

    摘自http://blog.csdn.net/liujun13579/article/details/7774267 三十三.Java图形化界面设计--布局管理器之null布局(空布局) 一般容器都有 ...

  8. 表格布局扩展/DW设计界面中快速整体布局页面的操作

    DW设计界面中快速整体布局页面的操作流程: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &q ...

  9. iOS系列译文:自定义Collection View布局

    原文出处: Ole Begemann   译文出处: 黄爱武(@answer-huang).欢迎加入技术翻译小组. UICollectionView在iOS6中第一次被介绍,也是UIKit视图类中的一 ...

随机推荐

  1. node源码详解(四) —— js代码如何调用C++的函数

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.o ...

  2. 内功心法 -- java.util.ArrayList<E> (1)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  3. 第二章:在HTML中使用JavaScript

    1:在使用<script>嵌入JavaScript代码死,记住不要在代码中的任何地方出现"</script>"字符串 例如,浏览器在加载下面所示代码时就会产 ...

  4. (@WhiteTaken)设计模式学习——抽象工厂模式

    抽象工厂模式,可以向客户端提供一个接口,而客户端不用指定具体的类型创建对象,却能够创建多个产品族(一类具有共性产品,如地域等)的对象. 下面直接上代码. 1.苹果需要实现水果的接口,而苹果可以有北方的 ...

  5. 重写titleView

    在一些特定的情况下不能使用原有的titleView需要重写titleView代码如下 #import "TitleView.h" @implementation TitleView ...

  6. IIS7.0发布后关于"不能在此路径中使用此配置节”的解决办法

    在系统为window sever2008,iis7.0上安装后发布出现 IIS Web Core 通知 BeginRequest 处理程序 尚未确定 错误代码 0x80070021 配置错误 不能在此 ...

  7. 2017年2月16日 分析下为什么spring 整合mybatis后为啥用不上session缓存

    因为一直用spring整合了mybatis,所以很少用到mybatis的session缓存. 习惯是本地缓存自己用map写或者引入第三方的本地缓存框架ehcache,Guava 所以提出来纠结下 实验 ...

  8. 移动端touch实现下拉刷新

    移动端实现下拉刷新 第一部分:四个touch事件 1.touchstart:只要将手指放在了屏幕上(而不管是几只),都会触发touchstart事件. 2.touchmove: 当我们用手指在屏幕上滑 ...

  9. mac 终端简单指令

    pwd 当前工作目录 cd(不加参数) 进root cd(folder) 进入文件夹 cd .. 上级目录 cd ~ 返回root cd - 返回上一个访问的目录 rm 文件名 删除 cat 文件名( ...

  10. Javascript面对对象. 第三篇

    3.字面量 为了让属性和方法很好的体现封装的效果,并且减少不必要的输入原型的创建可以使用字面量. function Box(){} //使用字面量的方法创建原型对象,这里的{}就是对象,是Object ...