Giter Club home page Giter Club logo

practice-swiftui's Introduction

Sangwon Shin ๐Ÿ‘‹

Hits

who am I?

  • ๐Ÿ‘ฏ I majored in Electronic Engineering
  • ๐Ÿ“ซ Konkuk University (2015.03 ~ 2021.08)

sangwon's github stats

sangwon's github stats

practice-swiftui's People

Contributors

brandnew-one avatar

Watchers

 avatar

practice-swiftui's Issues

Spacer

Spacer

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 2 51 55

๊ณต์‹๋ฌธ์„œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ์Šคํƒ ๋ ˆ์ด์•„์›ƒ์— ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด ์ฃผ ์ถ•์„ ๋”ฐ๋ผ ํ™•์žฅ๋˜๊ณ  ์Šคํƒ ๋ ˆ์ด์•„์›ƒ์— ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๋‘ ์ถ• ๋ชจ๋‘ ํ™•์žฅ๋˜๋Š” ์œ ์—ฐํ•œ ๊ณต๊ฐ„์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰ VStack์˜ ๊ฒฝ์šฐ์—๋Š” Vertical ํ•˜๊ฒŒ ํ™•์žฅ๋˜๊ณ , HStack์˜ ๊ฒฝ์šฐ์—๋Š” Horizontalํ•˜๊ฒŒ ํ™•์žฅ๋˜๋Š” ๊ณต๊ฐ„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ์ œ๋ฅผ ํ†ตํ•ด์„œ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

VStack {
  Image("turtlerock")
    .resizable()
    .frame(width: 150, height: 150)
  Spacer()
  Image("turtlerock")
    .resizable()
    .frame(width: 150, height: 150)
}

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 2 56 57

HStack {
    Image("turtlerock")
      .resizable()
      .frame(width: 150, height: 150)
    Spacer()
    Image("turtlerock")
      .resizable()
      .frame(width: 150, height: 150)
  }

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 2 57 14

์œ„์˜ ์˜ˆ์ œ๋“ค๋งŒ ๋ด๋„ Spacer๊ฐ€ ์–ด๋–ค ๊ธฐ๋Šฅ์„ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Spacer ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 3 04 32

minLength๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ ์•ž์„  ์˜ˆ์ œ๋“ค๊ณผ ๊ฐ™์ด ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ๊ฐ’์„ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด nil ๊ฐ’์ด ์„ค์ •๋˜๊ณ  view๋“ค ์‚ฌ์ด์— ์‹œ์Šคํ…œ ์ตœ๋Œ€ ๊ฐ„๊ฒฉ์ด ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

HStack {
  Image("turtlerock")
    .resizable()
    .frame(width: 150, height: 150)
  Spacer(minLength: 200)
  Image("turtlerock")
    .resizable()
    .frame(width: 150, height: 150)
}

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 3 08 40

minLength๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋ณ€์ˆ˜๋ช…์—์„œ๋„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋“ฏ์ด Spacer์˜ ์ตœ์†Œ๊ธธ์ด๋ฅผ ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„๋Š” ์ตœ์†Œ๊ธธ์ด๋ฅผ 200์œผ๋กœ ์ง€์ •ํ•ด spacer ๊ธธ์ด๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด Image๊ฐ€ ์งค๋ ค์„œ ๋‚˜์˜ค๋Š”๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
frame์„ ํ†ตํ•ด ๊ณ ์ •๋œ ํฌ๊ธฐ์˜ spacer๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.


ZStack์—์„œ Spacer๋Š” ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ€์งˆ๊นŒ์š”?

Stack์„ ๊ณต๋ถ€ํ•  ๋•Œ ZStack์—์„œ๋Š” Spacing์„ ์„ค์ •ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ Z์ถ•์œผ๋กœ view ๋“ค ์‚ฌ์ด์˜ ์ตœ๋Œ€๊ฐ„๊ฒฉ์„ ์„ค์ •ํ•˜๋Š” Spacer๋Š” ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ€์งˆ๊นŒ์š”?

๋งํฌ๋ฅผ ํ†ตํ•ด ํ•™์Šตํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์•„์ง ์ •ํ™•ํ•œ ์˜๋ฏธ๋ฅผ ํŒŒ์•…ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

[ํ™”๋ฉด์ „ํ™˜] Re-rendering ์‹œ ํ•˜์œ„๋ทฐ๊ฐ€ ๋งค๋ฒˆ init ๋˜๋Š” ํ˜„์ƒ

๋ฌธ์ œ์ 

1) SwiftUI4 ๋กœ ์—…๋ฐ์ดํŠธ ๋˜๋ฉด์„œ Bingding ํƒ€์ž…์— @published๋ฅผ ๋„ฃ์œผ๋ฉด Warning์ด ๋ฐœ์ƒํ•œ๋‹ค.

image

final class ContentViewModel: ObservableObject {
  @Published var sheetisShow: Bool = false
  private var cancellables = Set<AnyCancellable>()

  let sheetSubject = PassthroughSubject<Void, Never>()

  enum Action {
    case sheetisShow
  }

  func action(_ action: Action) {
    switch action {
    case .sheetisShow:
      sheetSubject.send()
    }
  }

  init() {
    transform()
  }

  func transform() {
    sheetSubject
      .throttle(for: 0.1, scheduler: RunLoop.main, latest: false)
      .subscribe(on: RunLoop.main)
      .sink(receiveValue: { [weak self] in
        guard let self = self else { return }
        self.sheetisShow = true
      })
      .store(in: &cancellables)
  }
}
  var body: some View {
    VStack {
      Text("This is Parent View")

      Button(
        action: { viewModel.action(.sheetisShow) },
        label: {
          Text("PRESS")
        }
      )
      .buttonStyle(.plain)

      ChildView()
    }
    .padding()
    .fullScreenCover(isPresented: $viewModel.sheetisShow) {
      ModalView()
    }
  }

SwiftUI๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ, modal full screen์ด๋‚˜ push๋“ฑ ํ™”๋ฉด์ „ํ™˜์— ํ•„์š”ํ•œ ๊ฐ’๋“ค์„ ๋ณดํ†ต ๋ทฐ๋ชจ๋ธ์—์„œ ๊ฐ€์ง€๊ณ  ๋ทฐ์—์„œ ํ•ด๋‹น ๊ฐ’๋“ค์„ Binding ํ˜•ํƒœ๋กœ ๊ด€์ฐฐํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ํ•ด๋‹น ๊ฐ’๋“ค์ด ๋ณ€ํ•˜๋ฉด ํ™”๋ฉด ์ „ํ™˜์ด ๋ฐœ์ƒํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

๋ถ„๋ช… ์ฒ˜์Œ SwiftUI๋ฅผ ๊ณต๋ถ€ํ•  ๋•Œ๋Š” ์œ„์˜ ์ฝ”๋“œ๊ฐ€ Warning์„ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์•˜๋˜๊ฒƒ ๊ฐ™์€๋ฐ(๋ชจ๋ฅด๊ณ  ์žˆ์—ˆ์„ ์ˆ˜ ์žˆ๋‹ค..)
Xcode 14.0 ์ดํ›„๋ถ€ํ„ฐ๋Š” Binding ๊ฐ’์— @published ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋ฉด ์œ„์™€ ๊ฐ™์ด ๋ณด๋ผ์ƒ‰ ๊ฒฝ๊ณ ๋ฅผ ๋งŒ๋‚˜๊ฒŒ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

๋ทฐ๋‹จ์—์„œ @State๋กœ Bool ๊ฐ’์„ ๋“ค๊ณ  ์žˆ๋‹ค๊ฐ€ ํ•ด๋‹น๊ฐ’์— ๋ณ€ํ™”๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ, ๋ทฐ๋ฅผ ๋‹ค์‹œ Re-Rendring ํ•˜๋Š” ๊ฒƒ๊ณผ ๋ทฐ๋ชจ๋ธ์— @published๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ, objectWillChange๋ฅผ ํ†ตํ•ด์„œ ๋ทฐ๋ชจ๋ธ์˜ ๋ณ€ํ™”๋ฅผ ์บ์น˜ํ•ด์„œ ๋ทฐ๋ฅผ ๋‹ค์‹œ Re-Rendring ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋Š”๊ฑธ๊นŒ?

์ง€๊ธˆ๊นŒ์ง€ @State, @binding, @published ๋“ฑ SwiftUI๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ณด๋˜ ํ”„๋กœํผํ‹ฐ ๋ž˜ํผ๋“ค์„ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ๊ฐ„๋‹จํ•œ๊ฒŒ ํŒŒ์•…ํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ์ •ํ™•ํ•˜๊ฒŒ ๋ถ„์„์ด ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

2) Parent๋ทฐ๊ฐ€ Re-Rendring ๋˜๋ฉด child ๋ทฐ๊ฐ€ init๋˜๋Š” ๋ฌธ์ œ์ 

Parent๋ทฐ์— Subview ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ์žˆ๋Š” case๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž. Parent ๋ทฐ๊ฐ€ ๋‹ค์‹œ Re-Rendring ๋  ๋•Œ, SubView๋“ค์ด ๋‹ค์‹œ init ๋œ๋‹ค.
์–ด์ฐŒ๋ณด๋ฉด ๋‹น์—ฐํ•˜์ง€๋งŒ ๋‹ค์‹œ init๋˜๋Š” ์‹œ์ ์ด ์ƒ์ดํ•˜๋‹ค.

1. @published๋ฅผ Binding ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ

struct ContentView: View {
  @StateObject
  var viewModel = ContentViewModel()

  @State
  var isShow: Bool = false

  init() {
    print("Content View Init")
  }

  var body: some View {
    VStack {
      Text("This is Parent View")

      Button(
        action: { viewModel.action(.sheetisShow) },
//        action: { isShow = true },
        label: {
          Text("PRESS")
        }
      )
      .buttonStyle(.plain)

      ChildView()
    }
    .padding()
    .fullScreenCover(isPresented: $viewModel.sheetisShow) {
      ModalView()
    }
  }
}

image

Binding๋ฅผ ๋ทฐ๋ชจ๋ธ์˜ @published ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ์—, ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ modal full screen์ด ๋„์› ๋‹ค๊ฐ€ ๋‹ค์‹œ ๋‚ด๋ฆด ๊ฒฝ์šฐ child view๊ฐ€ ์—ฌ๋Ÿฌ๋ฒˆ init๋˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฌผ๋ก  @StateObject๋กœ ์„ ์–ธ๋œ child view์˜ ๋ทฐ๋ชจ๋ธ์ด child view init ์‹œ์ ์— ๊ณ„์† init๋˜์ง€ ์•Š์•„ ํฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ ๋‹ค์Œ ์˜ˆ์‹œ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด์„œ ๋‹ค์‹œ ํ™•์ธํ•ด๋ณด์ž

2. @State๋ฅผ Binding ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ

struct ContentView: View {
  @StateObject
  var viewModel = ContentViewModel()

  @State
  var isShow: Bool = false

  init() {
    print("Content View Init")
  }

  var body: some View {
    VStack {
      Text("This is Parent View")

      Button(
//        action: { viewModel.action(.sheetisShow) },
        action: { isShow = true },
        label: {
          Text("PRESS")
        }
      )
      .buttonStyle(.plain)

      ChildView()
    }
    .padding()
    .fullScreenCover(isPresented: $isShow) {
      ModalView()
    }
  }
}

image

์œ„์™€ ๋™์ผํ•˜๊ฒŒ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ modal full screen์„ ๋„์šฐ๊ณ  ๋‹ค์‹œ content view๋กœ ๋Œ์•„์˜จ ๊ฒฝ์šฐ๋‹ค. @published์™€ @State ๋ฐ–์— ์ฐจ์ด๊ฐ€ ์—†๋Š”๋ฐ ์™œ ์ด๋ฒˆ ๊ฒฝ์šฐ์—๋Š” child view๊ฐ€ ์—ฌ๋Ÿฌ๋ฒˆ init๋˜์ง€ ์•Š์•˜์„๊นŒ?

๋งŒ์•ฝ ๋ถ€๋ชจ๋ทฐ๊ฐ€ Re-Rendring ๋˜๋ฉด์„œ ์ž์‹๋ทฐ๊ฐ€ init๋˜๋Š” ๊ฑฐ๋ผ๋ฉด, ๋ถ€๋ชจ๋ทฐ์˜ @State๊ฐ’์ด ๋ณ€ํ•˜๋“  @StateObject๊ฐ€ ๋ณ€ํ•˜๋“  ์ž์‹๋ทฐ๋Š” init์ด ๋˜์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š”๋ฐ ๋ฌด์Šจ ์ฐจ์ด ๋•Œ๋ฌธ์— ์ด๋Ÿฐ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์ •ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.

1)๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ”„๋กœํผํ‹ฐ ๋ž˜ํผ๋ฅผ ๊นŒ์„œ ์ •ํ™•ํ•˜๊ฒŒ ๋ฌธ์ œ๋ฅผ ํŒŒ์•…ํ•˜๋Š”๊ฒŒ ํ•„์š”ํ•˜๋‹ค.

@State

@State

struct MapView: View {
  var coordinate: CLLocationCoordinate2D
  @State private var region = MKCoordinateRegion()
  
  var body: some View {
    Map(coordinateRegion: $region)
      .onAppear {
        setRegion(coordinate)
        print("MapView onAppear")
      }
  }
  
  private func setRegion(_ coordinate: CLLocationCoordinate2D) {
    region = MKCoordinateRegion(
      center: coordinate,
      span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
    )
  }
}

์• ํ”Œ ์˜ˆ์ œ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด @State์™€ ๊ฐ™์€ ํ‚ค์›Œ๋“œ๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋Š” ๊ฑธ๊นŒ์š”?

์šฐ์„  ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ์‚ดํŽด๋ณด๋ฉด MapView๋Š” coordinate๋ผ๋Š” 2์ฐจ์› ์ขŒํ‘œ๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™” ๋˜๊ณ  View๊ฐ€ ๊ทธ๋ ค์ง€๋Š” ์‹œ์ ์—์„œ setRegion ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ region ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด ์ง€๋„๋ฅผ ๊ทธ๋ ค์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ขŒํ‘œ๊ฐ’์ด ๊ณ„์† ๋ฐ”๋€” ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ๋Œ€์‘ํ•ด์•ผ ํ• ๊นŒ์š”?

UIKit์˜ ๊ฒฝ์šฐ์—๋Š” Observer๋ฅผ ํ†ตํ•ด์„œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋งˆ๋‹ค ๋ทฐ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ SwiftUI๋Š” View๊ฐ€ ๊ตฌ์กฐ์ฒด๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฐธ์กฐ๊ฐ’์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— View๋ฅผ ์ƒˆ๋กœ ๊ทธ๋ ค์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ @State ๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋งˆ๋‹ค View๋ฅผ ๊ณ„์‚ฐํ•ด์„œ ๋‹ค์‹œ ๊ทธ๋ ค์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ Property Wrapper๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
ํ™•์‹คํžˆ ์ถ”๊ฐ€์ ์œผ๋กœ ์ •๋ฆฌํ•™ ํ•„์š”ํ•œ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์ผ๋‹จ ๋Œ€๋žต์ ์ธ ์—ญํ• ๋งŒ ์ดํ•ดํ•˜๊ณ  ๋‹ค๋ฅธ wapper๋“ค๊ณผ ํ•จ๊ป˜ ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Modifier

์ฐธ๊ณ  ๋งํฌ

struct ContentView: View {
  var body: some View {
    Text("Turtle Rock")
      .font(.title)
  }
}

SwiftUI์—์„œ .font() ์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ Text View์˜ font๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
SwiftUI์—์„œ๋Š” ์ด๋ ‡๊ฒŒ Modifier๋ฅผ ํ†ตํ•ด์„œ View๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Modifier๋ฅผ ํ†ตํ•ด์„œ ๋ทฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๊ธฐ์กด์˜ ๋ทฐ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ณ  ์ƒˆ๋กœ์šด ๋ทฐ๋ฅผ ๋งŒ๋“ ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค!

SwiftUI์—๋Š” ๊ฐ View ๋งˆ๋‹ค ๋ฏธ๋ฆฌ ์ •์˜๋œ Modifier๋ฅผ ํ†ตํ•ด์„œ View๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ณ  ViewModifierํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” ์ปค์Šคํ…€ํ•œ Modifier๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. (๊ณต์‹ ํ™ˆํŽ˜์ด์ง€์— ์„ค๋ช…์ด ์žˆ๋„ค์š”)

struct BorderedCaption: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.caption2)
            .padding(10)
            .overlay(
                RoundedRectangle(cornerRadius: 15)
                    .stroke(lineWidth: 1)
            )
            .foregroundColor(Color.blue)
    }
}

extension View {
    func borderedCaption() -> some View {
        modifier(BorderedCaption())
    }
}

์™€ ๊ฐ™์ด ์ปค์Šคํ…€ Modifier๋ฅผ ๋งŒ๋“ค๊ณ  ์ต์Šคํ…์…˜์„ ํ†ตํ•ด ์ถ”๊ฐ€ํ•˜๋ฉด View ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” View์—์„œ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


Modifier๋Š” ์ˆœ์„œ์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ’์ด ๋ฐ”๋€” ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

VStack {
    Text("Hello, World!")
      .frame(width: 200)
      .border(.gray, width: 2)
    Divider()
    Text("Hello, World!")
      .border(.gray, width: 2)
      .frame(width: 200)
  }

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 12 07 07

SwiftUI๋Š” ์ •๋ง ์ง๊ด€์ ์ด๋„ค์š”..


Modifier ์ ์šฉ์€ ํ•ด๋‹น ๋ทฐ์˜ ์ž์‹๋ทฐ์—๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

VStack {
      Text("Hello, World!")
        .frame(width: 200)
        .border(.gray, width: 2)
      Divider()
      Text("Hello, World!")
        .border(.gray, width: 2)
        .frame(width: 200)
    }
    .foregroundColor(.green)
  }

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 12 13 09

Vstack View์— ์ปฌ๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์ž์‹๋ทฐ(Text, Text) ๋„ ํ•จ๊ป˜ ์ ์šฉ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Stack

VStack

VStack {
  Text("Hello SwiftUI")
    .frame(width: 200)
  Text("Hello")
    .frame(width: 200)
}

์Šคํฌ๋ฆฐ์ƒท 2022-04-17 ์˜ค์ „ 2 45 32

VStack(alignment: .leading, spacing: 15) {
  Text("Hello SwiftUI")
  Text("Hello")
}
.padding()
.font(.subheadline)

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 1 45 23

Alignment๋ฅผ ํ†ตํ•ด ์ •๋ ฌ๋ฐฉ์‹์„ ์„ค์ •ํ•˜๊ณ  spcaing์„ ํ†ตํ•ด์„œ ๊ฐ„๊ฒฉ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


HStack

HStck์€ Vstack๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Vertical์„ Horizontal ํ•˜๊ฒŒ ๋ฐ”๊พธ๊ธฐ๋งŒ ํ•˜๋ฉด ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

HStack(spacing: 100) {
  Text("Hello SwiftUI")
  Text("Hello")
}
.padding()
.font(.subheadline)

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 2 08 30


ZStack

ZStack์€ Z์ถ•์œผ๋กœ ์ž์‹๋ทฐ๋“ค์„ ์Œ“์„ ์ˆ˜ ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ ๋ทฐ ์ž…๋‹ˆ๋‹ค. ์•ฝ๊ฐ„์€ ์ƒ์†Œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋…์ธ๋ฐ ์• ํ”Œ ์˜ˆ์ œ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ZStack {
  Rectangle()
    .fill(.red)
    .frame(width: 100, height: 50)
  Rectangle()
    .fill(.blue)
    .frame(width: 50, height: 100)
}

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 2 14 52

Alignment ๊ธฐ๋ณธ๊ฐ’์ด Center์ด๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์•™์„ ๊ธฐ์ค€์œผ๋กœ ๋‘ ๊ฐœ์˜ ์‚ฌ๊ฐํ˜•์ด ๊ฒน์น˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํŒŒ๋ž€์ƒ‰ ์‚ฌ๊ฐํ˜•์ด ๋นจ๊ฐ„์ƒ‰ ์‚ฌ๊ฐํ˜• ์œ„์— ์œ„์น˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์Šคํƒ์— ์„ ์–ธ๋œ ์ˆœ์„œ์— ๋”ฐ๋ผ ๋ณด์ด๋Š” ๊ฐ’์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํŠน์ดํ•œ ์ ์œผ๋กœ Zstack์—๋Š” Spacing์„ ์„ค์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋””์Šคํ”Œ๋ ˆ์ด๊ฐ€ 2D๋‹ˆ๊นŒ ๋‹น์—ฐํ•œ ๊ฑฐ๊ฒ ์ฃ ?

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-04-17 แ„‹แ…ฉแ„’แ…ฎ 2 27 58

[Combine] ๋ฒ„ํŠผ tap action ์— API call

@Published var signupButtonTapped = PassthroughSubject<Void, Never>()

private func transform() {
    signupButtonTapped
      .print("Before")
      .flatMap { _ in
        return AuthApiService.register(name: self.userName, email: self.userID, password: self.userPassword)
      } // weak self
      .print("After")
      .sink(receiveCompletion: { completion in
        print("completion:", completion)
      }, receiveValue: { value in
        print("ReceiveCompletion: ", value)
      })
      .store(in: &cancellables)
  }
  • ํ˜„์žฌ ๋ฒ„ํŠผ์„ ํƒญํ–ˆ์„ ๋•Œ, view์—์„œ viewModel์— ์žˆ๋Š” signupButtonTapped์— Void๋ฅผ send ํ•ด์ค€๋‹ค
  • ํ˜„์žฌ ๊ฐ’๋“ค์„ ๊ธฐ์ค€์œผ๋กœ API ํ†ต์‹ ํ•œ๋‹ค

์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋งŒ์•ฝ API ํ†ต์‹ ์—์„œ error๋กœ ์ŠคํŠธ๋ฆผ์ด ์ข…๋ฃŒ๋˜๋ฉด ๋ฒ„ํŠผ ๋™์ž‘์— ๋” ์ด์ƒ flatMap์„ ํ†ตํ•ด ์ƒ์„ฑ๋œ ์ŠคํŠธ๋ฆผ ์—ฐ๊ฒฐ์ด ๋Š๊ธฐ๊ฒŒ ๋œ๋‹ค(?)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.