Z축에 콘텐츠를 정렬하려면, ZStack이나 overlay(alignment:content:), background(_:in:fillStyle:)를 사용할 수 있습니다.
ZStack은 스택 내에 존재하는 다른 뷰들을 고려하지 않고 사용 가능한 공간을 기반으로 각 뷰의 크기를 조정합니다. 특정 콘텐츠의 크기를 다른 콘텐츠의 크기에 따라 달라지도록 하려면 overlay나 background modifier 내부에 해당하는 특정 콘텐츠를 정의할 수 있습니다.
위의 예시는 사진 하단에 텍스트 블록이 있는 이미지입니다. 하단을 완전히 가리지 않으면서 텍스트의 가독성을 향상시키기 위해, 텍스트 뒤에 반투명한 배경을 설정했습니다. 텍스트는 사진 너비에 맞게 줄 바꿈됩니다. 텍스트 배경은 텍스트에 맞추어 감싸지도록 사이즈가 지정됩니다.
CaptionedPhoto 뷰는 이미지를 정렬하고, Caption 뷰 내부의 이미지의 overlay(alignment:content:)에 텍스트를 제공합니다.
struct CaptionedPhoto: View {
let assetName: String
let captionText: String
var body: some View {
Image(assetName)
.resizable()
.scaledToFit()
.overlay(alignment: .bottom) {
Caption(text: captionText)
}
.clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous))
.padding()
}
}
CaptionedPhoto View 코드 설명
CaptionedPhoto 는 사진과 또 다른 커스텀 뷰인 Caption의 레이아웃을 지정해주는 커스텀 뷰입니다. Caption은 이미지 위에 올릴 캡션 텍스트의 레이아웃을 지정해주는 뷰입니다.
String 변수인 assetName에는 이미지 에셋이, captionText에는 캡션 뷰로 전달될 텍스트가 들어갈 것 입니다.
Image()에는 이미지 파일명이 입력되고, resizable().scaledToFit() 을 통해 사용 가능한 공간에 맞게 조절됩니다. 기본값은 사진의 원본 사이즈입니다.
조절된 이미지 크기는 최상위 수준의 유일한 뷰이므로, 이 크기가 CaptionedPhoto 뷰의 크기가 됩니다.
overlay(alignment: )를 이용해 다른 뷰를 이미지 앞에 겹쳐 놓을 수 있습니다. 예제에서는 글자와 배경색이 담긴 커스텀 뷰인 Caption을 내부에 정의하고, 중앙 하단에 위치하도록 했습니다.
앞선 뷰의 크기는 겹쳐진 뷰의 크기를 제한합니다.
clipShape와 padding을 통해 뷰에 코너라운드와 내부 여백을 주었습니다.
캡션 뷰는 background()를 이용하여 텍스트 뒤의 사진을 부분적으로 가리는 모양을 배치하여 텍스트에 더 높은 대비를 제공합니다.
struct Caption: View {
let text: String
var body: some View {
Text(text)
.padding()
.background(Color("TextContrast").opacity(0.75),
in: RoundedRectangle(cornerRadius: 10.0, style: .continuous))
.padding()
}
}
Caption View 코드 설명
텍스트에 padding()으로 여백을 준 뒤, background()의 색상과 투명도를 조절하고 코너 라운드를 지정했습니다. 그리고 다시 padding()을 주어 배경 바깥의 공간에 여백을 주었습니다.
오버레이나 백그라운드에 패딩을 결합할 때 주의해야 할 점이 있습니다. 우선 뷰에 패딩을 먼저 넣고나서 오버레이나 백그라운드를 준다면, 패딩 처리된 우선 뷰의 크기를 두번째 뷰의 크기로 인식합니다. 두 레이어를 모두 포함한 뷰에 여백을 주고 싶다면, 오버레이나 백그라운드 이후에 패딩을 적용하세요.
백그라운드는 오버레이와 유사하지만, 수정하는 뷰의 뒷 배경으로 들어간다는 차이점이 있습니다.
처음 쓰인 패딩은 텍스트와 뒷 배경 사이의 공간을, 두번째 쓰인 패딩은 뒷 배경과 이미지 사이의 공간이라고 생각 할 수 있습니다.
전체 코드
import SwiftUI
struct CaptionedPhoto: View {
let assetName: String
let captionText: String
var body: some View {
Image(assetName)
.resizable()
.scaledToFit()
.overlay(alignment: .bottom) {
Caption(text: captionText)
}
.clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous))
.padding()
}
}
struct Caption: View {
let text: String
var body: some View {
Text(text)
.padding()
.background(Color("TextContrast").opacity(0.75),
in: RoundedRectangle(cornerRadius: 10.0, style: .continuous))
.padding()
}
}
struct CaptionedPhoto_Previews: PreviewProvider {
static let landscapeName = "Landscape.jpeg"
static let landscapeCaption = "This photo is wider than it is tall."
static let portraitName = "Portrait.jpeg"
static let portraitCaption = "This photo is taller than it is wide."
static var previews: some View {
CaptionedPhoto(assetName: portraitName,
captionText: portraitCaption)
CaptionedPhoto(assetName: landscapeName,
captionText: landscapeCaption)
.preferredColorScheme(.dark)
CaptionedPhoto(assetName: landscapeName,
captionText: landscapeCaption)
.preferredColorScheme(.light)
}
}