YogaKit中 position 的使用方法

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

内容简介:这里有一篇关于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 的使用还是不得而知,希望有懂的大神告诉我一下!有写的不对的地方,还请慷慨指出!


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

查看所有标签

猜你喜欢:

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

Web API的设计与开发

Web API的设计与开发

[日] 水野贵明 / 盛荣 / 人民邮电出版社 / 2017-6 / 52.00元

本书结合丰富的实例,详细讲解了Web API的设计、开发与运维相关的知识。第1章介绍Web API的概要;第2章详述端点的设计与请求的形式;第3章介绍响应数据的设计;第4章介绍如何充分利用HTTP协议规范;第5章介绍如何开发方便更改设计的Web API;第6章介绍如何开发牢固的Web API。 本书不仅适合在工作中需要设计、开发或修改Web API的技术人员阅读,对想了解技术细节的产品经理、运维人......一起来看看 《Web API的设计与开发》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具