简体   繁体   中英

SwiftUI HStack with GeometryReader and paddings

In my iOS App i want to place two views of the same width so that they fill the entire width of the parent view.

For this I use GeometryReader and it broke auto layout. But auto layout does not work and the height of this view is not calculated automatically. Height of TestView is not determined, so i cant add frame size manually...

Here's what it should look like (what i expect TestView ):

测试视图

This is what it looks like when I put a view on a list ( CurrenciesView ):

货币视图

TestView.swift

struct TestView: View {
    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: 0) {
                VStack(alignment: .leading, spacing: 0.0) {
                    Text("Name 1\n Test second name 2")
                        .font(.system(size: 18))
                        .fontWeight(.bold)
                    HStack {
                        Text("123")
                        Text(" + 5")
                    }
                }
                .padding(.horizontal, 12.0)
                .padding(.vertical, 9.0)
                .frame(width: geometry.size.width / 2)
                .background(RoundedRectangle(cornerRadius: 8.0)
                .foregroundColor(Color.blue
                                    .opacity(0.2)))

                VStack(alignment: .leading, spacing: 0.0) {
                    Text("Name 1")
                        .font(.system(size: 18))
                        .fontWeight(.bold)
                    HStack {
                        Text("123")
                        Text(" + 5")
                    }
                }
                .padding(.horizontal, 12.0)
                .padding(.vertical, 9.0)
                .frame(width: geometry.size.width / 2)
                .background(RoundedRectangle(cornerRadius: 8.0)
                .foregroundColor(Color.blue
                                    .opacity(0.2)))
            }
        }

    }
}

CurrenciesView.swift

struct CurrenciesView: View {

    @State private var items: [Str] = (0..<5).map { i in

       return Str(title: "Struct  #\(i)")

    }

    var body: some View {
        NavigationView {
                    List {
                        Section(header:
                        TestView().listRowInsets(EdgeInsets())
                        ) {
                            ForEach(items) { item in
                                Text("asd")
                            }
                        }.clipped()

                    }
                    .navigationBarTitle("Section Name")
                    .navigationBarItems(trailing: EditButton())
                }
    }
}

You can create a custom PreferenceKey and a view that calculates it:

struct ViewSizeKey: PreferenceKey {
    static var defaultValue: CGSize = .zero

    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
        value = nextValue()
    }
}
struct ViewGeometry: View {
    var body: some View {
        GeometryReader { geometry in
            Color.clear
                .preference(key: ViewSizeKey.self, value: geometry.size)
        }
    }
}

Then, you can use them in your views. Note that you need to use @Binding in the TestView and @State private var headerSize in the parent view. Otherwise the parent view won't be refreshed and the List won't re-calculate the header size properly.

struct CurrenciesView: View {
    @State private var items: [String] = (0 ..< 5).map(String.init)
    @State private var headerSize: CGSize = .zero

    var body: some View {
        NavigationView {
            List {
                Section(header:
                    TestView(viewSize: $headerSize)
                ) {
                    ForEach(items, id: \.self) {
                        Text($0)
                    }
                }.clipped()
            }
            .navigationBarTitle("Section Name")
            .navigationBarItems(trailing: EditButton())
        }
    }
}
struct TestView: View {
    @Binding var viewSize: CGSize

    var body: some View {
        HStack(spacing: 0) {
            VStack(alignment: .leading, spacing: 0.0) {
                Text("Name 1\n Test second name 2")
                    .font(.system(size: 18))
                    .fontWeight(.bold)
                HStack {
                    Text("123")
                    Text(" + 5")
                }
            }
            .padding(.horizontal, 12.0)
            .padding(.vertical, 9.0)
            .frame(width: viewSize.width / 2)
            .background(RoundedRectangle(cornerRadius: 8.0)
                .foregroundColor(Color.blue
                    .opacity(0.2)))

            VStack(alignment: .leading, spacing: 0.0) {
                Text("Name 1")
                    .font(.system(size: 18))
                    .fontWeight(.bold)
                HStack {
                    Text("123")
                    Text(" + 5")
                }
            }
            .padding(.horizontal, 12.0)
            .padding(.vertical, 9.0)
            .frame(width: viewSize.width / 2)
            .background(RoundedRectangle(cornerRadius: 8.0)
                .foregroundColor(Color.blue
                    .opacity(0.2)))
        }
        .frame(maxWidth: .infinity)
        .background(ViewGeometry()) // calculate the view size
        .onPreferenceChange(ViewSizeKey.self) {
            viewSize = $0 // assign the size to `viewSize`
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM