๊ฐ๋ ๋์ค์ฝ๋๋ ํ์ํ์๋ฅผ ํ ๋ ์์ ๊ฐ๋จํ ๊ทธ๋ฆผํ์ด ํ์ํ๋ฐ, ๋งฅ๋ถ์์ ๊ธฐ๋ณธ ๊ทธ๋ฆผํ ํ๋ก๊ทธ๋จ์ด ์๋ณด์ฌ ๋ง๋ค์๋ค.
1. ์ฃผ์ ๊ธฐ๋ฅ
- ๊ธฐ๋ณธ ์์ ํ๋ ํธ 8๊ฐ + ์ต๊ทผ ์ฌ์ฉ ์์ 8๊ฐ
- ์์ ๋กญ๊ฒ ์ ๊ทธ๋ฆฌ๊ธฐ
- Undo / Redo (โZ / โงโZ)
- ColorPicker๋ก ์ฌ์ฉ์ ์ง์ ์์ ์ถ๊ฐ
- Clear ๋ฒํผ์ผ๋ก ์ ์ฒด ์ด๊ธฐํ
2. ๊ตฌ์กฐ
Paint/
โโโ PaintApp.swift # ์ฑ ์์์
โโโ ContentView.swift # ๋ฉ์ธ ๋ทฐ
โโโ CanvasView.swift # ๊ทธ๋ฆผ ๊ทธ๋ฆฌ๋ ๋ก์ง์ด ๋ค์ด์๋ ํ์ ๋ทฐ
โโโ DrawingPath.swift # ์ ์ ๊ตฌ์ฑํ๋ ๋ชจ๋ธ
โโโ DrawingViewModel.swift # ์ ์ฒด ์ ๋ชฉ๋ก ๋ฐ undo/redo ๊ด๋ฆฌํ๋ ViewModel
SwiftUI ์ํ ์ด๋ ธํ ์ด์
์ด๋ ธํ ์ด์ | ์ฉ๋ | ์์น | ์ฌ์ฉ ์์ |
@State | ๋จ์ํ ๊ฐ | View ๋ด๋ถ | ์ ํ๋ ์์, ์ต๊ทผ ์์ |
@StateObject | ViewModel์ ์ง์ ์์ฑํ ๋ | ์ต์์ View | DrawingViewModel |
@ObservedObject | ์์์์ ๋ง๋ ViewModel์ ํ์์์ ๊ด์ฐฐํ ๋ | ์์ View | CanvasView์์ ContentView์์ ์ ์ธ๋ DrawingViewModel์ ์ ๋ฌ๋ฐ์ |
1. @State: ๋จ์ํ ๊ฐ ๊ด๋ฆฌ
์ฌ์ฉ์๊ฐ ํด๋ฆญํ ์์์ด๋ ์ต๊ทผ ์์ ๋ชฉ๋ก์ ๋จ์ํ ๊ฐ์ผ๋ก ๋ทฐ ๋ด๋ถ์์ ๊ด๋ฆฌ
@State private var selectedColor: Color = .black
@State private var recentColors: [Color] = []
2. @StateObject: ์ํ ๊ฐ์ฒด(ViewModel) ์์ฑ ๋ฐ ์์
๊ฒฝ๋ก(๊ทธ๋ ค์ง ์ ) , redo stack, clear, undo/redo ๋ก์ง ๋ฑ ์ํ ๊ด๋ฆฌ
@StateObject private var viewModel = DrawingViewModel()
3. @ObservedObject: ์์ ๋ทฐ์์ ViewModel ์ฐธ์กฐ
์์ View์์ ์์ฑํ ViewModel์ CanvasView๊ฐ ๊ด์ฐฐํ๋ฉฐ ๋ ๋๋ง
# ContentView - ์์ ๋ทฐ
struct ContentView: View {
@Environment(\.undoManager) private var undoManager
@StateObject private var viewModel = DrawingViewModel()
@State private var selectedColor: Color = .black
@State private var recentColors: [Color] = []
...
CanvasView(
paths: $viewModel.paths,
viewModel: viewModel,
selectedColor: selectedColor,
lineWidth: 2,
onDrawingEnded: { newPath in
viewModel.addPath(newPath, using: undoManager)
updateRecentColors(selectedColor)
}
)
}
# CanvasView - ํ์ ๋ทฐ
struct CanvasView: View {
@Binding var paths: [DrawingPath]
@ObservedObject var viewModel: DrawingViewModel
let selectedColor: Color
let lineWidth: CGFloat
let onDrawingEnded: (DrawingPath) -> Void
...
}
UndoManager ์ฐ๋(โZ, โงโZ)
@Environment(\.undoManager) private var undoManager # ์ ์ญ ๋ณ์ ์ ์ธ
# ContentView.swift - ์ปค๋งจ๋ ๋ฑ๋ก
.onCommand(#selector(UndoManager.undo)) {
viewModel.undo(using: undoManager)
}
.onCommand(#selector(UndoManager.redo)) {
viewModel.redo(using: undoManager)
}
# DrawingViewModel.swift - ์ค์ ๋์ ํจ์
func undo(using undoManager: UndoManager?) {
guard let last = paths.popLast() else { return }
redoStack.append(last)
undoManager?.registerUndo(withTarget: self) { target in
target.redo(using: undoManager)
}
}
func redo(using undoManager: UndoManager?) {
guard let last = redoStack.popLast() else { return }
paths.append(last)
undoManager?.registerUndo(withTarget: self) { target in
target.undo(using: undoManager)
}
}
https://github.com/sungchan1/swift-paint
GitHub - sungchan1/swift-paint: swift-paint
swift-paint. Contribute to sungchan1/swift-paint development by creating an account on GitHub.
github.com
'๐ Diary' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[2024] ์ผ์ฑ์ ์ SW ์ฑ์ฉ ์ผ์ (0) | 2024.07.02 |
---|---|
[์ ๋ณด์ฒ๋ฆฌ๊ธฐ์ฌ] ์ ๋ณด์ฒ๋ฆฌ๊ณ ์ฌ ๋๋ ์ + ๊ณต๋ถ๋ฒ (2) | 2024.04.28 |
Apple Vision Pro ์์ํ๊ธฐ (0) | 2024.01.21 |
[MAC] M1 ๋งฅ๋ถ ํ๋ก 16์ธ์น ๋งฅ์ธ์ดํ ์ถฉ์ ํฌํธ ์๋ฆฌ (feat. ๋ํ TUVA) (0) | 2023.11.12 |
๊ฐ๋ฐ์๋ ๊ถ๊ธํ IT ์ธํ๋ผ (0) | 2022.11.22 |