iOS 盒子布局之 YogaKit

👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇

前言

未来大前端是一个趋势,对于布局方面盒子布局FlexBox也是趋势,我们iOS开发中,怎么使用盒子布局呢?

1. iOS 原生布局

1.1 iOS布局介绍

在iOS开发中常用的是下面2种

  • Frame

frame`布局是设置视图的坐标,依赖于父视图,属于`相对布局
  • Auto Layout

Auto Layout布局是苹果出的一种布局方式,原理是通过Cassowary算法进行计算 Cassowary是上世纪90年代诞生的一种用于解决用户界面布局问题的算法,它通过将布局问题抽象成线性等式不等式约束来进行求解,而我们要了解的Auto Layout就是对Cassowary算法的一种实现。通过视图控件之间的关系进行布局,但是本身语法很长,我们通常会使用三方的框架进行实现比如Masonry等

1.2 Auto Layout 原理

我们使用storyboard进行演示,我们确定一个视图的布局

c8eb06e37011552580da7db1a2e43467.jpeg

我们上面的蓝色视图就可以依赖下面黄色视图进行布局,设置等宽等高

e6732c14e56332ae2bbcd53ca6cc5f2d.jpeg
左对齐
a686aede1f3e4af0bcae7886628e4ba1.jpeg

底部距离黄色的头部距离

f6a850a5758429b1b79b2e293a12d2d7.jpeg

当我们旋转屏幕的时候,根据它们的依赖关系也是一样

06dcdf08b19bd9797c78933395b285d4.jpeg

这就是自动布局,依赖我们的确定的视图,根据依赖关系进行布局。

使用Frame表示

UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(20, 350, 100, 60)];

    view1.backgroundColor = [UIColor orangeColor];

    [self.view addSubview:view1];

    

    UIView *view2 = [[UIView alloc]init];

    view2.backgroundColor = [UIColor greenColor];

    CGRect frame = CGRectMake(0, 0, 0, 0);

    frame.size = view1.frame.size;

    frame.origin.x = view1.frame.origin.x;

    frame.origin.y = view1.frame.origin.y - view1.frame.size.height  -40;

    view2.frame = frame;

    [self.view addSubview:view2];

但是我们旋转屏幕的时候,不是我们想要的结果,这就是绝对布局的一些不好的地方

8750dbd7f8fffab5e16dc57c6b776f61.jpeg

自动布局的原理大概就是这样,控件件是依赖关系,不是绝对关系

2. YogaKit

2.1 FlexBox 简单介绍

FlexBox 是一种盒子布局方式,在前端和页面应用比较广泛,布局的方式主要是rowcolumnstack3个方向进行布局,控件类似在一个盒子里面,弹性布局.

FlexBox 把每个视图,都看作一个矩形盒子,拥有内外边距,沿着主轴方向排列,并且,同级的视图之间没有依赖

采用flex布局的元素,称为Flex容器,简称’容器‘,它所有元素自动成为容器成员,称为Flex项目。弹性布局和方向没有关系,它是一维布局。

2.2 YogaKit

YogaKitfacebook开源的一个关于盒子布局的框架,适用于整个大前端,这里我们主要介绍下iOS中yogakit的使用,查看GitHub上YogaKit[1]

我们新建一个项目pod 'YogaKit'

我们看下携程的首页,菜单布局

3a16f30355c0c5c2a218074485eec808.jpeg

我们分析下怎么样布局,布局的方式有很多,我们整体分为4个板块,从上向下布局。前2个布局样式我们可以水平布局,也可以竖直布局,第三个某块分为2个部分,右边的可以水平布局,也可以水平后竖直布局,最后一个水平布局

0555fd41713db4cdb15ebf83eb470c2d.jpeg

同时我们可以发现组件之间有间距,itemButton之间也有间距。这里要区分下paddingmargin的区别。padding类似我们iOS中的UIEdgeInsets,约束自己的内部边距,margin则相当于距外部的边距

e6508bb7fb011ff8fefc558cd157bfce.jpeg 红色的是margin,白色区域相当于padding

我们这里设置

#define paddingNo   3

#define marginNo    .5f

#define columnNo    3

#define btnHeight   62

#define btnWidth    ((UI_SCREEN_WIDTH - paddingNo*2 - columnNo*marginNo*2) / columnNo)
复制代码

2.3 使用

UIView的拓展 276160cb9d02a010650d4e49c46209e2.jpeg 继续查看YGLayoutYGLayoutisEnabled默认是no,要手动开启,同时要在主线程布局UI

79d063d9a593df14d8a01bf05faf7912.jpeg
2.3.1 第一模块和第二模块

我们把按钮创建抽出来

- (UIButton *)createBtnWithTitle:(NSString *)title BackgroundColor:(UIColor *)color ImageIndex:(int)index {

    UIButton *commonBtn = [[UIButton alloc] init];

    [commonBtn setBackgroundImage:[UIImage imageNamed:[NSString stringWithFormat:@"btnImg_%d", index]] forState:UIControlStateNormal];

    commonBtn.backgroundColor = color;

    [commonBtn setTitle:title forState:UIControlStateNormal];

    [commonBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

    commonBtn.titleLabel.font = [UIFont systemFontOfSize:15];

    commonBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

    [commonBtn setTitleEdgeInsets:UIEdgeInsetsMake(index==13?-btnHeight:0, 10, 0, 0)];

    [commonBtn addTarget:self action:@selector(commonBtnAction:) forControlEvents:UIControlEventTouchUpInside];

    

    return commonBtn;

}


- (void)commonBtnAction:(UIButton *)sender {

    sender.selected = !sender.selected;

    UIViewAnimationTransition tra = sender.selected?UIViewAnimationTransitionFlipFromLeft:UIViewAnimationTransitionFlipFromRight;

    [UIView animateWithDuration:.35 animations:^{

        [UIView setAnimationTransition:tra forView:sender cache:YES];

    }];

}

实现模块一的效果

00c6b146c93c78ae3091af11955bbd40.jpeg

我们最后设置下主界面的layout配置,同时主动调用applyLayoutPreservingOrigin:父视图执行布局计算并使用结果更新层次结构中视图的帧

我们把容器的主轴方向改为column,不设置高度的话会容器的元素会自动撑满

241f9e505f2a60fb7e532a192c3dcc4f.jpeg

设置高度,可以达到我们row的效果布局,默认容器的布局方向为纵向。

a244002098f2d0bb4a24d592477f921d.jpeg

第二模块类似

b4f3e1f66dfe289fbe5b475054eeebfc.jpeg
2.3.2 模块三和四

对于模块3我们直接添加会有问题

22fc2e58eb9546d2c8b6819be09de394.jpeg

我们把右边部分当成一个模块

c04ccae35013041582b3f293e8fcda8b.jpeg

模块4类似

e98dc134d29cd15031e2f6169b2d232b.jpeg

当我们调整个数的时候也很方便

e92694cf0b63cf2f234f830d49b11381.jpeg

我们也可以实现一个自定义的九宫格类型

9dca2b48828917201e5c485b3fb3e4ff.jpeg

参考资料

[1]

YogaKit: https://github.com/facebook/yoga

代码地址:

https://github.com/DHFLoveWL/YogaKitDemo)

来源:潜水的鱼儿 

https://juejin.cn/post/7039635424947470343

-End-

最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!

f1d04c6e376aa1701f653cc124968dc5.png

点击👆卡片,关注后回复【面试题】即可获取

在看点这里ff8a4dd5bb3b300f65f2a5407984f757.gif好文分享给更多人↓↓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值