SwiftUI에서 VStack이 화면 너비를 채우도록합니다.


119

이 코드가 주어지면 :

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

다음과 같은 인터페이스가 발생합니다.

시사

VStack레이블 / 텍스트 구성 요소에 전체 너비가 필요하지 않은 경우에도 화면 너비를 채우 려면 어떻게 해야합니까?

내가 찾은 트릭 은 다음과 같이 구조에 을 삽입하는 HStack것입니다.

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

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

    Spacer()
}

원하는 디자인을 산출합니다.

원하는 출력

더 좋은 방법이 있습니까?


1
유사한 결과를 얻을 수있는 최대 5 개의 대체 방법을 보여주는 내 answser 를 참조하십시오 .
Imanou Petit

답변:


199

.frame 수정자를 다음 옵션과 함께 사용해보십시오.

.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, 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)
    }
}

이것은 전체 화면을 채우도록 확장되는 유연한 프레임 ( 문서 참조 )으로 설명되며 , 추가 공간이있을 때 내용을 중앙에 배치합니다.


파단이 왼쪽으로 정렬되지 않습니다 ( .leading). 이전에 배치하면 전체 너비를 취합니다..background(Color.red)
ielyamani 19.06.07

왼쪽에도 정렬하는 코드가 추가되었습니다. 지금 정확히 일치해야
svarrall

12
이것은 잘못된 것입니다. 는 .backgound(Color.red)상기 프레임의 전망을 배경 아닌 배경입니다 VStack프레임보기입니다. (그 이유는 WWDC 비디오에 설명되어 있습니다. : P). 당신이 넣으면 .background(Color.green)전과 .frame당신은 볼 것이다 VStack당신이 넣을 때 ... 여전히 프레임이 빨간색 배경을 가지고있는 동안 그 내용에 맞는 폭을 가지고 .frame(...), 그것은을 편집 아니에요 VStack, 사실은 다른 뷰를 생성합니다.
Jake

2
@Jake은 재앙처럼 보인다
Sudara

1
질문이 있으시면 : Alignment : .topLeading을 사용하는 이유 VStack (alignment : .leading) ?? 공유를위한 감사합니다
UIChris

36

작동하고 아마도 좀 더 직관적 인 대체 스태킹 배열은 다음과 같습니다.

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()필요한 경우의 를 제거하여 콘텐츠의 위치를 ​​쉽게 변경할 수도 있습니다 .

위치 변경을위한 스페이서 추가 / 제거


5
좋은 대안은 GIF 👍🏻Liked
ielyamani

1
나는 이것이 더 직관적이고 OP의 질문과 더 일치한다는 것을 알았습니다.이 질문은 요소 주위에 컨테이너를 삽입하는 방법보다 Stack 요소가 컨테이너를 채우는 방법에 관한 것입니다.
brotskydotcom

1
나는 이것이 SwiftUI의 아이디어와 일치하는 최상의 답변이라고 생각합니다
krummens

1
이러한 일반적인 레이아웃에 대한 가장 SwiftUI-y 답변입니다.
dead_can_dance

30

더 좋은 방법이 있습니다!

하려면 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(당신이 간격 않은 경우) 당신이 추가 한 경우 어떤 발생할 수 HStackA를을 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)
    }
}

시도했지만 relativeWidth작동하지 않았습니다. 어떻게 든 GeometryReader경우 작동 .frame앞에 위치.background(Color.red)
ielyamani

I 다음에 GeometryReader"수정 자 추가"를 수행 할 때 표시된 목록 Show SwiftUI Inspector이나 UI 내의 다른 위치 에서 볼 수 없습니다 . 어떻게 발견 GeometryReader했습니까?
사라짐

1
@gone-Stack Overflow :)
Jake

20

Swift 5.2 및 iOS 13.4를 사용하면 필요에 따라 다음 예제 중 하나를 사용 VStack하여 최상위 제약 조건 및 전체 크기 프레임 에 맞출 수 있습니다 .

아래의 코드 스 니펫은 모두 동일한 디스플레이를 표시하지만 뷰 계층을 디버깅하는 동안 나타날 VStack수있는 View요소 의 유효 프레임 이나 수를 보장하지는 않습니다 .


1. 사용 frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:)방법

가장 간단한 방법은 VStack최대 너비와 높이로 프레임을 설정 하고 필요한 정렬을 전달하는 것입니다 frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:).

struct ContentView: View {

    var body: some View {
        VStack(alignment: .leading) {
            Text("Title")
                .font(.title)
            Text("Content")
                .font(.body)
        }
        .frame(
            maxWidth: .infinity,
            maxHeight: .infinity,
            alignment: .topLeading
        )
        .background(Color.red)
    }

}

또는에 대해 특정 정렬을 사용하여 최대 프레임을 설정 View하는 것이 코드베이스의 일반적인 패턴 인 경우 확장 메서드를 만들 수 있습니다 View.

extension View {

    func fullSize(alignment: Alignment = .center) -> some View {
        self.frame(
            maxWidth: .infinity,
            maxHeight: .infinity,
            alignment: alignment
        )
    }

}

struct ContentView : View {

    var body: some View {
        VStack(alignment: .leading) {
            Text("Title")
                .font(.title)
            Text("Content")
                .font(.body)
        }
        .fullSize(alignment: .topLeading)
        .background(Color.red)
    }

}

2. Spacers를 사용 하여 강제 정렬

당신은 추가 할 수 있습니다 VStack내부의 전체 크기 HStack와 사용 후행과 하단 Spacer당신의 강제들 VStack최고 선두 정렬 :

struct ContentView: View {

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

                Spacer() // VStack bottom spacer
            }

            Spacer() // HStack trailing spacer
        }
        .frame(
            maxWidth: .infinity,
            maxHeight: .infinity
        )
        .background(Color.red)
    }

}

3. ZStack및 전체 크기 배경 사용View

이 예에서는 VStackZStack 상단 행간 정렬이있는 내부 . Color보기를 사용하여 최대 너비 및 높이를 설정 하는 방법에 유의하십시오 .

struct ContentView: View {

    var body: some View {
        ZStack(alignment: .topLeading) {
            Color.red
                .frame(maxWidth: .infinity, maxHeight: .infinity)

            VStack(alignment: .leading) {
                Text("Title")
                    .font(.title)
                Text("Content")
                    .font(.body)
            }
        }
    }

}

4. 사용 GeometryReader

GeometryReader다음과 같은 선언이 있습니다 .

콘텐츠를 자체 크기 및 좌표 공간의 함수로 정의하는 컨테이너보기입니다. [...]이보기는 부모 레이아웃에 유연한 선호 크기를 반환합니다.

아래 코드 스 니펫은 최상위 제약 조건 및 전체 크기 프레임 GeometryReader에 맞추는 데 사용하는 방법을 보여줍니다 VStack.

struct ContentView : View {

    var body: some View {
        GeometryReader { geometryProxy in
            VStack(alignment: .leading) {
                Text("Title")
                    .font(.title)
                Text("Content")
                    .font(.body)
            }
            .frame(
                width: geometryProxy.size.width,
                height: geometryProxy.size.height,
                alignment: .topLeading
            )
        }
        .background(Color.red)
    }

}

5. 사용 overlay(_:alignment:)방법

VStack기존 전체 크기 위에 상단 선행 제약 조건 을 맞추려면 다음 방법 View을 사용할 수 있습니다 overlay(_:alignment:).

struct ContentView: View {

    var body: some View {
        Color.red
            .frame(
                maxWidth: .infinity,
                maxHeight: .infinity
            )
            .overlay(
                VStack(alignment: .leading) {
                    Text("Title")
                        .font(.title)
                    Text("Content")
                        .font(.body)
                },
                alignment: .topLeading
            )
    }

}

디스플레이:


10

문제를 해결하는 가장 간단한 방법은 ZStack + .edgesIgnoringSafeArea (.all)를 사용하는 것입니다.

struct TestView : View {

    var body: some View {
        ZStack() {
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack {
                Text("Hello World")
            }
        }
    }
}


4

사용하여 할 수 있습니다. 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)
            }
        }
    }
}

출력은 다음과 같습니다.

여기에 이미지 설명 입력


4

"장치"가없는 좋은 솔루션은 잊혀진 것입니다. ZStack

ZStack(alignment: .top){
    Color.red
    VStack{
        Text("Hello World").font(.title)
        Text("Another").font(.body)
    }
}

결과:

여기에 이미지 설명 입력


3

또 다른 대안은 an 내부에 하위 뷰 중 하나를 HStack배치하고 그 Spacer()뒤에 a 를 배치하는 것입니다.

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)
    }
}

를 야기하는 :

VStack 내부의 HStack


1
이럴이 가장 우아한 솔루션입니다
뱌체슬라프

3

이것이 나를 위해 일한 것입니다 ( ScrollView(선택 사항) 필요한 경우 더 많은 콘텐츠와 중앙 콘텐츠를 추가 할 수 있습니다) :

import SwiftUI

struct SomeView: View {
    var body: some View {
        GeometryReader { geometry in
            ScrollView(Axis.Set.horizontal) {
                HStack(alignment: .center) {
                    ForEach(0..<8) { _ in
                        Text("🥳")
                    }
                }.frame(width: geometry.size.width, height: 50)
            }
        }
    }
}

// MARK: - Preview

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

결과

중심


2

나는 이것이 모든 사람에게 효과가 없다는 것을 알고 있지만, Divider를 추가하는 것만으로도 문제가 해결된다는 것이 흥미 롭다고 생각했습니다.

struct DividerTest: View {
var body: some View {
    VStack(alignment: .leading) {
        Text("Foo")
        Text("Bar")
        Divider()
    }.background(Color.red)
  }
}

2

다음은 유용한 코드입니다.

extension View {
    func expandable () -> some View {
        ZStack {
            Color.clear
            self
        }
    }
}

.expandable()수정자를 사용하거나 사용하지 않은 결과를 비교합니다 .

Text("hello")
    .background(Color.blue)

-

Text("hello")
    .expandable()
    .background(Color.blue)

여기에 이미지 설명 입력


2

여기에 이미지 설명 입력

로그인 페이지 디자인 SwiftUI

import SwiftUI

struct ContentView: View {

    @State var email: String = "william@gmail.com"
    @State var password: String = ""
    @State static var labelTitle: String = ""


    var body: some View {
        VStack(alignment: .center){
            //Label
            Text("Login").font(.largeTitle).foregroundColor(.yellow).bold()
            //TextField
            TextField("Email", text: $email)
                .textContentType(.emailAddress)
                .foregroundColor(.blue)
                .frame(minHeight: 40)
                .background(RoundedRectangle(cornerRadius: 10).foregroundColor(Color.green))

            TextField("Password", text: $password) //Placeholder
                .textContentType(.newPassword)
                .frame(minHeight: 40)
                .foregroundColor(.blue) // Text color
                .background(RoundedRectangle(cornerRadius: 10).foregroundColor(Color.green))

            //Button
            Button(action: {

            }) {
                HStack {
                    Image(uiImage: UIImage(named: "Login")!)
                        .renderingMode(.original)
                        .font(.title)
                        .foregroundColor(.blue)
                    Text("Login")
                        .font(.title)
                        .foregroundColor(.white)
                }


                .font(.headline)
                .frame(minWidth: 0, maxWidth: .infinity)
                .background(LinearGradient(gradient: Gradient(colors: [Color("DarkGreen"), Color("LightGreen")]), startPoint: .leading, endPoint: .trailing))
                .cornerRadius(40)
                .padding(.horizontal, 20)

                .frame(width: 200, height: 50, alignment: .center)
            }
            Spacer()

        }.padding(10)

            .frame(minWidth: 0, idealWidth: .infinity, maxWidth: .infinity, minHeight: 0, idealHeight: .infinity, maxHeight: .infinity, alignment: .top)
            .background(Color.gray)

    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1

GeometryReader를 편리한 확장 기능으로 사용하여 부모를 채울 수 있습니다.

extension View {
    func fillParent(alignment:Alignment = .center) -> some View {
        return GeometryReader { geometry in
            self
                .frame(width: geometry.size.width,
                       height: geometry.size.height,
                       alignment: alignment)
        }
    }
}

따라서 요청 된 예제를 사용하면

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

            Text("Content")
                .lineLimit(nil)
                .font(.body)
        }
        .fillParent(alignment:.topLeading)
        .background(Color.red)
    }
}

(스페이서가 더 이상 필요하지 않습니다)

여기에 이미지 설명 입력


이것은 전체 화면이 아닙니다.
Duck

질문은 전체 화면을 요구하는 것이 아니라 전체 너비를 요구했습니다. 안전 영역을 넘어 확장하려면을 사용하십시오. edgesIgnoringSafeArea
볼론 혼란

0
 var body: some View {
      VStack {
           CarouselView().edgesIgnoringSafeArea(.all)           
           List {
                ForEach(viewModel.parents) { k in
                    VideosRowView(parent: k)
                }
           }
    }
 }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.