SwiftUI - Размещение двух сборщиков рядом в HStack не изменяет размер сборщиков

Моя цель - расположить два сборщика рядом друг с другом горизонтально, чтобы каждый сборщик занимал половину ширины экрана. Представь себе UIPickerView это соответствует ширине экрана и имеет два компонента одинаковой ширины - это то, что я пытаюсь воссоздать в SwiftUI.

Поскольку средства выбора в SwiftUI в настоящее время не допускают использование нескольких компонентов, для меня очевидной альтернативой было просто разместить два средства выбора внутри HStack,

Вот пример кода из тестового проекта:

struct ContentView: View {
    @State var selection1: Int = 0
    @State var selection2: Int = 0

    @State var integers: [Int] = [0, 1, 2, 3, 4, 5]

    var body: some View {
        HStack {
            Picker(selection: self.$selection1, label: Text("Numbers")) {
                ForEach(self.integers) { integer in
                    Text("\(integer)")
                }
            }
            Picker(selection: self.$selection2, label: Text("Numbers")) {
                ForEach(self.integers) { integer in
                    Text("\(integer)")
                }
            }
        }
    }
}

А вот и холст:

SwiftUI - Сборщики в HStack

Подборщики не изменяют размеры, чтобы быть половиной ширины экрана, как я ожидал бы. Они сохраняют свой размер и вместо этого растягивают ширину представления контента, искажая ширину других элементов пользовательского интерфейса в процессе (как я узнал, когда попытался сделать это в моем другом проекте).

Я знаю, что я могу использовать UIViewRepresentable чтобы получить эффект, который я хочу, но SwiftUI будет гораздо проще использовать, учитывая сложность того, для чего я пытаюсь использовать это.

Это ошибка, что два сборщика внутри HStack неправильно изменяет их размер, или у пикеров в SwiftUI просто фиксированная ширина, которую нельзя изменить?


Обновить

С помощью GeometryReader Мне удалось приблизиться к изменению размеров сборщиков, как я хочу, но не полностью.

Примечание: вы также можете достичь такого же несовершенного результата, не используя GeometryReader просто установив рамку на каждом сборщике .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) ,

Вот пример кода:

struct ContentView: View {
    @State var selection1: Int = 0
    @State var selection2: Int = 0

    @State var integers: [Int] = [0, 1, 2, 3, 4, 5]

    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: 0) {
                Picker(selection: self.$selection1, label: Text("Numbers")) {
                    ForEach(self.integers) { integer in
                        Text("\(integer)")
                    }
                }
                .frame(maxWidth: geometry.size.width / 2)
                Picker(selection: self.$selection2, label: Text("Numbers")) {
                    ForEach(self.integers) { integer in
                        Text("\(integer)")
                    }
                }
                .frame(maxWidth: geometry.size.width / 2)
            }
        }
    }
}

А вот и холст:

Сборщики в HStack с GeometryReader

Сборщики теперь ближе к желаемой внешности, но размеры все еще немного смещены, и теперь они накладываются друг на друга посередине.

3 ответа

Решение

Перекрытие в середине вы можете исправить, добавив модификатор clipped(). Что касается ширины, я вижу их обоих одинаково:

https://i.sta ck.imgur.com/9Un6I.png

struct ContentView: View {
    @State var selection1: Int = 0
    @State var selection2: Int = 0

    @State var integers: [Int] = [0, 1, 2, 3, 4, 5]

    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: 0) {
                Picker(selection: self.$selection1, label: Text("Numbers")) {
                    ForEach(self.integers) { integer in
                        Text("\(integer)")
                    }
                }
                .frame(maxWidth: geometry.size.width / 2)
                .clipped()
                .border(Color.red)

                Picker(selection: self.$selection2, label: Text("Numbers")) {
                    ForEach(self.integers) { integer in
                        Text("\(integer)")
                    }
                }
                .frame(maxWidth: geometry.size.width / 2)
                .clipped()
                .border(Color.blue)
            }
        }
    }
}

Начиная с iOS 15.5 (проверено на симуляторе), Xcode 13.4 в дополнение к добавлению .clipped() вам также необходимо добавить следующее расширение, чтобы предотвратить проблему перекрытия сенсорной области, упомянутую в комментариях из других ответов:

      extension UIPickerView {
    open override var intrinsicContentSize: CGSize {
        return CGSize(width: UIView.noIntrinsicMetric , height: 150)
    }
}

Просто поместите его перед структурой представления, где вы используете средство выбора.

Источник: TommyL на форуме Apple:https://developer.apple.com/forums/thread/687986?answerId=706782022#706782022 .

0

для предотвращения перекрытия в xcode13 просто добавьте

      .compositingGroup()

затем добавьте

      .clipped()
Другие вопросы по тегам