内容简介:这里有一篇关于YogaKit使用方法的翻译文章,其中介绍的比较全面,基本可以使用FlexBox布局,但是仅仅看这里的介绍还是难以解决一些布局问题,本篇文章不再介绍在学习FlexBox布局的时候,为了加深理解建议学习一下CSS,理解盒子模型、外边距、内边距、定位、定位上下文及相对定位和绝对定位的区别,能够帮助我们更好的理解FlexBox,更好的使用YogaKit。如下图,这种布局很常见,实现的方法也有很多,使用YogaKit实现也有很多方法,但是优雅程度不同。
这里有一篇关于YogaKit使用方法的翻译文章,其中介绍的比较全面,基本可以使用FlexBox布局,但是仅仅看这里的介绍还是难以解决一些布局问题,本篇文章不再介绍 FlexBox 和 YogaKit 的相关知识和概念,直奔主题实践,旨在通过案例帮助更好的解决问题。
在学习FlexBox布局的时候,为了加深理解建议学习一下CSS,理解盒子模型、外边距、内边距、定位、定位上下文及相对定位和绝对定位的区别,能够帮助我们更好的理解FlexBox,更好的使用YogaKit。
案例一:
如下图,这种布局很常见,实现的方法也有很多,使用YogaKit实现也有很多方法,但是优雅程度不同。
首先,使用 preservingOrigin 可以勉强实现这一布局,但是代码显得不规整,作为一种布局方法,我直接摒弃。
let blueView = UIView(frame: .zero) blueView.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 layout.marginTop = 60 } view.addSubview(blueView) let imageView = UIImageView(frame: .zero) imageView.configureLayout { (layout) in layout.isEnabled = true layout.height = 100 layout.marginTop = 10 } view.addSubview(imageView) view.yoga.applyLayout(preservingOrigin: true) imageView.yoga.applyLayout(preservingOrigin: false) 复制代码
其次,使用 margin 属性,将其赋负值也可以轻易实现此效果, 然而这些都不是重点
let blueView = UIView(frame: .zero) blueView.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 layout.marginTop = 60 } view.addSubview(blueView) let imageView = UIImageView(frame: .zero) imageView.configureLayout { (layout) in layout.isEnabled = true layout.height = 100 layout.aspectRatio = 1 layout.marginTop = -50 layout.alignSelf = .center } blueView.addSubview(imageView) view.yoga.applyLayout(preservingOrigin: true) 复制代码
问题1:YogaKit是布局流式布局的利器,在使用的时候会发现整个布局都是根据内容依次堆叠,在如图的布局样式中,如果要把 imageView 放到蓝色背景的底部,此时就无法使用 marginBottom 来完成。
解决这个问题首先想到的是通过调整父视图的内容布局属性来完成。
let blueView = UIView(frame: .zero) blueView.backgroundColor = .blue blueView.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 layout.marginTop = 60 layout.justifyContent = .flexEnd } view.addSubview(blueView) 复制代码
问题2:如果仅仅通过修改 layout.justifyContent = .flexEnd 来解决此问题就会引起新的问题,就是说会影响蓝色View中的其他内容,所有内容都以底部为起点开始布局,故此方案有部分影响,根据情况采纳。
其次的解决方法可以是用定位来处理,只能说不要太完美。
let blueView = UIView(frame: .zero) blueView.backgroundColor = .blue blueView.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 layout.marginTop = 60 layout.position = .relative } view.addSubview(blueView) let image = UIImageView(frame: .zero) image.backgroundColor = .yellow image.configureLayout { (layout) in layout.isEnabled = true layout.height = 100 layout.bottom = 0 layout.aspectRatio = 1 layout.alignSelf = .center layout.position = .absolute } blueView.addSubview(image) view.yoga.applyLayout(preservingOrigin: true) 复制代码
案例二:
在项目中可能会遇到这种布局,使用YogaKit中的FlexWrap能更方便的解决item(图中圆角方块)换行问题,但是也存在一些问题,如图所示,为了便于说明做以下命名,图中深色圆角方块为 item ,图中图片为 image ,图中包裹 item 的边框为 wrapper ,整体为 cell
在此中样式的 cell 中,我们希望 image 按比例位于 cell 的最右边,所以 wrapper 的 flexGrow 设为 1,可以将 image 挤到最右边; wrapper 中的 item 要换行,所以 wrapper 的 flexWrap 设为 wrap ,核心代码如下:
cell.configureLayout { (layout) in layout.isEnabled = true layout.flexDirection = .row } let wrapper = UIView(frame: .zero) wrapper.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 layout.flexDirection = .row } cell.addSubview() let image = UIImageView(frame: .zero) image.configureLayout { (layout) in layout.isEnabled = true layout.width = 140 layout.aspectRatio = 1 } cell.addSubview(image) for _ in 0..<8 { let item = UILabel(frame: .zero) item.configureLayout { (layout) in layout.isEnabled = true layout.marginHorizontal = 8 layout.marginVertical = 5 layout.width = 60 layout.height = 30 } wrapper.addSubview(item) } 复制代码
问题1:仅仅如此是不够的,运行会看到 image 被挤出屏幕外边,而且 item 们也没有折行,显然 wrapper 被内容撑开,未达到预期样式。
子视图会影响俯视图的大小,使用 flexWrap 属性可以让子视图折行,但是前提是要给父视图一个明确的宽度。
let maxWidth = YGValue(view.bounds.size.width - 140) wrapper.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 layout.flexDirection = .row layout.width = maxWidth } 复制代码
问题2:在给定 wrapper 一个宽度后,貌似可以完美解决问题,但是前提是需要计算宽度,不够优雅,在一个宽度不固定的容器内显然不能使用此方法。
要解决此问题就要用到 position 属性, position 有两个值: .relative 相对定位 和 .absolute 绝对定位,相对定位可以作为绝对定位的定位上下文,决定绝对定位的参照物,如果没有定位上下文默认参照物为根视图。使用绝对定位使得该视图脱离布局流,位置相对于父视图,不会影响父视图大小。在 wrapper 中再添加一个 rapWrapper 来承载 item 。
let wrapper = UIView(frame: .zero) wrapper.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 layout.position = .relative } cell.addSubview(wrapper) let rapWrapper = UIView(frame: .zero) rapWrapper.backgroundColor = .gray rapWrapper.configureLayout { (layout) in layout.isEnabled = true layout.flexWrap = .wrap layout.flexDirection = .row layout.position = .absolute } wrapper.addSubview(rapWrapper) 复制代码
for _ in 0..<8 { let item = UILabel(frame: .zero) item.configureLayout { (layout) in layout.isEnabled = true layout.marginHorizontal = 8 layout.marginVertical = 5 layout.width = 60 layout.height = 30 } rapWrapper.addSubview(item) } 复制代码
案例三:
同样是简单的布局,使用YogaKit也很简单,然而简单是要付出代价的,正确的使用才能避免不必要的尴尬:sweat:
看上去如此简单的布局,用YogaKit的时候会感受到它的"魔性",前提是要正确的使用。
首先想到的布局方法是 scrollView 使用 flexGrow 充满,将 button 挤到底部,而 scrollView 的 contentSize 也不用计算了,在内部加一个 contentView 负责填充内容,撑开 scrollView 即可,简单到堪称完美。
let scrollView = UIScrollView(frame: .zero) scrollView.backgroundColor = .blue scrollView.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 } view.addSubview(scrollView) let contentView = UIView(frame: .zero) contentView.configureLayout { (layout) in layout.isEnabled = true layout.height = 300 } scrollView.addSubview(contentView) let button = UIView(frame: .zero) button.backgroundColor = .yellow button.configureLayout { (layout) in layout.isEnabled = true layout.height = 50 } view.addSubview(button) view.yoga.applyLayout(preservingOrigin: true) scrollView.contentSize.height = contentView.bounds.size.height 复制代码
问题1:看似很简单的布局,也为以后出错埋下了伏笔,当 contentView 的高度小时还看不出问题,但是当 contentView 的高度大于屏幕高度时,问题出现了, scrollView 不能滑动, button 也被挤到了屏幕外面。
contentView.configureLayout { (layout) in layout.isEnabled = true layout.height = 900 } 复制代码
如此,解决办法也就显而易见了,没错,使用定位解决问题。
let scrollView = UIScrollView(frame: .zero) scrollView.backgroundColor = .blue scrollView.configureLayout { (layout) in layout.isEnabled = true layout.flexGrow = 1 layout.position = .relative } view.addSubview(scrollView) let contentView = UIView(frame: .zero) contentView.configureLayout { (layout) in layout.isEnabled = true layout.height = 900 layout.position = .absolute } scrollView.addSubview(contentView) let button = UIView(frame: .zero) button.backgroundColor = .yellow button.configureLayout { (layout) in layout.isEnabled = true layout.height = 50 } view.addSubview(button) view.yoga.applyLayout(preservingOrigin: true) scrollView.contentSize.height = contentView.bounds.size.height 复制代码
末尾:
不知道使用YogaKit的同学有多少,也没有看到有介绍 position 的文章,我也是通过阅读了「CSS权威指南」后才尝试使用 position 的,同时对于 overflow 的使用还是不得而知,希望有懂的大神告诉我一下!有写的不对的地方,还请慷慨指出!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- [译] 通过实现 25 个数组方法来理解及高效使用数组方法
- AWK简单使用方法
- python 内置函数使用方法
- 栈和帧指针使用方法
- Golang Label使用方法
- c# – 为什么委托在静态方法中使用时不能引用非静态方法?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript编程精解
Marijn Haverbeke / 徐涛 / 机械工业出版社华章公司 / 2012-10-1 / 49.00元
如果你只想阅读一本关于JavaScript的图书,那么本书应该是你的首选。本书由世界级JavaScript程序员撰写,JavaScript之父和多位JavaScript专家鼎力推荐。本书适合作为系统学习JavaScript的参考书,它在写作思路上几乎与现有的所有同类书都不同,打破常规,将编程原理与运用规则完美地结合在一起,而且将所有知识点与一个又一个经典的编程故事融合在一起,读者可以在轻松的游戏式......一起来看看 《JavaScript编程精解》 这本书的介绍吧!