본문 바로가기

분류 전체보기

(340)
AutoScrolling #00 TabView와 Custom Indicator를 가지는 인터페이스를 구현한다. 크기를 조절하는 등의 방식으로 App의 배너에 유용히 사용할 수 있을 것으로 생각된다. 따라 해볼 강의는 TabView와 TabIndicator 까지만 구현하지만 심미성을 위해 약간의 디자인 요소를 추가해 본다. 기능 참고 강의는 아래와 같은 기능을 가지고 있다. 여러 사진을 하나씩 표현하는 TabView TabView와 연동되는 Custom Tab Indicator Tab Indicator의 양 끝에 적용되는 리바운드 효과 Tab Indicator에 적용되는 Animation 효과 추가적으로 구현할 기능은 다음과 같다. 표시되는 사진의 평균적인 색상을 구하기 구해진 평균 색상을 사용해 사진과 조화로운 Tab Indicator..
A&K XB10의 배터리를 교체해 보자 서론 자취방이라 스피커는 없어도 된다며 저소음 라이프를 즐기던 때가 있었다. 블루투스 송신기와 리시버를 사용했었는데 자그마한 사이즈에 평가도 좋던 XB10이 되시겠다. 아이리버 Astell&Kern AK XB10 (정품) : 다나와 가격비교 가전/TV>홈시어터/오디오>앰프/리시버>AV리시버, 요약정보 : 블루투스 수신기 / 블루투스 v4.1 / 프로파일: A2DP, AVRCP, HSP, HFP / 코덱: aptX, aptX HD, AAC, SBC / 입출력: AUX / 핸즈프리 / 내장배터리 / 충전시 prod.danawa.com 당시엔 매물이 없어 중고나라에 잠복하다 겨우 가져왔었고, 꽤나 잘 썼지만 갑자기 불어온 스피커 바람에 박스 안으로, 서람 안으로 방치만 되기 시작했다. 심야에 음악을 들을 일이..
06. 더 나아가기 더 나아가기 | 난이도 선택하기, 개선하기 강의는 끝났지만 난이도를 선택하는 부분은 빠져있다. enum FastingPlan: String { case beginner = "12:12" case intermediate = "16:8" case advanced = "20:4" var fastingPeriod: Double { switch self { case .beginner: return 12 case .intermediate: return 16 case .advanced: return 20 } } } beginner와 intermediate, advance를 화면에서 직접 선택할 수 있도록 추가로 구현한다. 난이도 선택하기 | 인터페이스 구성하기 현재 앱의 화면은 위와 같고, 난이도를 선택하기 위해 다..
05. 기능 구현 #3 기능 구현 #3 | Upcoming time, Percentage, 실제 시간 반영하기 Upcoming time 타이머의 상태가 notStarted이면 elapsedTime과 remainingTime을 표시하는 것은 부자연스럽다. 선택된 난이도에 따라서 현재시간을 기준으로 다음 식사 시간을 나타내도록 수정한다. // MARK: Timer VStack(spacing: 30) { // MARK: Upcoming Time if fastingManager.fastingState == .notStarted { VStack(spacing: 5) { Text("Upcoming fast") .opacity(0.7) Text("\(fastingManager.fastingPlan.fastingPeriod, specifie..
04. 기능 구현 #2 기능 구현 #2 | Timer 구현 Timer 구현 | fastingTime, feedingTime 계산하기 class FastingManager: ObservableObject { @Published private(set) var fastingState: FastingState = .notStarted @Published private(set) var fastingPlan: FastingPlan = .intermediate @Published private(set) var startTime: Date @Published private(set) var endTime: Date var fastingTime: Double { return fastingPlan.fastingPeriod } var feeding..
03. 기능 구현 #1 기능 구현 #1 | FastingManager FastingManager | FastingState FastingManager는 본격적인 식단 관리 기능의 구현에 해당한다. FastingManager라는 이름의 파일을 새로 생성해 구현한다. import Foundation class FastingManager: ObservableObject { } ObservableObject 프로토콜을 채용한 클래스의 형태로, 해당 해당 클래스에 접근하는 View가 Published로 지정된 속성을 사용할 수 있게 된다. import Foundation enum FastingState { case notStarted case fasting case feeding } class FastingManager: Observa..
02. 인터페이스 디자인 #2 인터페이스 디자인 #2 ContentView ContentView | Header body의 가독성을 높이기 위해 구성되는 View들은 extension으로 구현한다. header는 현재 상태를 문장으로 표시하기 위한 TextView와 이후 Fasting Plan을 변경하는 버튼을 포함한다. struct ContentView: View { var body: some View { VStack { header ProgressRing() } } } extension ContentView { // MARK: Title, Fasting Plan var header: some View { VStack { Text("Let's get started!") .font(.headline) .foregroundColor(C..
01. 인터페이스 디자인 #1 인터페이스 디자인 #1 ProgressRing, Timer ProgressRing ProgressRing은 총 진행상황을 표시할 PlaceHolder와 현재 진행 상황을 표시할 진행링 두 개의 View의 조합이다. 같은 좌표에 겹쳐 표시돼야 하므로 ZStack으로 구현한다. struct ProgressRing: View { @State var progress = 0.0 var body: some View { 우선 진행 상태를 나타낼 변수를 하나 정의한다. var body: some View { ZStack { // MARK: Placholder Ring Circle() .stroke(lineWidth: 20) .foregroundColor(Color(UIColor.systemGray)) .opacity(..
00. 시작하며 이제 막 UIKit에 대한 공부를 마치고 작은 프로젝트를 진행하던 작년에 이야기다. 작은 프로젝트를 몇 개 해 봤지만 여전히 개념들은 어려웠고, 특히나 만들려고 했던 인터벌 타이머는 thread 분리와 함께 완전히 박살났다. 1초 간격으로 실행 돼야 할 코드가 어느 때는 0.5초 만에, 어느 때는 1초가 넘어서 동작하니 제대로 된 기능을 한다고 볼 수 없다. 올해는 SwiftUI를 배웠고, 다시 이전의 프로젝트를 재시동 하기 전에 시계나 타이머에 관한 프로젝트를 몇 개 해 보고자 한다. 이번에 만들어 보는 FastingTimer는 식단 관리 앱이다. 원형의 Indicator를 가지고 진행 상황을 알려주고, 매 초 업데이트 되니 내가 구현하려던 매커니즘과 동일하다고 할 수 있다. 앱 Swift Swift ..
26. 기본 UI 구현하기 #9 기본 UI 구현하기 #9 프로필 수정 버튼 표시하기 ProfileView에는 EditProfile 버튼이 존재한다. 지금은 본인의 Profile인지 상대방의 Profile인지 구분 없이 Edit Profile을 표시하지만, 이 둘을 구분해 Follow 버튼으로 치환해 표시할 수 있도록 구현해 본다. class ProfileViewModel: ObservableObject { @Published var tweets = [Tweet]() @Published var likedTweets = [Tweet]() private let service = TweetService() private let userService = UserService() let user: User init(user: User) { sel..