swiftUI - Avocados
Launch Screen을 먼저 만들었다.
- 아보카도 사진은 수평, 수직으로 가운데 정렬하였고
- AVOCADOS Label은 수직으로 가운데 정렬 후 아보카도와 vertical spacing을 설정하였다(마우스 드래그)
다음은 아래 사진처럼 Tab View를 만들 것이다.
import SwiftUI
struct AppView: View {
var body: some View {
TabView {
AvocadosView()
.tabItem {
Image("tabicon-branch")
Text("Avocados")
}
ContentView()
.tabItem {
Image("tabicon-book")
Text("Recipes")
}
RipeningStagesView()
.tabItem {
Image("tabicon-avocado")
Text("Ripening")
}
SettingsView()
.tabItem {
Image("tabicon-settings")
Text("Settings")
}
}
.tint(.primary)
}
}
struct AppView_Previews: PreviewProvider {
static var previews: some View {
AppView()
}
}
.tint : 클릭된 부분의 색깔을 설정할 수 있다.
다음으로는 움직이는 메인 뷰를 만드는 코드다.
import SwiftUI
struct AvocadosView: View {
// MARK: - PROPERTIES
@State private var pulsateAnimation: Bool = false
var body: some View {
VStack {
Spacer()
Image("avocado")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 240, height: 240, alignment: .center)
.shadow(color: Color("ColorBlackTransparentDark"), radius: 12, x: 0, y: 8)
.scaleEffect(self.pulsateAnimation ? 1 : 0.9)
.opacity(self.pulsateAnimation ? 1 : 0.9)
.animation(Animation.easeOut(duration: 1.5).repeatForever(), value: pulsateAnimation)
VStack {
Text("Avocados".uppercased())
.font(.system(size: 42, weight: .bold, design: .serif))
.padding()
.shadow(color: Color("ColorBlackTransparentDark"), radius: 4, x: 0, y: 4)
Text("""
Creamy, green, and full of nutrients! Avocado is a powerhouse ingredient at any meal. Enjoy these handpicked avocado recipes for breakfast, lunch, dinner & more!
""")
.lineLimit(nil)
.font(.system(.headline, design: .serif))
.foregroundColor(Color("ColorGreenLight"))
.multilineTextAlignment(.center)
.lineSpacing(8)
.frame(maxWidth: 640, minHeight: 120)
}
.padding()
Spacer()
}
.background(
Image("background")
.resizable()
.aspectRatio(contentMode: .fill)
)
.edgesIgnoringSafeArea(.all)
.onAppear {
self.pulsateAnimation.toggle()
}
}
}
struct AvocadosView_Previews: PreviewProvider {
static var previews: some View {
AvocadosView()
}
}
""" """ : 가독성을 위해서 줄바꿈 한 것 뿐이다.
.lineLimit(nil) : 줄의 제한을 없애는 것
.edgesIgnoringSafeArea(.all) : 상단, 하단의 SafeArea를 무시한다.
ContentView만들기
import SwiftUI
struct HeaderView: View {
// MARK: - PROPERTIES
@State private var showHeadLine: Bool = false
var slideInAnimation: Animation {
Animation.spring(response: 1.5, dampingFraction: 0.5, blendDuration: 0.5)
.speed(1)
.delay(0.25)
}
var body: some View {
ZStack {
Image("avocado-slice-1")
.resizable()
.aspectRatio(contentMode: .fill)
HStack(alignment: .top, spacing: 0) {
Rectangle()
.fill(Color("ColorGreenLight"))
.frame(width: 4)
VStack(alignment: .leading, spacing: 0) {
Text("Avocado")
.font(.system(.title, design: .serif))
.fontWeight(.bold)
.foregroundColor(Color.white)
.shadow(radius: 3)
Text("Avocados are a powerhouse ingradient at any meal for anyone.")
.font(.footnote)
.lineLimit(2)
.multilineTextAlignment(.leading)
.foregroundColor(Color.white)
.shadow(radius: 3)
}
.padding(.vertical, 0)
.padding(.horizontal, 20)
.frame(width: 281, height: 105)
.background(Color("ColorBlackTransparentLight"))
}
.frame(width: 285, height: 105, alignment: .center)
.offset(x: -66, y: showHeadLine ? 75 : 220)
.animation(slideInAnimation, value: showHeadLine)
.onAppear {
self.showHeadLine.toggle()
}
}
.frame(width: 480, height: 320, alignment: .center)
}
}
struct HeaderView_Previews: PreviewProvider {
static var previews: some View {
HeaderView()
.previewLayout(.sizeThatFits)
}
}
Animation.spring(response: 1.5, dampingFraction: 0.5, blendDuration: 0.5).speed(1).delay(0.25)
: response - 몇초에 걸쳐서 작동시킬지
: dampingFraction : 스프링의 강도를 의미한다. (강도에 따라서 애니메이션이 다시 정상으로 돌아가는 속도가 차이난다고한다.)
: blendDuration: 블랜드시간 지정 (값을 0으로 설정하면 목표 값으로 즉시 이동하는 것과 같은 효과를 값을 크게 설정하면 스무스해진다.)
.offset(x: -66, y: showHeadLine ? 75 : 220) : 밑에서 위로 올라가는 동작을 설정한다.
.animation(slideInAnimation, value: showHeadLine) : showHeadLine의 값이 변하면 감지하여 slideAnimation을 수행한다.
import SwiftUI
struct ContentView: View {
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .center, spacing: 20) {
// MARK: - HEADER
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top,spacing: 0, content: {
HeaderView()
})
}
// MARK: - FOOTER
VStack(alignment: .center, spacing: 20) {
Text("All About Avocados")
.font(.system(.title, design: .serif))
.foregroundColor(Color("ColorGreenAdaptive"))
.padding(8)
Text("Everything you wanted to know about avocados but were too afraid to ask.")
.font(.system(.body, design: .serif))
.multilineTextAlignment(.center)
.foregroundColor(Color.gray)
}
.frame(maxWidth: 640)
.padding()
.padding(.bottom, 85)
}
}
.edgesIgnoringSafeArea(.all)
.padding(0)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
다음과 같이 만들기
import SwiftUI
// MARK: - HEADER MODEL
struct Header: Identifiable {
var id = UUID()
var image: String
var headline: String
var subheadline: String
}
import SwiftUI
// MARK: - HEADERS DATA
let headersData: [Header] = [
Header(
image: "avocado-slice-1",
headline: "Avocados",
subheadline: "Avocados are a powerhouse ingredient at any meal for anyone."
),
Header(
image: "avocado-slice-2",
headline: "Healthy",
subheadline: "Avocados are good for us and they can be part of our healthy diet."
),
Header(
image: "avocado-slice-3",
headline: "Nutrients",
subheadline: "Avocados have a surprising amount and diversity of vitamins and minerals."
),
Header(
image: "avocado-slice-4",
headline: "Delicious",
subheadline: "Craving more guacamole? Find the best guacamole recipes in the app."
),
Header(
image: "avocado-slice-5",
headline: "Tasty",
subheadline: "Avocados are a good source of natural fiber, which making you feel full."
),
Header(
image: "avocado-slice-6",
headline: "Recipes",
subheadline: "Enjoy these carefully handpicked avocado recipes for every occasion!"
)
]
import SwiftUI
struct ContentView: View {
// MARK: - PROPERTIES
var headers: [Header] = headersData
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .center, spacing: 20) {
// MARK: - HEADER
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .top,spacing: 0, content: {
ForEach(headers) { item in
HeaderView(header: item)
}
})
}
// MARK: - FOOTER
VStack(alignment: .center, spacing: 20) {
Text("All About Avocados")
.font(.system(.title, design: .serif))
.foregroundColor(Color("ColorGreenAdaptive"))
.padding(8)
Text("Everything you wanted to know about avocados but were too afraid to ask.")
.font(.system(.body, design: .serif))
.multilineTextAlignment(.center)
.foregroundColor(Color.gray)
}
.frame(maxWidth: 640)
.padding()
.padding(.bottom, 85)
}
}
.edgesIgnoringSafeArea(.all)
.padding(0)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(headers: headersData)
}
}
Custom Modifiers 만들기
- reusable code로 반복되어 사용될 때 유용하다.
예를 들어 하단에 있는 코드는 유지, 보수, 재사용할 때 문제가 될 수 있다. hard coded이기 때문에
import SwiftUI
struct DishesView: View {
var body: some View {
HStack {
HStack {
Image("icon-toasts")
.resizable()
.frame(width: 42, height: 42, alignment: .center)
Spacer()
Text("Toasts")
}
Image(systemName: "heart.circle")
HStack() {
Text("Guacamole")
Spacer()
Image("icon-gucamole")
.resizable()
.frame(width: 42, height: 42, alignment: .center)
}
}
.font(.system(.callout, design: .serif))
.foregroundColor(Color.gray)
.padding(.horizontal)
.frame(maxHeight: 220)
}
}
struct DishesView_Previews: PreviewProvider {
static var previews: some View {
DishesView()
.previewLayout(.fixed(width: 414, height: 200))
}
}
위에 코드를 ViewModifier 를 사용하여 아래 코드처럼 만들 수 있다.
import SwiftUI
struct DishesView: View {
var body: some View {
HStack {
HStack {
Image("icon-toasts")
.resizable()
.modifier(IconModifier())
Spacer()
Text("Toasts")
}
Image(systemName: "heart.circle")
HStack() {
Text("Guacamole")
Spacer()
Image("icon-gucamole")
.resizable()
.modifier(IconModifier())
}
}
.font(.system(.callout, design: .serif))
.foregroundColor(Color.gray)
.padding(.horizontal)
.frame(maxHeight: 220)
}
}
struct IconModifier: ViewModifier {
func body(content: Content) -> some View {
content
.frame(width: 42, height: 42, alignment: .center)
}
}
struct DishesView_Previews: PreviewProvider {
static var previews: some View {
DishesView()
.previewLayout(.fixed(width: 414, height: 200))
}
}
import SwiftUI
struct DishesView: View {
var body: some View {
HStack(alignment: .center, spacing: 4) {
// 1nd Column
VStack(alignment: .leading, spacing: 4) {
HStack {
Image("icon-toasts")
.resizable()
.modifier(IconModifier())
Spacer()
Text("Toasts")
}
Divider()
HStack {
Image("icon-tacos")
.resizable()
.modifier(IconModifier())
Spacer()
Text("Tacos")
}
Divider()
HStack {
Image("icon-salads")
.resizable()
.modifier(IconModifier())
Spacer()
Text("salads")
}
Divider()
HStack {
Image("icon-halfavo")
.resizable()
.modifier(IconModifier())
Spacer()
Text("halfavo")
}
}
// 2nd Column
VStack(alignment: .center, spacing: 16) {
HStack {
Divider()
}
Image(systemName: "heart.circle")
.font(Font.title.weight(.ultraLight))
.imageScale(.large)
HStack {
Divider()
}
}
// 3nd Column
VStack(alignment: .trailing, spacing: 4) {
HStack() {
Text("Guacamole")
Spacer()
Image("icon-guacamole")
.resizable()
.modifier(IconModifier())
}
Divider()
HStack() {
Text("Sandwich")
Spacer()
Image("icon-sandwiches")
.resizable()
.modifier(IconModifier())
}
Divider()
HStack() {
Text("Soup")
Spacer()
Image("icon-soup")
.resizable()
.modifier(IconModifier())
}
Divider()
HStack() {
Text("Smoothie")
Spacer()
Image("icon-smoothies")
.resizable()
.modifier(IconModifier())
}
}
}
.font(.system(.callout, design: .serif))
.foregroundColor(Color.gray)
.padding(.horizontal)
.frame(maxHeight: 220)
}
}
struct IconModifier: ViewModifier {
func body(content: Content) -> some View {
content
.frame(width:42, height: 42, alignment: .center)
}
}
struct DishesView_Previews: PreviewProvider {
static var previews: some View {
DishesView()
.previewLayout(.fixed(width: 414, height: 280))
}
}
systemImage 의 이미지도 꾸밀 수 있다 : .font(Font.title.weight(.ultraLight)) 처럼 접근하면 다양하게 변화를 줄 수 있다.
struct IconModifier: ViewModifier : ViewModifier 를 사용하여 같은 코드를 재사용 가능하게 해준다.
Divider() : 경계선 만들기
다음으로는 ContentView에 추가한다.
DishesView()
.frame(maxWidth: 640) // 아이패드를 위한 설정
다음과 같은 View 만들기
import SwiftUI
struct FactsView: View {
var body: some View {
ZStack {
Text("It’s little wonder there are so many health benefits when a single serve of avocado (1/4 or 50g) boasts healthy fats, fibre, folate, niacin, vitamins C, B5, E & K, potassium and antioxidants.")
.padding(.leading, 55)
.padding(.trailing, 10)
.padding(.vertical, 3)
.frame(width: 300, height: 135, alignment: .center)
.background(LinearGradient(gradient: Gradient(colors: [Color("ColorGreenMedium"), Color("ColorGreenLight")]), startPoint: .leading, endPoint: .trailing))
.cornerRadius(12)
.lineLimit(6)
.multilineTextAlignment(.leading)
.font(.footnote)
.foregroundColor(Color.white)
Image("avocado-fact-2")
.resizable()
.frame(width: 66, height: 66, alignment: .center)
.clipShape(Circle())
.background(
Circle()
.fill(Color.white)
.frame(width: 74, height: 74, alignment: .center)
)
.background(
Circle()
.fill(LinearGradient(gradient: Gradient(colors: [Color("ColorGreenMedium"), Color("ColorGreenLight")]), startPoint: .trailing, endPoint: .leading))
.frame(width: 82, height: 82, alignment: .center)
)
.background(
Circle()
.fill(Color("ColorAppearanceAdaptive"))
.frame(width: 90, height: 90, alignment: .center)
)
.offset(x: -150)
}
}
}
struct FactsView_Previews: PreviewProvider {
static var previews: some View {
FactsView()
.previewLayout(.fixed(width: 400, height: 220))
}
}
.padding(.leading, 55): 왼쪽에 간격 설정
.padding(.trailing, 10): 오른쪽에 간격 설정
.padding(.vertical, 3): 상하단에 간격 설정
다음으로는 사람 사진 들어가있는 원 설정이다
Image("avocado-fact-2")
.resizable()
.frame(width: 66, height: 66, alignment: .center)
.clipShape(Circle())
.background(
Circle()
.fill(Color.white)
.frame(width: 74, height: 74, alignment: .center)
)
.background(
Circle()
.fill(LinearGradient(gradient: Gradient(colors: [Color("ColorGreenMedium"), Color("ColorGreenLight")]), startPoint: .trailing, endPoint: .leading))
.frame(width: 82, height: 82, alignment: .center)
)
.background(
Circle()
.fill(Color("ColorAppearanceAdaptive"))
.frame(width: 90, height: 90, alignment: .center)
)
.offset(x: -150)
다음은 유지 보수, 재사용이 가능하도록 하는 내용인데 생략
다음은 아래 뷰처럼 만들것이다.
import SwiftUI
struct RecipeCardView: View {
// MARK: - PROEPRTIES
var recipe: Recipe
var body: some View {
VStack(alignment: .leading, spacing: 0) {
Image(recipe.image)
.resizable()
.scaledToFit()
.overlay(
HStack {
Spacer()
VStack {
Image(systemName: "bookmark")
.font(Font.title.weight(.light))
.foregroundColor(Color.white)
.imageScale(.small)
.shadow(color: Color("ColorBlackTransparentLight"), radius: 2, x: 0, y: 0)
.padding(.trailing, 20)
.padding(.top, 22)
Spacer()
}
}
)
VStack(alignment: .leading, spacing: 12) {
// TITLE
Text(recipe.title)
.font(.system(.title, design: .serif))
.foregroundColor(Color("ColorGreenMedium"))
.lineLimit(1)
// HEADLINE
Text(recipe.headline)
.font(.system(.body, design: .serif))
.foregroundColor(Color.gray)
.italic()
// RATES
HStack(alignment: .center, spacing: 5) {
ForEach(1...(recipe.rating), id: \.self) { item in
Image(systemName: "star.fill")
.font(.body)
.foregroundColor(Color.yellow)
}
}
// COOKING
HStack(alignment: .center, spacing: 12) {
HStack(alignment: .center, spacing: 2) {
Image(systemName: "person.2")
Text("Serves: \(recipe.serves)")
}
HStack(alignment: .center, spacing: 2) {
Image(systemName: "clock")
Text("Serves: \(recipe.preparation)")
}
HStack(alignment: .center, spacing: 2) {
Image(systemName: "flame")
Text("Cooking: \(recipe.cooking)")
}
}
.font(.footnote)
.foregroundColor(Color.gray)
}
.padding()
.padding(.bottom, 12)
}
.background(Color.white)
.cornerRadius(12)
.shadow(color: Color("ColorBlackTransparentLight"), radius: 8, x: 0, y: 0)
}
}
struct RecipeCardView_Previews: PreviewProvider {
static var previews: some View {
RecipeCardView(recipe: recipesData[0])
.previewLayout(.sizeThatFits)
}
}
contentView에서 추가한 코드
VStack(alignment: .center, spacing: 20) {
ForEach(recipes) { item in
RecipeCardView(recipe: item)
}
}
북마크 이미지를 우측 상단에 표시하는 방법
- HStack에서 Spacer를 사용하여 우측 끝으로 이동시키고 VStack에서 Spacer를 사용하여 상단으로 이동시켰다.
overlay: overlay는 뷰 원본의 공간을 기준으로 그 위에 새로운 뷰를 중첩하여 쌓는 기능을 하는 수식어다.
- 즉 overlay는 상단 코드에서는 Image 위에 또 다른 View를 쌓는 것이다.
다음과 같은 뷰 만들어주기
import SwiftUI
struct RecipeDetailView: View {
// MARK: - PROPERTIES
var recipe: Recipe
@State private var pulsate: Bool = false
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .center, spacing: 0) {
Image(recipe.image)
.resizable()
.scaledToFit()
Group {
// TITLE
Text(recipe.title)
.font(.system(.largeTitle, design: .serif))
.fontWeight(.bold)
.multilineTextAlignment(.center)
.foregroundColor(Color("ColorGreenAdaptive"))
.padding(.top, 10)
// RATING
RecipeRatingView(recipe: recipe)
// COOKING
RecipeCookingView(recipe: recipe)
// INGREDIENTS
Text("Ingredients")
.fontWeight(.bold)
.modifier(TitleModifier())
VStack(alignment: .leading, spacing: 5) {
ForEach(recipe.ingredients, id: \.self) { item in
VStack(alignment: .leading, spacing: 5) {
Text(item)
.font(.footnote)
.multilineTextAlignment(.leading)
Divider()
}
}
}
// INSTRUCTIONS
Text("Instructions")
.fontWeight(.bold)
.modifier(TitleModifier())
ForEach(recipe.instructions, id: \.self) { item in
VStack(alignment: .center, spacing: 5) {
Image(systemName: "chevron.down.circle")
.resizable()
.frame(width: 42, height: 42, alignment: .center)
.imageScale(.large)
.font(Font.title.weight(.ultraLight))
.foregroundColor(Color("ColorGreenAdaptive"))
Text(item)
.lineLimit(nil)
.multilineTextAlignment(.center)
.font(.system(.body, design: .serif))
.frame(minHeight: 100)
}
}
}
.padding(.horizontal, 24)
.padding(.vertical, 12)
}
}
.edgesIgnoringSafeArea(.top)
.overlay(
HStack {
Spacer()
VStack {
Button(action: {
// ACTION
}, label: {
Image(systemName: "chevron.down.circle.fill")
.font(.title)
.foregroundColor(Color.white)
.shadow(radius: 4)
.opacity(self.pulsate ? 1 : 0.6)
.scaleEffect(self.pulsate ? 1.2 : 0.8, anchor: .center)
.animation(Animation.easeInOut(duration: 1.5).repeatForever(autoreverses: true), value: pulsate)
})
.padding(.trailing, 20)
.padding(.top, 24)
Spacer()
}
}
)
.onAppear {
self.pulsate.toggle()
}
}
}
struct RecipeDetailView_Previews: PreviewProvider {
static var previews: some View {
RecipeDetailView(recipe: recipesData[0])
}
}
.overlay로 우측 상단에 버튼을 만들었다.
아래 코드를 눌러서 modal를 dismiss해줄 수 있다.
@Environment(\.dismiss) var dismiss
Button(action: {
// ACTION
self.dismiss()
}
다음은 RipeningView를 만들 것이다.
import SwiftUI
struct RipeningView: View {
// MARK: - PROEPRTIES
@State private var slideInAnimation: Bool = false
var body: some View {
VStack {
Image("avocado-ripening-1")
.resizable()
.frame(width: 100, height: 100, alignment: .center)
.clipShape(Circle())
.background(
Circle()
.fill(Color("ColorGreenLight"))
.frame(width: 110, height: 110, alignment: .center)
)
.background(
Circle()
.fill(Color("ColorAppearanceAdaptive"))
.frame(width: 120, height: 120, alignment: .center)
)
.zIndex(1)
.animation(Animation.easeInOut(duration: 1), value: slideInAnimation)
.offset(y: slideInAnimation ? 55 : -55)
VStack(alignment: .center, spacing: 10) {
// STAGE
VStack(alignment: .center, spacing: 0) {
Text("1")
.font(.system(.largeTitle, design: .serif))
.fontWeight(.bold)
Text("STAGE")
.font(.system(.body, design: .serif))
.fontWeight(.heavy)
}
.foregroundColor(Color("ColorGreenMedium"))
.padding(.top, 65)
.frame(width: 180)
// TITLE
Text("Hard")
.font(.system(.title, design: .serif))
.fontWeight(.bold)
.foregroundColor(Color("ColorGreenMedium"))
.padding(.vertical, 12)
.padding(.horizontal, 0)
.frame(width: 220)
.background(
RoundedRectangle(cornerRadius: 12)
.fill(LinearGradient(gradient: Gradient(colors: [Color.white, Color("ColorGreenLight")]), startPoint: .top, endPoint: .bottom))
.shadow(color: Color("ColorBlackTransparentLight"), radius: 6, x: 0, y: 6)
)
// DESCRIPTION
Spacer()
Text("Fresh off the tree, the avocado is very hard with no give.")
.foregroundColor(Color("ColorGreenDark"))
.fontWeight(.bold)
.lineLimit(nil)
Spacer()
// RIPENESS
Text("5+ DAYS")
.foregroundColor(Color.white)
.font(.system(.callout, design: .serif))
.fontWeight(.bold)
.shadow(radius: 3)
.padding(.vertical)
.padding(.horizontal, 0)
.frame(width: 185)
.background(
RoundedRectangle(cornerRadius: 12)
.fill(LinearGradient(gradient: Gradient(colors: [Color("ColorGreenMedium"), Color("ColorGreenDark")]), startPoint: .top, endPoint: .bottom))
.shadow(color: Color("ColorBlackTransparentLight"), radius: 6, x: 0, y: 6)
)
// INSTRUCTION
Text("Hold avocados at room temperature until they are fully ripe.")
.font(.footnote)
.fontWeight(.bold)
.lineLimit(3)
.frame(width: 160)
Spacer()
}
.zIndex(0)
.multilineTextAlignment(.center)
.padding(.horizontal)
.frame(width: 260, height: 485, alignment: .center)
.background(LinearGradient(gradient: Gradient(colors: [Color("ColorGreenLight"), Color("ColorGreenMedium")]), startPoint: .top, endPoint: .bottom))
.cornerRadius(20)
}
.edgesIgnoringSafeArea(.all)
.onAppear {
self.slideInAnimation.toggle()
}
}
}
struct RipeningView_Previews: PreviewProvider {
static var previews: some View {
RipeningView()
}
}
다음으로는 다음 사진과 같은 뷰 만들기
import SwiftUI
struct RipeningStagesView: View {
// MARK: - PROPERTIES
var ripeningStages: [Ripening] = ripeningData
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
VStack {
Spacer()
HStack(alignment: .center, spacing: 25) {
ForEach(ripeningStages) { stage in
RipeningView(ripening: stage)
}
}
.padding(.vertical)
.padding(.horizontal, 25)
Spacer()
}
}
.edgesIgnoringSafeArea(.all)
}
}
struct RipeningStagesView_Previews: PreviewProvider {
static var previews: some View {
RipeningStagesView(ripeningStages: ripeningData)
}
}
다음처럼 만들기
import SwiftUI
struct SettingsView: View {
// MARK: - PROPERTIES
@State private var enableNotification: Bool = false
@State private var backgroundRefresh: Bool = false
var body: some View {
VStack(alignment: .center, spacing: 0) {
// MARK: - HEADER
VStack(alignment: .center, spacing: 5) {
Image("avocado")
.resizable()
.scaledToFit()
.padding(.top)
.frame(width: 100, height: 100, alignment: .center)
.shadow(color: Color("ColorBlackTransparentLight"), radius: 8, x: 0, y: 4)
Text("Avocados".uppercased())
.font(.system(.title, design: .serif))
.fontWeight(.bold)
.foregroundColor(Color("ColorGreenAdaptive"))
}
.padding()
Form {
// MARK: - SECTION #1
Section {
Toggle(isOn: self.$enableNotification) {
Text("Enable notification")
}
} header: {
Text("General Settings")
}
Toggle(isOn: $backgroundRefresh) {
Text("Background refresh")
}
// MARK: - SECTION #2
Section(content: {
if enableNotification {
HStack {
Text("Product").foregroundColor(Color.gray)
Spacer()
Text("Avocado Recipes")
}
HStack {
Text("Compatibility").foregroundColor(Color.gray)
Spacer()
Text("iPhone & iPad")
}
HStack {
Text("Developer").foregroundColor(Color.gray)
Spacer()
Text("John / Jane")
}
HStack {
Text("Designer").foregroundColor(Color.gray)
Spacer()
Text("Avocado Recipes")
}
HStack {
Text("Website").foregroundColor(Color.gray)
Spacer()
Link("swiftuimasterclass.com", destination: URL(string: "swiftuimasterclass.com")!)
// Text("swiftuimasterclass.com")
}
HStack {
Text("Version").foregroundColor(Color.gray)
Spacer()
Text("1.0.0")
}
} else {
HStack {
Text("Personal message").foregroundColor(Color.gray)
Spacer()
Text("👍 Happy Coding!")
}
}
}, header: {
Text("Application")
})
}
}
.frame(maxWidth: 640)
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView()
}
}