Заставить VStack заполнить ширину экрана в SwiftUI - PullRequest
6 голосов
/ 07 июня 2019

Учитывая этот код:

import SwiftUI

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Title")
                .font(.title)

            Text("Content")
                .lineLimit(nil)
                .font(.body)

            Spacer()
        }
        .background(Color.red)
    }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

Это приводит к следующему взаимодействию:

preview

Как я могу сделать VStack заполнить ширину экрана, даже если меткам / текстовым компонентам не нужна полная ширина?

Уловка, которую я нашел, состоит в том, чтобы вставить пустой HStack вструктура выглядит так:

VStack(alignment: .leading) {
    HStack {
        Spacer()
    }
    Text("Title")
        .font(.title)

    Text("Content")
        .lineLimit(nil)
        .font(.body)

    Spacer()
}

Что дает желаемый дизайн:

desired output

Есть ли лучший способ?

Ответы [ 5 ]

7 голосов
/ 07 июня 2019

Есть лучший способ!

Чтобы VStack заполнил ширину родительского элемента, вы можете использовать GeometryReader и установить рамку. (.relativeWidth(1.0) должно работать, но, видимо, сейчас не работает)

struct ContentView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("test")
            }
                .frame(width: geometry.size.width,
                       height: nil,
                       alignment: .topLeading)
        }
    }
}

Чтобы сделать VStack ширину реального экрана, вы можете использовать UIScreen.main.bounds.width при настройке рамки вместо GeometryReader, но я думаю, что вы, вероятно, хотели ширину родительского вида.

Кроме того, этот способ имеет дополнительное преимущество, заключающееся в том, что вы не добавляете интервал в VStack, что может произойти (если у вас есть интервал), если вы добавили HStack с Spacer() в качестве его содержимого к VStack.

ОБНОВЛЕНИЕ - НЕ ЛУЧШЕ!

После проверки принятого ответа я понял, что принятый ответ на самом деле не работает! На первый взгляд кажется, что он работает, но если вы обновите VStack, чтобы иметь зеленый фон, вы заметите, что VStack по-прежнему такой же ширины.

struct ContentView : View {
    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {
                Text("Hello World")
                    .font(.title)
                Text("Another")
                    .font(.body)
                Spacer()
                }
                .background(Color.green)
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
                .background(Color.red)
        }
    }
}

Это потому, что .frame(...) фактически добавляет другое представление в иерархию представлений, и это представление заканчивается заполнением экрана. Тем не менее, VStack по-прежнему нет.

Эта проблема, кажется, также совпадает с моим ответом и может быть проверена с использованием того же подхода, что и выше (установка различных цветов фона до и после .frame(...). Единственный способ, который, по-видимому, фактически расширяет VStack это использовать проставки:

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            HStack{
                Text("Title")
                    .font(.title)
                Spacer()
            }
            Text("Content")
                .lineLimit(nil)
                .font(.body)
            Spacer()
        }
            .background(Color.green)
    }
}
7 голосов
/ 07 июня 2019

Попробуйте использовать модификатор .frame со следующими параметрами:

.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: Alignment.topLeading)
    struct ContentView : View {
        var body: some View {
            VStack(alignment: .leading) {
                Text("Hello World")
                    .font(.title)
                Text("Another")
                    .font(.body)
                Spacer()
            }
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
            .background(Color.red)
        }
    }

Это описывается как гибкая рамка ( см. Документацию ), которая растягивается, чтобы заполнить весь экран, и когда у нее появляется дополнительное пространство, она центрирует свое содержимое внутри него.

2 голосов
/ 07 июня 2019

Альтернативное расположение стеков, которое работает и, возможно, немного более интуитивно понятно, заключается в следующем:

struct ContentView: View {
    var body: some View {
        HStack() {
            VStack(alignment: .leading) {
                Text("Hello World")
                    .font(.title)
                Text("Another")
                    .font(.body)
                Spacer()
            }
            Spacer()
        }.background(Color.red)
    }
}

Контент также можно легко переместить, удалив Spacer() при необходимости.

adding/removing Spacers to change position

1 голос
/ 07 июня 2019

Еще одна альтернатива - разместить одно из подпредставлений внутри HStack и поместить Spacer() после него:

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {

            HStack {
                Text("Title")
                    .font(.title)
                    .background(Color.yellow)
                Spacer()
            }

            Text("Content")
                .lineLimit(nil)
                .font(.body)
                .background(Color.blue)

            Spacer()
            }

            .background(Color.red)
    }
}

в результате:

HStack inside a VStack

0 голосов
/ 07 июня 2019

Вы можете сделать это, используя GeometryReader

GeometryReader

Код:

struct ContentView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
               Text("Turtle Rock").frame(width: geometry.size.width, height: geometry.size.height, alignment: .topLeading).background(Color.red)
            }
        }
    }
}

Ваш вывод как:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...