iOS/SwiftUI
SwiftUI size rendering algorithm
HaningYa
2020. 10. 26. 13:27
728x90
SwiftUI 에서 size 를 결정하는 방식은 UIKit 과 다르다.
UIKit 은 parentView 를 기준으로 childView 의 size를 결정하는 반면
SwiftUI는 childView를 기준으로 parentView 가 resizing 될 수 있다.
(물론 parentView 가 몇가지 size를 child 에게 제안한다.)
순서대로 나열해 보자면
1. The parent view determines the available frame at its disposal.
본인이 제공가능한 view size 계산해서
2. The parent view proposes a size to the child view.
그걸 child 에게 제안한다.
3. Based on the proposal from the parent, the child view chooses its size.
그 제안에 따라서 child 가 size 결정한다.
4. The parent view sizes itself such that it contains its child view.
parent 가 그 사이즈에 맞게 본인 사이즈를 바꾼다.
This process is recursive, starting at the root view, down to the last leaf view in the view hierarchy.
이 과정은 재귀적으로 view 계층에서 마지막 view가 생성될 때 까지 진행된다.
이 알고리즘대로 코드를 짜봤다.
import UIKit
// view 를 2차원 배열로 나타냄
// 0은 사용가능 한 view
// 0아닌 정수는 (1,2,3,4...) 각각의 다른 view 를 뜻함
// 이미 0,1 과 7,8에 view 가 있다고 가정
var parent : [Int] = [1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0]
//스크린 출력
func printScreen(_ layout : [Int]) {
for item in layout {
print(item, terminator : "")
}
print("")
}
//입력된 view 에 대한 가능한 size 정보반환
func returnAvailableSize(_ layout : [Int]) -> [[Int]] {
var availablePos : [[Int]] = [[]]
var state = false
var tmp : [Int] = []
for i in 0..<layout.count {
if layout[i] == 0 {
state = true
tmp.append(i)
}else {
state = false
}
if i == layout.count-1 {
state = false
}
if state == false && tmp.count != 0 {
availablePos.append(tmp)
tmp.removeAll()
}
}
//배치 가능한 index 배열을 준다.
availablePos.removeFirst()
return availablePos
}
//가증한 size에서 랜덤으로 child 에게 제시할 size 를 반환 (start, end)
func proposeView(_ layout : [[Int]] ) -> (Int, Int){
let sizepick = layout.randomElement()!
var startIndex = sizepick.randomElement()!
var endIndex = sizepick.randomElement()!
startIndex = min(startIndex,endIndex)
endIndex = max(startIndex,endIndex)
return (startIndex,endIndex)
}
//child 가 제시된 size에서 본인이 moreSize만큼 필요하면 더 size를 요구함
//more size는 0에서 10사이 랜덤값
func pickSize(_ tuple : (Int,Int),_ moreSize : Int) -> (Int,Int) {
let start = Int.random(in: tuple.0...tuple.1 + moreSize)
let end = Int.random(in: tuple.0...tuple.1 + moreSize)
return (min(start,end),max(start,end))
}
//해당 child 가 요구한 view 를 parent에게 반영, 더 큰 size를 요구하면 parent 의 size를 수정
func addSubView(_ subView : (Int,Int),_ viewID : Int){
let parentSize = parent.count
print("addSubView")
if subView.0 > parentSize-1 || subView.1 > parentSize-1 {
print("parentView resized")
//child 가 parent 보다 더큰 size 를 원한다면
let diff = subView.1 - parentSize + 1
print("need more size for child : \(diff)")
//차이만큼 size를 parent 에 추가
for _ in 0..<diff {
parent.insert(0, at: subView.0)
}
}
//해당 childview 를 parent 에 addsubView
for i in subView.0...subView.1 {
parent[i] = viewID
}
}
for i in 2..<9 {
print("parent view")
printScreen(parent)
print("available size")
print(returnAvailableSize(parent))
let tuple = proposeView(returnAvailableSize(parent))
print("proposed size")
print(tuple)
print("child picked size")
let childSize = pickSize(tuple,Int.random(in: 0...10))
print(childSize)
print("child add subView")
addSubView(childSize, i)
print("loop \(i) endeed")
printScreen(parent)
print("-------------------------------------------------------------------------------")
}
출력값
2부터 8까지 8개의 childview 를 populating 한다고 가정한다.
parent view
1100000110000000000000
available size
[[2, 3, 4, 5, 6], [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]]
proposed size
(9, 9)
child picked size
(9, 10)
child add subView
addSubView
loop 2 endeed
1100000112200000000000
-------------------------------------------------------------------------------
- parent view 를 출력한다.
- parent view 에서 사용 가능한 view size 를 2차원 배열로 리턴한다.
- 사용 가능한 size 에서 child 에게 제안할 size를 골랐다.
- 그 size 내부에서 child 가 본인의 사이즈를 선택한다.
- 선택한 사이즈를 parent view 에 표시한다. (parent view 보다 크면 parent view size 가 커진다.)
- 2 loop 가 끝나고 9, 10 번째에 view 2 가 들어가있다.
parent view
1100000112200000000000
available size
[[2, 3, 4, 5, 6], [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]]
proposed size
(19, 19)
child picked size
(19, 27)
child add subView
addSubView
parentView resized
need more size for child : 6
loop 3 endeed
1100000112200000000333333333
-------------------------------------------------------------------------------
- parent view 를 출력한다.
- parent view 에서 사용 가능한 view size 를 2차원 배열로 리턴한다.
- 사용 가능한 size 에서 child 에게 제안할 size를 골랐다.
- 그 size 내부에서 child 가 본인의 사이즈를 선택한다. 여기서는 parent view 보다 큰 size를 원하고 있다.
imageView native resolution과 같이 - 선택한 사이즈를 parent view 에 표시한다. (parent view 보다 크면 parent view size 가 커진다.)
- 2 loop 가 끝나고 19에서 27까지 view 3 가 들어가있다.
parent view
1100000112200000000333333333
available size
[[2, 3, 4, 5, 6], [11, 12, 13, 14, 15, 16, 17, 18]]
proposed size
(13, 18)
child picked size
(19, 22)
child add subView
addSubView
loop 4 endeed
1100000112200000000444433333
-------------------------------------------------------------------------------
parent view
1100000112200000000444433333
available size
[[2, 3, 4, 5, 6], [11, 12, 13, 14, 15, 16, 17, 18]]
proposed size
(2, 6)
child picked size
(3, 7)
child add subView
addSubView
loop 5 endeed
1105555512200000000444433333
-------------------------------------------------------------------------------
parent view
1105555512200000000444433333
available size
[[2], [11, 12, 13, 14, 15, 16, 17, 18]]
proposed size
(2, 2)
child picked size
(3, 6)
child add subView
addSubView
loop 6 endeed
1106666512200000000444433333
-------------------------------------------------------------------------------
parent view
1106666512200000000444433333
available size
[[2], [11, 12, 13, 14, 15, 16, 17, 18]]
proposed size
(11, 11)
child picked size
(11, 13)
child add subView
addSubView
loop 7 endeed
1106666512277700000444433333
-------------------------------------------------------------------------------
parent view
1106666512277700000444433333
available size
[[2], [14, 15, 16, 17, 18]]
proposed size
(15, 16)
child picked size
(16, 20)
child add subView
addSubView
loop 8 endeed
1106666512277700888884433333
-------------------------------------------------------------------------------
728x90