SwiftUI로 List의 height를 내용에 맞추어 동적으로 변화시킨다

10207 단어 SwiftSwiftUI
추기: NavigationView 안에서 잘 안 되는 경우가 있었습니다.

SwiftUI 로 List 의 높이를 내용에 맞추어 바꾸는 방법입니다.
아래 그림과 같이 List의 높이를 내용과 동일하게 합니다. (회색 부분은 List 배경입니다.)

높이 설정 전




높이 설정 후


List와 같은 방식으로 표시되는 (높이가 같음) VStack을 만들고 높이를 List로 설정합니다.
import SwiftUI
import Combine

struct Item: Identifiable {
    var id = UUID()
    var name:String
}

class ViewModel: ObservableObject {
    var items:[Item] = { (0..<2).map { i in Item(name: "item\(i)") } }()

    @Published var listHidden = true
    var listHeight:CGFloat = 0

    var publisher = PassthroughSubject<Bool, Never>()

    func setHeight(_ height: CGFloat) {
        listHeight = height
        // 5. List を表示
        listHidden = false
    }
}


struct MyView: View {
    @ObservedObject var viewModel = ViewModel()

    init() {
        // 分かりやすい用に List の背景色を付けます
        UITableView.appearance().backgroundColor = UIColor.lightGray
    }

    var body: some View {

        // 1. VStack の方が表示される
        if viewModel.listHidden {
            ZStack {
                VStack(spacing: 0) {
                    ForEach(viewModel.items) { item in
                        Row(item: item)
                    }
                }
                .background(
                    GeometryReader { geo in
                        Color.white
                            // 4. viewModel の listHeight に高さをセット
                            .onReceive(viewModel.publisher) { _ in
                                viewModel.setHeight(geo.size.height)
                            }
                    }
                )
                // 2. VStack が見えないようにする
                Color.white
            }
            // 3. 表示したら publisher から通知
            .onAppear { viewModel.publisher.send(true) }

        // 6. 表示される
        } else {
            List {
                ForEach(viewModel.items) { item in
                    Row(item: item)
                }
            }
            // 7. 高さを設定
            .frame(height: viewModel.listHeight)
        }
    }
}

struct Row: View {
    var item:Item
    var body: some View {
        Text(item.name)
            .listRowInsets(.init()) // 余白を消しておく
            .padding()
            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
            .background(Color.orange)
    }
}

struct MyView_Previews: PreviewProvider {
    static var previews: some View {
        MyView()
    }
}


버전
Swift 5.4

좋은 웹페이지 즐겨찾기