Skip to content

Commit 130b20d

Browse files
authored
[NL-60] : 프로필 편집 화면 view 구성 (#39)
* [NL-60] : 프로필 편집 화면 view 구성 * [NL-60] : View모델 생성 과 연결
1 parent bb06850 commit 130b20d

File tree

13 files changed

+1179
-31
lines changed

13 files changed

+1179
-31
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//
2+
// SettingRoute.swift
3+
// CommonLayer
4+
//
5+
// Created by 최재혁 on 8/16/25.
6+
//
7+
8+
public enum SettingRoute {
9+
case myPage
10+
case pushSetting
11+
case editProfile
12+
case timePicker
13+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// UIResponder.swift
3+
// CoreLayer
4+
//
5+
// Created by 최재혁 on 8/16/25.
6+
//
7+
8+
import UIKit
9+
10+
extension UIResponder {
11+
private static weak var _currentFirstResponder: UIResponder? = nil
12+
13+
public static var currentFirstResponder: UIResponder? {
14+
_currentFirstResponder = nil
15+
UIApplication.shared.sendAction(
16+
#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
17+
return _currentFirstResponder
18+
}
19+
20+
@objc private func findFirstResponder(sender: Any) {
21+
UIResponder._currentFirstResponder = self
22+
}
23+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//
2+
// DontKnowTimeView.swift
3+
// FeatureLayer
4+
//
5+
// Created by 최재혁 on 7/27/25.
6+
//
7+
8+
import SnapKit
9+
import Then
10+
import UIKit
11+
12+
public final class CheckBox: UIControl {
13+
14+
private let checkboxImageView = UIImageView().then {
15+
$0.contentMode = .center
16+
$0.backgroundColor = STColors.white.color
17+
18+
$0.layer.borderColor = STColors.gray7.color.cgColor
19+
$0.layer.borderWidth = 1.5
20+
$0.layer.cornerRadius = 6
21+
22+
$0.image = STImages.check.image
23+
$0.isUserInteractionEnabled = false
24+
}
25+
26+
private let titleLabel = UILabel().then {
27+
var style = Typography.Body_16_M
28+
style.color = STColors.gray1.color
29+
$0.style = style
30+
$0.styledText = "check box"
31+
$0.isUserInteractionEnabled = false
32+
}
33+
34+
// MARK: - 공개 속성
35+
public var title: String? {
36+
get { titleLabel.text }
37+
set {
38+
titleLabel.styledText = newValue
39+
40+
updateTitle()
41+
}
42+
}
43+
44+
public override var isSelected: Bool {
45+
didSet {
46+
updateAppearance()
47+
}
48+
}
49+
50+
public override var isEnabled: Bool {
51+
didSet {
52+
updateAppearance()
53+
}
54+
}
55+
56+
// MARK: - 초기화
57+
override init(frame: CGRect) {
58+
super.init(frame: frame)
59+
setupView()
60+
}
61+
62+
required init?(coder: NSCoder) {
63+
fatalError("init(coder:) has not been implemented")
64+
}
65+
66+
// MARK: - 설정
67+
private func setupView() {
68+
self.backgroundColor = .clear
69+
70+
addSubview(checkboxImageView)
71+
addSubview(titleLabel)
72+
73+
checkboxImageView.snp.makeConstraints {
74+
$0.leading.centerY.equalToSuperview()
75+
$0.width.height.equalTo(20)
76+
}
77+
78+
titleLabel.snp.makeConstraints {
79+
$0.leading.equalTo(checkboxImageView.snp.trailing).offset(6)
80+
$0.centerY.equalToSuperview()
81+
$0.trailing.lessThanOrEqualToSuperview()
82+
}
83+
84+
// 콘텐츠에 따라 최소 높이 설정
85+
self.snp.makeConstraints {
86+
$0.height.greaterThanOrEqualTo(24)
87+
}
88+
89+
updateTitle()
90+
}
91+
92+
// MARK: - UI 업데이트
93+
private func updateAppearance() {
94+
if isEnabled {
95+
checkboxImageView.image = STImages.check.image
96+
if isSelected {
97+
checkboxImageView.backgroundColor = STColors.primary2.color
98+
checkboxImageView.layer.borderColor = STColors.primary2.color.cgColor
99+
} else {
100+
checkboxImageView.backgroundColor = STColors.white.color
101+
checkboxImageView.layer.borderColor = STColors.gray7.color.cgColor
102+
}
103+
} else {
104+
checkboxImageView.backgroundColor = STColors.gray9.color
105+
if isSelected {
106+
checkboxImageView.layer.borderColor = STColors.gray9.color.cgColor
107+
checkboxImageView.image = STImages.checkGray.image
108+
} else {
109+
checkboxImageView.layer.borderColor = STColors.gray7.color.cgColor
110+
checkboxImageView.image = nil
111+
}
112+
}
113+
}
114+
115+
private func updateTitle() {
116+
if isEnabled {
117+
titleLabel.textColor = STColors.gray1.color
118+
} else {
119+
titleLabel.textColor = STColors.gray6.color
120+
}
121+
122+
updateAppearance()
123+
}
124+
125+
// MARK: - 터치 처리
126+
public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
127+
super.touchesEnded(touches, with: event)
128+
if isEnabled {
129+
isSelected.toggle()
130+
sendActions(for: .valueChanged) // 상태 변경 시 .valueChanged 이벤트를 보냅니다.
131+
}
132+
}
133+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//
2+
// GenderSelectionView.swift
3+
// FeatureLayer
4+
//
5+
// Created by 최재혁 on 7/26/25.
6+
//
7+
8+
import SnapKit
9+
import Then
10+
import UIKit
11+
12+
// MARK: - GenderSelectionViewDelegate (성별 선택 그룹에서 선택된 성별을 알리는 프로토콜)
13+
protocol GenderSelectionViewDelegate: AnyObject {
14+
func genderSelectionView(_ view: GenderSelectionView, didSelectGender gender: String?)
15+
}
16+
17+
// MARK: - GenderSelectionView (라디오 버튼 그룹)
18+
public final class GenderSelectionView: UIView {
19+
20+
// 델리게이트를 통해 상위 뷰에 선택된 성별을 알림
21+
weak var delegate: GenderSelectionViewDelegate?
22+
23+
// 라디오 버튼들을 정렬하기 위한 스택 뷰
24+
private let stackView = UIStackView().then {
25+
$0.axis = .horizontal
26+
$0.spacing = 20
27+
}
28+
29+
private var radioButtons: [RadioButtonView] = []
30+
31+
// 현재 선택된 성별 텍스트
32+
private var selectedGender: String? {
33+
didSet {
34+
delegate?.genderSelectionView(self, didSelectGender: selectedGender)
35+
}
36+
}
37+
38+
// 코드 기반 초기화
39+
override init(frame: CGRect) {
40+
super.init(frame: frame)
41+
setupView()
42+
}
43+
44+
required init?(coder: NSCoder) {
45+
super.init(coder: coder)
46+
setupView()
47+
}
48+
49+
// 뷰의 초기 설정
50+
private func setupView() {
51+
addSubview(stackView)
52+
53+
stackView.snp.makeConstraints { make in
54+
make.edges.equalToSuperview()
55+
}
56+
57+
addGenderOptions()
58+
}
59+
60+
// 성별 옵션 (남성, 여성) 라디오 버튼 추가
61+
private func addGenderOptions() {
62+
let maleRadioButton = RadioButtonView().then {
63+
$0.title = "남성"
64+
$0.delegate = self
65+
}
66+
67+
radioButtons.append(maleRadioButton)
68+
stackView.addArrangedSubview(maleRadioButton)
69+
70+
let femaleRadioButton = RadioButtonView().then {
71+
$0.title = "여성"
72+
$0.delegate = self
73+
}
74+
radioButtons.append(femaleRadioButton)
75+
stackView.addArrangedSubview(femaleRadioButton)
76+
}
77+
78+
// 특정 인덱스의 라디오 버튼을 선택 상태로 만듦
79+
private func selectRadioButton(at index: Int) {
80+
guard index < radioButtons.count else { return }
81+
82+
for (i, button) in radioButtons.enumerated() {
83+
button.isSelected = (i == index)
84+
}
85+
selectedGender = radioButtons[index].title
86+
}
87+
88+
public func setInitialSelection(gender: String) {
89+
if gender == "남성", let index = radioButtons.firstIndex(where: { $0.title == "남성" }) {
90+
selectRadioButton(at: index)
91+
} else if gender == "여성", let index = radioButtons.firstIndex(where: { $0.title == "여성" }) {
92+
selectRadioButton(at: index)
93+
}
94+
}
95+
}
96+
97+
extension GenderSelectionView: RadioButtonViewDelegate {
98+
// MARK: - RadioButtonViewDelegate (RadioButtonView로부터 탭 이벤트 수신)
99+
func radioButtonView(_ radioButtonView: RadioButtonView, didSelect isSelected: Bool) {
100+
// 어떤 라디오 버튼이 탭되었는지 확인하고 해당 버튼을 선택 상태로 만듦
101+
for (i, button) in radioButtons.enumerated() {
102+
if button === radioButtonView { // 탭된 버튼이 현재 버튼과 동일한 경우
103+
selectRadioButton(at: i) // 해당 버튼을 선택 상태로 설정
104+
break
105+
}
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)