인터페이스 디자인 #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(Color(#colorLiteral(red: 0.8567120433, green: 0.5915268064, blue: 1, alpha: 1)))
}
}
}
진행링과 같은 색으로 현재 상태를 표시한다.
지금은 임시 문자열을 표시하지만 이후엔 상태에 맞는 문자열을 표시하도록 구현한다.
import SwiftUI
import SwiftUIVisualEffects
struct ContentView: View {
var body: some View {
VStack {
header
ProgressRing()
}
}
}
extension ContentView {
var header: some View {
VStack {
// MARK: Title
Text("Let's get started!")
.font(.headline)
.foregroundColor(Color(#colorLiteral(red: 0.8567120433, green: 0.5915268064, blue: 1, alpha: 1)))
// MARK: Fasting Plan
Text("16:8")
.fontWeight(.bold)
.padding(.horizontal, 24)
.padding(.vertical, 8)
.background(BlurEffect().blurEffectStyle(.systemThickMaterial))
.cornerRadius(25)
}
}
}
아래쪽엔 현재 진행 중인 Fasting Plan을 표시한다.
마찬가지로 임시로 표시하고 있지만 사용자가 선택한 Fasting Plan을 알맞게 표시하도록 구현한다.
Capsule 모양의 배경은 호환성을 위해 SwiftUI의 Matetial 대신 swiftui visual effects 패키지를 사용했다.
자세한 내용은 위 글을 참고하면 된다.
ContentView
| Times
extension ContentView {
var header: some View {
.
.
.
}
var times: some View {
HStack(spacing: 60) {
// MARK: Start Time
VStack(spacing: 5) {
Text("Start")
.opacity(0.7)
Text(Date(), formatter: Self.DateFormat)
.fontWeight(.bold)
}
// MARK: End Time
VStack(spacing: 5) {
Text("End")
.opacity(0.7)
Text(Date(), formatter: Self.DateFormat)
.fontWeight(.bold)
}
}
}
}
times는 시작 시간과 끝나는 시간을 표시한다.
Date를 String으로 치환해 사용하며, 이러한 방식은 iOS의 버전에 따라 두 가지 방식이 존재한다.
Text(Date(), format: .dateTime.weekday().hour().minute().second())
.fontWeight(.bold)
iOS15부터는 Text(_:format:)을 사용하고, format 파라미터에 .dateTime으로 시작하는 체이닝을 전달해 변환할 수 있다.
static let DateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "E h:mm:ss a"
return formatter
}()
Text(Date(), formatter: Self.DateFormat)
.fontWeight(.bold)
iOS15 이전까지는 DateFormatter를 정의하고 Text(_:formatter:)의 formatter 파라미터에 전달해 변환한다.
Source
extension ContentView {
var header: some View {
.
.
.
}
var times: some View {
HStack(spacing: 60) {
// MARK: Start Time
VStack(spacing: 5) {
Text("Start")
.opacity(0.7)
if #available(iOS 15.0, *) {
Text(Date(), format: .dateTime.weekday().hour().minute().second())
.fontWeight(.bold)
} else {
Text(Date(), formatter: Self.DateFormat)
.fontWeight(.bold)
}
}
// MARK: End Time
VStack(spacing: 5) {
Text("End")
.opacity(0.7)
Text(Date().addingTimeInterval(16), formatter: Self.DateFormat)
.fontWeight(.bold)
}
}
}
}
extension ContentView {
// MARK: DateFormat
static let DateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "E h:mm:ss a"
return formatter
}()
}
분기 코드는 위와 같고
결과는 사진과 같다.
formatter를 사용해도 조금 귀찮을 뿐이지 iOS15와 동일하게 구현하는 것이 얼마든지 가능하다.
ContentView
| strBtn
extension ContentView {
var header: some View {
.
.
.
}
var times: some View {
.
.
.
}
var strBtn: some View {
Button {
// MARK: Button Action
} label: {
Text("Start Fasting")
.font(.title3)
.fontWeight(.bold)
.padding(.horizontal, 24)
.padding(.vertical, 8)
.background(BlurEffect().blurEffectStyle(.systemThickMaterial))
.cornerRadius(25)
}
.foregroundColor(.primary)
}
}
가장 아래에는 Timer를 시작 할 버튼을 하나 배치한다.
foregroundColor를 단순한 black이 아닌 primary를 사용하면 Scheme에 따라 적절히 반응하는 UI를 구현할 수 있다.
struct ContentView: View {
var body: some View {
VStack(spacing: 40) {
header
ProgressRing()
times
strBtn
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
}
마지막으로 정렬과 간격을 적당히 손 보면 완성이다.
Source
//
// ContentView.swift
// FastingTimer_B
//
// Created by Martin.Q on 2023/02/15.
//
import SwiftUI
import SwiftUIVisualEffects
struct ContentView: View {
var body: some View {
VStack(spacing: 40) {
header
ProgressRing()
times
strBtn
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension ContentView {
var header: some View {
VStack(spacing: 40) {
// MARK: Title
Text("Let's get started!")
.font(.headline)
.foregroundColor(Color(#colorLiteral(red: 0.8567120433, green: 0.5915268064, blue: 1, alpha: 1)))
// MARK: Fasting Plan
Text("16:8")
.fontWeight(.bold)
.padding(.horizontal, 24)
.padding(.vertical, 8)
.background(BlurEffect().blurEffectStyle(.systemThickMaterial))
.cornerRadius(25)
}
}
var times: some View {
HStack(spacing: 60) {
// MARK: Start Time
VStack(spacing: 5) {
Text("Start")
.opacity(0.7)
if #available(iOS 15.0, *) {
Text(Date(), format: .dateTime.weekday().hour().minute().second())
.fontWeight(.bold)
} else {
Text(Date(), formatter: Self.DateFormat)
.fontWeight(.bold)
}
}
// MARK: End Time
VStack(spacing: 5) {
Text("End")
.opacity(0.7)
Text(Date().addingTimeInterval(16), formatter: Self.DateFormat)
.fontWeight(.bold)
}
}
}
var strBtn: some View {
Button {
// MARK: Button Action
} label: {
Text("Start Fasting")
.font(.title3)
.fontWeight(.bold)
.padding(.horizontal, 24)
.padding(.vertical, 8)
.background(BlurEffect().blurEffectStyle(.systemThickMaterial))
.cornerRadius(25)
}
.foregroundColor(.primary)
}
}
extension ContentView {
// MARK: DateFormat
static let DateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "E h:mm:ss a"
return formatter
}()
}
'프로젝트 > FastingTimer' 카테고리의 다른 글
05. 기능 구현 #3 (0) | 2023.02.20 |
---|---|
04. 기능 구현 #2 (0) | 2023.02.17 |
03. 기능 구현 #1 (0) | 2023.02.16 |
01. 인터페이스 디자인 #1 (0) | 2023.02.14 |
00. 시작하며 (0) | 2023.02.09 |