이때 Spacer를 사용해 각 컨포넌트 사이에 공간을 주어 분리해줄 수 있다
struct Person: Identifiable {
var id = UUID()
let name: String
let imageName: String
}
struct ContentView: View {
var body: some View {
VStack{
Image(systemName: "heart")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200)
Spacer() // 공간을 줌
Text("Heart!")
Spacer() // 공간을 줌
Button {
print("Blink!")
} label: {
Text("HIT!")
}
}
}
}
수평으로는 가능할까?
struct ContentView: View {
var body: some View {
VStack{
Image(systemName: "heart")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200)
Spacer()
HStack { // 수평으로 배치하는 Stact
Image(systemName: "heart.fill") // 꽉 찬 하트
Spacer()
Text("Bolt") // Bolt 라는 텍스트
}
.padding(.horizontal, 100) // 간격 조정
Spacer() // 공간을 줌
Button {
print("Blink!")
} label: {
Text("HIT!")
}
}
}
}
HStack을 사용해 수평으로 꽉찬 하트와 Bolt 라는 텍스트를 배치해주었습니다.
이때, Spacer()를 사용하게 되면 각각 화면의 끝으로 이동하게 됩니다.
이를
.padding(.horizontal, 간격을 줄 만큼의 숫자)
을 사용해 둘의 간격을 임의로 조절해 줄 수 있습니다.
기본 사용
Color(.blue)
모서리 부분까지 채워주기
Color(.blue).edgesIgnoringSafeArea(.all)
추가)
Color(.blue).edgesIgnoringSafeArea(.top) // 위쪽 SafeArea만 채워짐
Color(.blue).edgesIgnoringSafeArea(.bottom) // 아래쪽 SafeArea만 채워짐
Color(.blue).edgesIgnoringSafeArea([.top, .bottom]) // 위 아래 둘 다 채워짐, all과는 다름
// 가로모드로 돌렸을 때 all은 다 채워지지만, [.top, .bottom]은 다 채워지지 않음
크기 지정 후 원하는 도형으로 모양을 바꾸기
Color(.blue)
.frame(width: 300, height: 200)
// 크기 지정, 너비 300, 높이 200
.clipShape(RoundedRectangle(cornerRadius: 30))
// 도형으로 자르기(여기서는 모서리가 둥근 사각형, 모서리 둥글기는 30
특정 색상 가져오기
Color(red: 0.4, green: 0.5, blue: 0.1)
RGB 사용해서 가져오기
Color(hue: 0.3, saturation: 0.4, brightness: 0.5)
hue, saturation, brightness 로 만들기
직접 Asset의 ColorSet으로 원하는 색을 가져와 쓸 수 있습니다.
struct ContentView: View {
var body: some View {
MyView()
}
}
struct MyView: View {
var body: some View {
Text("Hi dongle")
}
}
// View 안에는 View 만 들어갈 수 있음
왜 사용해야 할까?
기존 Struct로 "Hi"를 유저가 볼 수 있도록 만들고, "Hi dongle"을 보여주고 싶다면 다시 새로운 Struct를 이용해 만들어야 하는 불편함이 있었기 때문입니다.
즉, Struct(구조체)로 만든 내용은 앱화면을 다시 그리기가 힘들어집니다.
작동 원리
@State var name: String = ""
State가 변하면 다시 화면을 그려주게 됨
struct ContentView: View {
@State var name: String = ""
var body: some View {
VStack{
Text("Hi \(name)") // 초기 name은 공백이므로 이름이 보여지지 않음
Button {
name = "Dongle!" // 버튼을 누르게 되면 Dongle!이 name에 저장되어 State도 변하게되어 Hi Dongle!로 화면이 다시 그려짐
} label: {
Text("Click!")
}
}
}
}
간단하게 보자면 설정이나 옵션이라고 생각할 수 있다.
struct ContentView: View {
var body: some View {
Image(systemName: "heart")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100)
.background(.green)
.foregroundColor(.red)
}
}
.을 찍고 옵션처럼 효과를 하나 하나 주는 것 이라고 생각하면 되는데, 사실은 위의 코드로 예를 들어보자면 Image에 .resizable()한 이미지를 만들고, 그 이미지에 .aspectRatio(contentMode: .fit)한 이미지를 만들어준다고 생각하면 됩니다.
이런 상황에서 두 컴포넌트 사이의 간격을 조정해주는 방법으로는
padding()
을 사용하면 됩니다.
여러가지 padding 응용
.padding(.bottom, 100) // 아래로 여백 100만큼
.padding(.leading, 100) // 옆으로 여백 100 만큼
padding()을 주고 배경을 줄 경우 늘어나니 주의할 것, (영역의 혼란을 줄 수 있으므로)
var body: some View {
Image(systemName: "heart")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300, height: 200)
.background(.green)
}
frame() 너비, 높이 정렬을 사용할 수 있으며, 기본은 center 가운데이다
두근 버튼을 누르면 가득 채워진 하트와 빈 하트가 번갈아가면서 나옴
@State var isPitapat: Bool = false
var body: some View {
ZStack{
Color.yellow.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
Image(systemName: isPitapat ? "heart.fill" : "heart") // 만약 isPitapat이 true면 heart.fill flase면 heart 반환
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200)
Spacer()
HStack {
Text("하트를 원하시면")
Button{
isPitapat.toggle() // 스위치 역할, true, false 번갈아가면서
} label: {
Text("두근!")
.padding() // 여백
.background(.orange) // 배경 오렌지
.cornerRadius(10) // 모서리 둥글게
}
}
}
}
}