YogaKit中 position 的使用方法

栏目: CSS · 发布时间: 5年前

内容简介:这里有一篇关于YogaKit使用方法的翻译文章,其中介绍的比较全面,基本可以使用FlexBox布局,但是仅仅看这里的介绍还是难以解决一些布局问题,本篇文章不再介绍在学习FlexBox布局的时候,为了加深理解建议学习一下CSS,理解盒子模型、外边距、内边距、定位、定位上下文及相对定位和绝对定位的区别,能够帮助我们更好的理解FlexBox,更好的使用YogaKit。如下图,这种布局很常见,实现的方法也有很多,使用YogaKit实现也有很多方法,但是优雅程度不同。

这里有一篇关于YogaKit使用方法的翻译文章,其中介绍的比较全面,基本可以使用FlexBox布局,但是仅仅看这里的介绍还是难以解决一些布局问题,本篇文章不再介绍 FlexBoxYogaKit 的相关知识和概念,直奔主题实践,旨在通过案例帮助更好的解决问题。

在学习FlexBox布局的时候,为了加深理解建议学习一下CSS,理解盒子模型、外边距、内边距、定位、定位上下文及相对定位和绝对定位的区别,能够帮助我们更好的理解FlexBox,更好的使用YogaKit。

案例一:

如下图,这种布局很常见,实现的方法也有很多,使用YogaKit实现也有很多方法,但是优雅程度不同。

YogaKit中 position 的使用方法

首先,使用 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

YogaKit中 position 的使用方法

在此中样式的 cell 中,我们希望 image 按比例位于 cell 的最右边,所以 wrapperflexGrow 设为 1,可以将 image 挤到最右边; wrapper 中的 item 要换行,所以 wrapperflexWrap 设为 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中 position 的使用方法

看上去如此简单的布局,用YogaKit的时候会感受到它的"魔性",前提是要正确的使用。

首先想到的布局方法是 scrollView 使用 flexGrow 充满,将 button 挤到底部,而 scrollViewcontentSize 也不用计算了,在内部加一个 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 的使用还是不得而知,希望有懂的大神告诉我一下!有写的不对的地方,还请慷慨指出!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

关乎天下

关乎天下

关明生 / 学林出版社 / 2005-8 / 8.00元

《关乎天下:中小企业赢取江山的秘诀》收录了作者多年在大企业(如阿里巴巴网站)从事管理基层得到的经验,可为众多中小企业提供招贤纳士和销售管理方面的新思路。一起来看看 《关乎天下》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器