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