티스토리 뷰

반응형

FlowLayout

 

 

import SwiftUI

/// 컨텐츠 크기 만큼 아래로 배치 되는 레이아웃 iOS 16+
struct FlowLayout: Layout {
    var spacing: CGFloat? = nil
    var lineSpacing: CGFloat = 10.0 // 기본 줄 간격을 설정
    
    struct Cache {
        var sizes: [CGSize] = []
        var spacing: [CGFloat] = []
    }
    
    func makeCache(subviews: Subviews) -> Cache {
        let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
        let spacing: [CGFloat] = subviews.indices.map { index in
            guard index != subviews.count - 1 else {
                return 0
            }
            
            return subviews[index].spacing.distance(
                to: subviews[index+1].spacing,
                along: .horizontal
            )
        }
        
        return Cache(sizes: sizes, spacing: spacing)
    }
    
    func sizeThatFits(
        proposal: ProposedViewSize,
        subviews: Subviews,
        cache: inout Cache
    ) -> CGSize {
        var totalHeight = 0.0
        var totalWidth = 0.0
        
        var lineWidth = 0.0
        var lineHeight = 0.0
        
        for index in subviews.indices {
            if lineWidth + cache.sizes[index].width > proposal.width ?? 0 {
                totalHeight += lineHeight + lineSpacing // 줄 간격 추가
                lineWidth = cache.sizes[index].width
                lineHeight = cache.sizes[index].height
            } else {
                lineWidth += cache.sizes[index].width + (spacing ?? cache.spacing[index])
                lineHeight = max(lineHeight, cache.sizes[index].height)
            }
            
            totalWidth = max(totalWidth, lineWidth)
        }
        
        totalHeight += lineHeight
        
        return .init(width: totalWidth, height: totalHeight)
    }
    
    func placeSubviews(
        in bounds: CGRect,
        proposal: ProposedViewSize,
        subviews: Subviews,
        cache: inout Cache
    ) {
        var lineX = bounds.minX
        var lineY = bounds.minY
        var lineHeight: CGFloat = 0
        
        for index in subviews.indices {
            if lineX + cache.sizes[index].width > (proposal.width ?? 0) {
                lineY += lineHeight + lineSpacing // 줄 간격 추가
                lineHeight = 0
                lineX = bounds.minX
            }
            
            let position = CGPoint(
                x: lineX + cache.sizes[index].width / 2,
                y: lineY + cache.sizes[index].height / 2
            )
            
            lineHeight = max(lineHeight, cache.sizes[index].height)
            lineX += cache.sizes[index].width + (spacing ?? cache.spacing[index])
            
            subviews[index].place(
                at: position,
                anchor: .center,
                proposal: ProposedViewSize(cache.sizes[index])
            )
        }
    }
}

 

 

struct ContentView: View {
    
    let array = "다중 레이아웃을 사용하면 다양한 방식으로 뷰를 구성할 수 있습니다. 한 가지 중요한 것은 콘크리트 레이아웃의 하위 항목 사이의 간격입니다. 이번 주에 우리는 뷰 사이의 특정 간격을 지정할 수 있는 사용자 정의 레이아웃을 구축하는 방법과 SwiftUI에서 플랫폼 중심의 사전 정의된 간격 규칙을 준수하는 방법을 배울 것입니다.".split(separator: " ")
    
    var body: some View {
        VStack {
            FlowLayout(spacing: 10, lineSpacing: 10) {
                ForEach(array.indices, id: \.self) {
                    Text(array[$0])
                        .font($0.isMultiple(of: 2) ? .title : .title2)
                        .border(Color.red)
                }
            }
        }
    }
}



 

출처

https://swiftwithmajid.com/2022/11/16/building-custom-layout-in-swiftui-basics

https://swiftwithmajid.com/2022/12/06/building-custom-layout-in-swiftui-spacing

iOS

Swift

Xcode

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함