Yoga flexbox (CSS Flexbox 라는 것의 구현체)에 Swift Interface를 추가시킨 Layout Framework
FlexLayout은 PinLayout와 같이 쓰인다.
PinLayout은 CSS의 absolute Positioning(절대 위치 포지셔닝)에 기반한 layout 프레임워크이다. 더 유연하고 애니메이션에 유용하게 쓰인다.
Flexbox Container를 만드는 법
1. Container를 만든다.
.
2. Container를 Layout 한다.
정리
1. Container View를 만든다.
2. Container View.flex.define { ... } 으로 Child의 배치를 넣어준다.
3. layoutSubviews(), willTransition(to:), viewWillTransition(to: ..) 함수에서 Container View를 layout 시킨다. (Pin이던 Flex던 Auto던) layout시킬 때 위치나 크기를 설정한다.
4. FlexLayout의 layout() 메서드를 이용해 FlexBox의 자식들을 배치시킨다.
fileprivate let rootFlexContainer = UIView()
init() {
super.init(frame: .zero)
addSubview(rootFlexContainer)
...
// Column container
rootFlexContainer.flex.direction(.column).padding(12).define { (flex) in
// Row container
flex.addItem().direction(.row).define { (flex) in
flex.addItem(imageView).width(100).aspectRatio(of: imageView)
// Column container
flex.addItem().direction(.column).paddingLeft(12).grow(1).define { (flex) in
flex.addItem(segmentedControl).marginBottom(12).grow(1)
flex.addItem(label)
}
}
flex.addItem().height(1).marginTop(12).backgroundColor(.lightGray)
flex.addItem(bottomLabel).marginTop(12)
}
}
override func layoutSubviews() {
super.layoutSubviews()
// 1) Layout the flex container. This example use PinLayout for that purpose, but it could be done
// also by setting the rootFlexContainer's frame:
// rootFlexContainer.frame = CGRect(x: 0, y: 0,
// width: frame.width, height: rootFlexContainer.height)
rootFlexContainer.pin.top().left().width(100%).marginTop(topLayoutGuide)
// 2) Then let the flexbox container layout itself. Here the container's height will be adjusted automatically.
rootFlexContainer.flex.layout(mode: .adjustHeight)
}
direction
addItem(: UIView)
aspectRatio
grow
Margin, Padding 차이
layout(mode: )
/*
스크롤뷰 + 플렉스 뷰
*/
final class Example2View: UIView {
private let scrollView = UIScrollView()
private let rootFlexContainerView = UIView()
private let imageView: UIImageView = {
let view = UIImageView()
view.image = UIImage(systemName: "star.fill")
return view
}()
private let imageView2: UIImageView = {
let view = UIImageView()
view.image = UIImage(systemName: "star.fill")
return view
}()
private let imageView3: UIImageView = {
let view = UIImageView()
view.image = UIImage(systemName: "star.fill")
return view
}()
private let starImageView: UIImageView = {
let view = UIImageView()
view.image = UIImage(systemName: "star.fill")
return view
}()
private let yearlabel: UILabel = {
let label = UILabel()
label.text = "2010"
label.font = .boldSystemFont(ofSize: 50.0)
return label
}()
private let ratinglabel: UILabel = {
let label = UILabel()
label.text = "TV-14"
label.font = .boldSystemFont(ofSize: 50.0)
return label
}()
private let seriesLabellabel: UILabel = {
let label = UILabel()
label.text = "3-Series"
label.font = .boldSystemFont(ofSize: 50.0)
return label
}()
private let label: UILabel = {
let label = UILabel()
label.text = "투썸플레이스"
return label
}()
init() {
super.init(frame: .zero)
// MARK: --
/**
backgroundColory
- 배경
justifyContent
- flex Container의 현재 줄(main-axis)을 따라 정렬을 정의한다.
- flex Container의 모든 Child들이 최대 크기에 도달한 경우 남은 여분의 빈 공간을 어떻게 배분할지 결정한다.
- flex-start (시작점 정렬)
- flex-end (끝점 정렬)
- space between (양 끝 정렬 후 중간 균등 정렬)
- space around (아이템 주위에 균등한 간격)
*/
rootFlexContainerView.flex.direction(.column).define { (flex) in
// 이미지
flex.addItem(imageView).width(100%).aspectRatio(of: imageView).backgroundColor(.lightGray)
// summary row
flex.addItem().direction(.row).padding(5.0).define { (flex) in
flex.addItem(starImageView).width(20%).aspectRatio(of: imageView)
// 년 - 시리즈 - 시리즈
flex.addItem().direction(.row).justifyContent(.spaceBetween).grow(2.0).define { (flex) in
flex.addItem(yearlabel)
flex.addItem(ratinglabel)
flex.addItem(seriesLabellabel)
}
flex.addItem().width(100.0).height(1.0)
}
flex.addItem(imageView2).width(100%).aspectRatio(of: imageView).backgroundColor(.lightGray)
flex.addItem(imageView3).width(100%).aspectRatio(of: imageView).backgroundColor(.lightGray)
}
scrollView.addSubview(rootFlexContainerView)
addSubview(scrollView)
}
override func layoutSubviews() {
super.layoutSubviews()
// 1. scrollView와 ContainerView를 레이아웃
scrollView.pin.all(pin.safeArea)
rootFlexContainerView.pin.top().left().right()
// 2. FlexContainer안의 Child들 배치
rootFlexContainerView.flex.layout(mode: .adjustHeight)
// 3. adjust the scrollView contentSize
scrollView.contentSize = rootFlexContainerView.frame.size
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
backgroundColor
justfyContent
스크롤뷰 안에 플렉스 컨테이너 뷰를 넣을 때에는
override func layoutSubviews() {
super.layoutSubviews()
// 1. scrollView와 ContainerView를 레이아웃
scrollView.pin.all(pin.safeArea)
rootFlexContainerView.pin.top().left().right()
// 2. FlexContainer안의 Child들 배치
rootFlexContainerView.flex.layout(mode: .adjustHeight)
// 3. adjust the scrollView contentSize
scrollView.contentSize = rootFlexContainerView.frame.size
}
ScrollView의 ContentSize를 정의해주는것이 중요하다.
Is there anything I need to be careful about when using FlexLayout and PinLayout together? geometry dash subzero asks.