#swiftui
#swiftui
Вопрос:
У меня есть представление SwiftUI в an HStack
, которое будет шире, чем его родительское. Когда это происходит, HStack
он расширяется в обоих leading
trailing
направлениях и, несмотря на то, что он помещен в a VStack
с alignment
установленным значением .leading
(что, как я надеялся, закрепит leading
ребро).
Рассмотрим следующий упрощенный код игровой площадки:
import SwiftUI
import PlaygroundSupport
struct TestView : View {
var body: some View {
VStack {
VStack(alignment: .leading) {
HStack {
Rectangle()
.foregroundColor(Color.red)
.frame(width: 20)
Rectangle()
.foregroundColor(.green)
}.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 200)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 200)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
}
.border(Color.red)
}
.frame(width: 300, height: 400)
.border(Color.black)
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = UIHostingController(rootView: TestView())
В приведенном выше примере все помещается в представление и ведет себя так, как ожидалось:
Однако измените последний зеленый Rectangle
цвет на width
из 500
вместо 200
, и произойдет следующее:
Вы можете видеть, что оранжевое начало Rectangle
исчезло, сдвинуто влево. Аналогично, желтый Rectangle
в конце был сдвинут вправо.
Я хотел бы, чтобы произошел Rectangle
видимый оранжевый цвет, что означает, что все 3 HStack
s будут иметь одинаковое x
происхождение (0). Таким образом, результатом будет видеть оранжевый прямоугольник слева, зеленый видимый, но перетекающий вправо, а желтый невидимый, поскольку он будет удален с экрана.
Я предполагаю, что это может быть связано с использованием clipped()
или fixedSize
, но я пока не смог найти рабочее решение.
Комментарии:
1. Итак, если я правильно понимаю, вы хотите, чтобы все 3 записи всегда были видны независимо от их размера, у зеленой записи может быть 200 или 500 или 1000, вы хотите видеть их всегда?
2. Нет — при зеленом прямоугольнике шириной 500 оранжевый должен быть виден слева, зеленый будет частично виден и растечется вправо, а желтый исчезнет с экрана
Ответ №1:
Самое простое решение (никаких обходных путей или других представлений не требуется) — установить alignment
в модификаторе фрейма outer VStack
.leading
значение, подобное этому:
struct TestView : View {
var body: some View {
VStack {
VStack(alignment: .leading) {
HStack {
Rectangle()
.foregroundColor(Color.red)
.frame(width: 20)
Rectangle()
.foregroundColor(.green)
}.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 200)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 500)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
}
.border(Color.red)
}
.frame(width: 300, height: 400, alignment: .leading) //<= here
.border(Color.black)
}
}
Комментарии:
1. Это умное решение! Однако, как вы признали, это несколько банально и имеет побочные эффекты, такие как тот факт, что
disabled
он будет передаваться дочерним элементам. Итак, я не смог бы иметь интерактивные элементы внутри. Вы сказали, что у вас могут быть другие идеи?2. @jn_pdx обновил мой ответ другим решением. Дайте мне знать, подходит ли это вашему варианту использования. Иногда программы GeometryReaders ведут себя очень плохо в ScrollViews и представлениях с динамическим размером. Так что, возможно, я смогу найти другие решения, основанные только на базовых представлениях, таких как V / HStacks и paddings.
3. Ваше последнее решение не работает с SIGABRT на игровой площадке (Xcode 12.1)
4. @jn_pdx ну, я тестировал его только в полном проекте Xcode (12.1 и 12.2b4). Требуется ли запускать его на игровой площадке? Ха-ха, я нашел решение!! Дайте мне один момент, чтобы обновить мой ответ
5. Нет, не требуется, но одна вещь, которую я узнал с помощью SwiftUI, заключается в том, что если он выходит из строя в одном месте (например, на игровой площадке), он может выйти из строя в другом (например, Catalyst или определенная версия iOS). Только что увидел ваше обновленное решение. Вот и все!
Ответ №2:
struct TestView : View {
var body: some View {
VStack {
VStack(alignment: .leading) {
HStack {
Rectangle()
.foregroundColor(Color.red)
.frame(width: 20)
Rectangle()
.foregroundColor(.green)
}.frame(height: 40)
HStack {
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
Rectangle()
.foregroundColor(.green)
.frame(width: 200)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
}
.frame(height: 40)
HStack {
GeometryReader{_ in
Rectangle()
.foregroundColor(.orange)
.frame(width: 10)
.offset(x: 0)
Rectangle()
.foregroundColor(.green)
.frame(width: 500)
.offset(x: 10)
Rectangle()
.foregroundColor(.yellow)
.frame(width: 10)
.offset(x: 510)
}
}
.frame(height: 40)
}
.border(Color.red)
}
.frame(width: 300, height: 400)
.border(Color.black)
}
}
Комментарии:
1. Это довольно круто. Любой способ сделать это, если вы не знали размеры прямоугольников? Если бы они имели динамический размер, вы не смогли бы установить смещение для каждого элемента, верно?
2. Правильно, SwiftUI использует предустановленные инженерами Apple коды для наших рендеров, например, внутри Hstack или Vstack, если они вас не устраивают, вы можете использовать свой собственный дизайн с темой геометрии, это очень продвинутый и сложный инструмент, вы должны быть уверены, как его использовать и обрабатывать, в противном случае используйтепросто HStack или Vstack. .
3. Хорошо. Подожду, пока кто-нибудь придумает что-то, что может обрабатывать представления с динамическим размером, но если нет, я думаю, у вас это есть
4. Я думаю, вы не поняли геометрию, геометрия не обрабатывает представления с динамическим размером, вы должны все рассказать об этом, парень, который это делает, — это HStack или VStack, когда вы работаете с геометрией, вы должны сами рассчитать эти вещи, это означает, что вам НУЖНО написать логику рендеринга дляэто
5. Я это абсолютно понимаю — я часто использую GeometryReader. Я просто не уверен, что нет решения a la
fixedSize
(на самом деле, противоположного этому) илиclipped
или настройки выравнивания, которая охватывает этот случай — например, ниже есть ответ, который делает это с помощью aScrollView
.