@@ -10,42 +10,51 @@ import SwiftUI
1010
1111/// 시간, 분, 오전/오후 세 열을 나란히 배치하는 커스텀 타임 피커
1212public struct TTimePicker : View {
13- @State private var selectedHour : Int // 0 ~ 11 (표시 시에는 +1 해서 1~12)
14- @State private var selectedMinute : Int // 0 ~ 59
15- @State private var selectedPeriod : Int // 0: AM, 1: PM
13+ /// 선택된 시간이 종합되는 date
14+ @Binding private var date : Date
15+ /// 0 ~ 11 (표시 시에는 +1 해서 1~12)
16+ @State private var selectedHour : Int
17+ /// 분 선택은 내부적으로 분 배열의 인덱스로 저장 (예, minuteStep이 5면 0~11)
18+ @State private var selectedMinuteIndex : Int
19+ /// 0: AM, 1: PM
20+ @State private var selectedPeriod : Int
1621
17- // 설정값
22+ /// 셀 높이
1823 let rowHeight : CGFloat = 35
24+ /// 피커에 표시되는 셀 개수
1925 let visibleCount : Int = 5
26+ /// 선택되지 않은 시간 텍스트 폰트
2027 let normalFont : Font = Typography . FontStyle. heading4. font
28+ /// 선택된 시간 텍스트 폰트
2129 let selectedFont : Font = Typography . FontStyle. heading3. font
30+ /// 선택되지 않은 시간 텍스트 컬러
2231 let normalColor : Color = . neutral400
32+ /// 선택된 시간 텍스트 컬러
2333 let selectedColor : Color = . neutral900
34+ /// 분 단위 설정
35+ let minuteStep : Int
36+ // 무한 스크롤 사용 여부 - false로 설정하면 유한 스크롤
37+ let infiniteScroll : Bool = true
38+ /// 실제 분 값을 계산
39+ /// ex - minuteStep이 5이면 내부 저장값 7 -> 35분
40+ public var selectedMinute : Int {
41+ selectedMinuteIndex * minuteStep
42+ }
2443
25- // 무한 스크롤 사용 여부 (여기서 전체 피커에 대해 동일하게 설정할 수 있음)
26- let infiniteScroll : Bool = true // false로 설정하면 유한 스크롤이 됩니다.
27-
28- /// 현재 날짜와 시각을 기준으로 기본 선택값을 지정하는 initializer
29- public init (
30- selectedHour: Int = {
31- let calendar = Calendar . current
32- let hour24 = calendar. component ( . hour, from: . now)
33- // 12시간제로 변환 (0일 경우 12로, 나머지는 그대로)
34- let hour12 = hour24 % 12 == 0 ? 12 : hour24 % 12
35- // TTimePicker는 0이 "1시", 11이 "12시"에 해당하므로 -1 처리
36- return hour12 - 1
37- } ( ) ,
38- selectedMinute: Int = Calendar . current. component ( . minute, from: . now) ,
39- selectedPeriod: Int = {
40- let hour24 = Calendar . current. component ( . hour, from: . now)
41- // 0: AM, 1: PM (오전이면 0, 오후면 1)
42- return hour24 < 12 ? 0 : 1
43- } ( )
44- ) {
45- _selectedHour = State ( initialValue: selectedHour)
46- _selectedMinute = State ( initialValue: selectedMinute)
47- _selectedPeriod = State ( initialValue: selectedPeriod)
48- }
44+ public init ( selectedDate: Binding < Date > , minuteStep: Int = 1 ) {
45+ _date = selectedDate
46+
47+ let hour24 = Calendar . current. component ( . hour, from: selectedDate. wrappedValue)
48+ let hour12 = hour24 % 12 == 0 ? 12 : hour24 % 12
49+ let hour = hour12 - 1
50+ _selectedHour = State ( initialValue: hour)
51+
52+ let minute = Calendar . current. component ( . minute, from: selectedDate. wrappedValue)
53+ _selectedMinuteIndex = State ( initialValue: minute / minuteStep)
54+
55+ _selectedPeriod = State ( initialValue: hour24 < 12 ? 0 : 1 )
56+ self . minuteStep = minuteStep
57+ }
4958
5059 public var body : some View {
5160 ZStack {
@@ -64,21 +73,33 @@ public struct TTimePicker: View {
6473 normalColor: normalColor,
6574 selectedColor: selectedColor,
6675 infiniteScroll: infiniteScroll,
67- selected: $selectedHour
76+ selected: Binding ( get: {
77+ selectedHour
78+ } , set: {
79+ selectedHour = $0
80+ updateDate ( )
81+ } )
6882 )
6983 Text ( " : " )
7084 . typographyStyle ( . heading4, with: . neutral900)
71- // 분 열: "00" ~ "59"
85+ // 분 열: 생성 시 minuteStep에 따라 아이템 생성 (예, minuteStep 5 → [ "00","05",..., "55"])
7286 FlatPickerColumn (
73- items: ( 0 ..< 60 ) . map { String ( format: " %02d " , $0) } ,
87+ items: stride ( from: 0 , to: 60 , by: minuteStep)
88+ . map { String ( format: " %02d " , $0) } ,
7489 rowHeight: rowHeight,
7590 visibleCount: visibleCount,
7691 normalFont: normalFont,
7792 selectedFont: selectedFont,
7893 normalColor: normalColor,
7994 selectedColor: selectedColor,
8095 infiniteScroll: infiniteScroll,
81- selected: $selectedMinute
96+ selected: Binding (
97+ get: { selectedMinuteIndex } ,
98+ set: { newValue in
99+ selectedMinuteIndex = newValue
100+ updateDate ( )
101+ }
102+ )
82103 )
83104 Text ( " : " )
84105 . typographyStyle ( . heading4, with: . clear)
@@ -92,9 +113,31 @@ public struct TTimePicker: View {
92113 normalColor: normalColor,
93114 selectedColor: selectedColor,
94115 infiniteScroll: false ,
95- selected: $selectedPeriod
116+ selected: Binding (
117+ get: { selectedPeriod } ,
118+ set: { newValue in
119+ selectedPeriod = newValue
120+ updateDate ( )
121+ }
122+ )
96123 )
97124 }
98125 }
99126 }
127+
128+ private func updateDate( ) {
129+ var calendar : Calendar = Calendar . current
130+ calendar. timeZone = TimeZone ( secondsFromGMT: 0 ) ?? . current // UTC로 설정
131+ var components : DateComponents = calendar. dateComponents ( [ . year, . month, . day, . hour, . minute] , from: date)
132+
133+ // 24시간대로 시간 포맷 설정
134+ let hour24 : Int = ( selectedHour + 1 ) % 12 + ( selectedPeriod == 1 ? 12 : 0 )
135+
136+ components. hour = hour24
137+ components. minute = selectedMinute
138+
139+ if let newDate = calendar. date ( from: components) {
140+ date = newDate
141+ }
142+ }
100143}
0 commit comments