본문 바로가기

학습 노트

(174)
AutoScrolling #03 이번엔 Tab Indicator에 적절한 animation을 추가하기 위해 필요한 준비를 해 본다. Tab before enum Tab: String, CaseIterable { case dance = "Dance" case fruite = "Fruite" case mirror = "Mirror" case night = "Night" case road = "Road" } after enum Tab: String, CaseIterable { case dance = "Dance" case fruite = "Fruite" case mirror = "Mirror" case night = "Night" case road = "Road" var index: Int { return Tab.allCases.firstI..
AutoScrolling #02 화면 구성에 필요한 기본 인터페이스를 디자인한다. 사진을 표시할 ImageView들로 구성된 TabView와 해당 TabView와 연동되는 Tab Indicator를 구성한다. ImageView extension Home { func TabImageView(_ tab: Tab) -> some View { GeometryReader { let size = $0.size Image(tab.rawValue) .resizable() .aspectRatio(contentMode: .fill) .frame(width: size.width, height: size.height) .clipped() } .ignoresSafeArea(.container, edges: .bottom) } } 표시할 이미지의 크기를 기기의..
AutoScrolling #01 프로젝트는 MV 아키텍처를 사용한다. MVVM이나 MVC 대신 해당 아키텍처를 사용하도록 Apple을 권장하고 있고, 프로젝트의 구성이 조금 더 단순해진다는 장점이 있다. Assets Assets에는 TabView에 표시할 사진들을 추가한다. 원본은 3000 * 4000 크기의 사진들이지만 너무 과한 해상도의 사진은 비효율적이기에 이후에는 퍼포먼스 문제로 853 * 1280 수준으로 다운사이징 진행했다. Tab.swift // // Tab.swift // AutoScrolling // // Created by Martin.Q on 2023/03/14. // import SwiftUI /// Enum Tab Cases /// - rawValue: Asset Image Name enum Tab: String..
AutoScrolling #00 TabView와 Custom Indicator를 가지는 인터페이스를 구현한다. 크기를 조절하는 등의 방식으로 App의 배너에 유용히 사용할 수 있을 것으로 생각된다. 따라 해볼 강의는 TabView와 TabIndicator 까지만 구현하지만 심미성을 위해 약간의 디자인 요소를 추가해 본다. 기능 참고 강의는 아래와 같은 기능을 가지고 있다. 여러 사진을 하나씩 표현하는 TabView TabView와 연동되는 Custom Tab Indicator Tab Indicator의 양 끝에 적용되는 리바운드 효과 Tab Indicator에 적용되는 Animation 효과 추가적으로 구현할 기능은 다음과 같다. 표시되는 사진의 평균적인 색상을 구하기 구해진 평균 색상을 사용해 사진과 조화로운 Tab Indicator..
SwiftUI에서 Blur를 사용하는 4가지 방법 Blur Apple Developer Documentation developer.apple.com struct ContentView: View { var body: some View { ZStack() { Image("bg.sample") .resizable() .ignoresSafeArea() .scaledToFill() .blur(radius: 20) Text("Blur") .font(.largeTitle) .foregroundColor(.white) } } } iOS13 부터 지원하는 blur는 가장 간단한 방법이지만 Image Layer에 적용해야 한다는 단점이 존재한다. 이는 해당 방식으로는 TextView의 frame에만 blur 효과를 주기 어렵다는 의미이기도 하다. VisualEffect ..
33. AppStorage & SceneStorage AppStorage & SceneStorage AppStorarage와 SceneSotrage는 사용자의 선택사항을 저장한다. 둘을 사용하지 않고도 CoreData, Text file, Binary File을 사용해 구현하는 것도 가능하지만, 초기화 코드가 필요하고, 이를 위한 코드의 양이 만만치 않다. 따라서 SwiftUI에서는 OS가 제공하는 Default System이라는 기본 형식을 저장하는 기본 DB를 사용해 이를 간단히 해결할 수 있다. 이는 userDefaults로 Dictionary와 비슷하게 기능한다. AppStorage와 SceneStorage는 비슷하게 기능하지만. 이름대로 각각 App 전체와 특정 Scene에서 유효하다는 차이가 존재한다. @State private var numbe..
32. CoreData #2 CoreData #2 검색 기능 List { ForEach(members) { member in Button { editTarget = member } label: { HStack { Text(member.name!) .foregroundColor(.primary) Spacer() Text("\(member.age)") .foregroundColor(.secondary) } } } .onDelete(perform: delete(at:)) } .searchable(text: $keyword) .onChange(of: keyword, perform: { newValue in members.nsPredicate = newValue.isEmpty ? nil : NSPredicate(format: "name CO..
31. CoreData #1 CoreData #1 SwiftUI에서 CoreData를 사용해 CRUD를 구현해 본다. CoreData에는 MemberEntity가 존재하고, name과 age를 저장한다. SwiftUI에서 CoreData에 접근하는 방식은 UIKit에서 싱글톤 객체를 생성한 다음 mainContext에 접근하는 방식이 아닌, CoreData 자체를 공유 데이터로 설정해 각 View에서 접근하는 방식을 주로 사용한다. CoreData를 공유 데이터로 설정하기. @main struct DataPersistenceApp: App { let manager = CoreDataManager.shared var body: some Scene { WindowGroup { MainList() .environment(\.managed..
30. Gesture Tap Gesture .onTapGesture Apple Developer Documentation developer.apple.com struct TapGesture_Tutorials: View { @State private var tapCount = 0 var body: some View { VStack { Text("\(tapCount)") .font(.system(size: 250)) HStack { Image(systemName: "minus.circle") .font(.system(size: 100)) .foregroundColor(.red) .padding() .onTapGesture { tapCount -= 1 } Image(systemName: "plus.circle") .font(.sy..
29. List의 부가 기능 구현하기 List의 부가 기능 구현하기 Pull Refresh Apple Developer Documentation developer.apple.com 화면을 아래로 끌어당겨 새로고침 하는 iOS의 가장 보편적인 새로고침 방식이다. struct PullToRefresh: View { @State private var items = AppleProduct.sampleList[0 ..< 2] @State private var index = 2 var body: some View { List(items) { item in Text(item.name) } .animation(.easeInOut, value: items) .refreshable { await refresh() } } private func refresh(..