Skip to content

Comments

Style/#56 커스텀 피커#57

Merged
soseoyo12 merged 4 commits intodevelopfrom
style/#56-customPicler
Jan 14, 2026
Merged

Style/#56 커스텀 피커#57
soseoyo12 merged 4 commits intodevelopfrom
style/#56-customPicler

Conversation

@soseoyo12
Copy link
Contributor

🔗 연결된 이슈

📄 작업 내용

  • 커스텀 피커 구현
구현 내용 IPhone 16 pro IPhone 13 mini
GIF image image

💻 주요 코드 설명

전체 구조

크게 두개의 struct인데

  1. CustomWheelPicker: Picker에 커스텀 디자인은 래핑하는 역할!
  2. PickerViewRepresentable: UIKit 컴포넌트를 SwiftUI에 이식하기 위해 필요

CustomWheelPicker

코드를 보면 ZStack으로 UI래핑중!!

struct CustomWheelPicker: View {
    @Binding var selection: Int
    let range: ClosedRange<Int>
    var width: CGFloat = 80

    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 12)
                .fill(.gray300)
                .frame(width: width, height: 44)
            
            PickerViewRepresentable(selection: $selection, range: range)
                .frame(width: width + 20, height: 132)
        }
        .frame(width: width, height: 132)
        .clipped()
    }
}

PickerViewRepresentable

UIKit에서 SwiftUI로 이식하려면 막 하면 안되겠져
따라서 UIViewRepresentable라는 프로토콜을 채택해야함!!

이 프로토콜을 채택하면 어떤것을 구현해야하느냐 ->

필수 구현

// 1. UIKit 뷰 생성
func makeUIView(context: Context) -> UIViewType

// 2. SwiftUI 상태 변경 시 UIKit 뷰 업데이트
func updateUIView(_ uiView: UIViewType, context: Context)

네~ 화면 그려야되고 상태 바뀌면 반영해야되니까 두개 전부 구현해야합니다

하나씩 설명해볼게요

makeUIView
func makeUIView(context: Context) -> UIPickerView {
        let picker = UIPickerView()
        picker.delegate = context.coordinator
        picker.dataSource = context.coordinator
        
        let row = selection - range.lowerBound
        picker.selectRow(row, inComponent: 0, animated: true)
        
        return picker
    }

coordinator: 아래에 나오니까 아래에서 확인!!

let row = selection - range.lowerBound : row(행)랑 selection을 구분해줘야하는데 index를 다룰때에는 row를 쓰고 사용자가 선택하는 순서는 selection을 씁니다 근데 index는 0부터 selection은 1부터 시작해서 이 값을 보정해주는 과정입니다

picker.selectRow(row, inComponent: 0, animated: true): 피커 처음 만들때 초기값을 어떤 걸 줄지!
inComponent: 몇번째 열인지! 다중열인 피커도 있기 때문에 선택해줘야합니다. 저의 케이스에서는 하나 밖에 없기때문에 0
animated: 행이 강제로 선택될때(버튼으로 row값 조절 등) 뚝뚝 끊기면서 선택될지 아니면 에니메이션을 줄지 여부

updateUIView
func updateUIView(_ uiView: UIPickerView, context: Context) {
        let row = selection - range.lowerBound
        if uiView.selectedRow(inComponent: 0) != row {
            uiView.selectRow(row, inComponent: 0, animated: true)
        }
    }

SwiftUI의 @Binding var selection 값이 바뀔 때마다 호출됩니다.

selectedRow(inComponent: 0): 피커가 현재 가리키고 있는 행 인덱스 반환.
"피커의 현재 위치"랑 "selection에서 계산한 위치"가 다를 때만 위치로 이동!

선택 구현

// 3. Coordinator 생성 (delegate/dataSource 필요할 때) -> 데이터 전달!! 데이터 관리가 필요할때!!!!!!!!!!
func makeCoordinator() -> Coordinator

// 4. 뷰가 사라질 때 정리 작업
static func dismantleUIView(_ uiView: UIViewType, coordinator: Coordinator)

입니다.

func makeCoordinator() -> Coordinator {
        Coordinator(self) //코디네이터 생성!
    }

static func dismantleUIView의 경우에는 커스텀 피커 구현에서 사용하지 않습니다.

UIKit에선 뷰와 데이터 사이에 뷰컨이 열일을!! SwiftUI에선?

네~ 그 사이를 채워주는 역할을 담당하는것이 Coordinator입니다 (코디네이터 패턴아닙니다.)
만들어줘야겠져

class Coordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource

위와 같이 델리게이트, 데이터소스 프로토콜을 채택하게 되는데

DataSource (필수 2개)

  • numberOfComponents(in:) — 필수
  • pickerView(_:numberOfRowsInComponent:) — 필수

Delegate (전부 optional)

  • didSelectRow — 선택 이벤트 받고 싶으면
  • viewForRow — 커스텀 UI 원하면
  • rowHeightForComponent — 높이 바꾸고 싶으면

인데 각 각의 메서드를 설명해보도록 하겠습니다~

func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 }

열을 몇개 사용할건지!


 func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
    parent.range.count 
}

열에 행이 몇개인지

component를 매개변수로 받는 이유

만약 피커가 "년 | 월 | 일" 3열이면:

  • component == 0 → 년도 열 → "2000~2025니까 26개"
  • component == 1 → 월 열 → "12개"
  • component == 2 → 일 열 → "31개"

component에 따라서 다른 값을 줘야하기 때문

근데 항상 component가 0이 들어오기 때문에 그냥 parent.range.count를 반환

만약 여러개였으면

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    switch component {
    case 0: return years.count
    case 1: return 12
    case 2: return 31
    default: return 0
    }
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    parent.selection = parent.range.lowerBound + row
}

유저가 휠 굴려서 선택이 확정됐을 때. 휠이 멈추고 가운데에 딱 고정되는 순간. 호출

매개변수:

  • pickerView: 이벤트가 발생한 피커 자체
  • row: 선택된 행의 인덱스 (0부터 시작)
  • component: 몇 번째 열에서 선택됐는지 (여기선 열이 1개라 항상 0)

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView

피커가 각 행을 그릴 때마다. 화면에 보이는 행마다 한 번씩 호출

매개변수:

  • pickerView: 피커 자체
  • row: 그리려는 행의 인덱스 (0부터)
  • component: 몇 번째 열인지 (여기선 항상 0)
  • reusing view: 재사용 가능한 뷰 (있으면 UIView, 없으면 nil) 이거 그냥 콜뷰쓸때 셀 재사용하는거랑 같음

반환값:

  • UIView — 이 행에 표시할 뷰를 직접 만들어서 반환

기본 피커는 그냥 텍스트만 보여줌 근데 이 메서드 쓰면 폰트, 색상, 이미지 등 완전 커스텀 가능

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
    // 1. 기본 divider 라인 제거
    pickerView.subviews.forEach { subview in
        subview.backgroundColor = .clear
    }
    
    // 2. 라벨 생성 또는 재사용
    let label = (view as? UILabel) ?? UILabel()
    
    // 3. 라벨 설정
    label.text = "\(parent.range.lowerBound + row)"
    label.textAlignment = .center
    label.font = UIFont.systemFont(ofSize: 24, weight: .semibold)
    label.textColor = .label
    
    return label
}

재사용 로직

let label = (view as? UILabel) ?? UILabel()
  • view가 UILabel이면 → 그거 그대로 써
  • view가 nil이거나 다른 타입이면 → 새 UILabel 생성

사용법

struct MyView: View {
	@State private var selectedValue: Int = 5
	var body: some View {
		CustomWheelPicker(selection: $selectedValue, range: 1...10)
	}
}

@soseoyo12 soseoyo12 requested a review from a team January 13, 2026 17:12
@soseoyo12 soseoyo12 self-assigned this Jan 13, 2026
@soseoyo12 soseoyo12 requested review from sum130, wotjs020708 and y-eonee and removed request for a team January 13, 2026 17:12
@soseoyo12 soseoyo12 linked an issue Jan 13, 2026 that may be closed by this pull request
1 task
@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

SwiftUI에서 UIKit의 UIPickerView를 감싼 커스텀 휠 피커 CustomWheelPicker가 추가되었습니다. UIViewRepresentable 기반의 내부 브리징(PickerViewRepresentable)과 Coordinator를 통해 바인딩된 정수 선택(ClosedRange)을 동기화합니다.

Changes

Cohort / File(s) Change summary
커스텀 휠 피커 컴포넌트
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift
신규 파일: CustomWheelPicker SwiftUI View 추가. 내부 PickerViewRepresentable(UIViewRepresentable) 및 Coordinator 구현. UIPickerView 데이터소스/델리게이트 연동, 바인딩 동기화, 초기/업데이트 선택 동기화, UI 레이블/스타일 지정.
애셋: 색상 그라디언트
Cherrish-iOS/Cherrish-iOS/Assets.xcassets/Color/home_gradient1.colorset/Contents.json, Cherrish-iOS/Cherrish-iOS/Assets.xcassets/Color/home_gradient2.colorset/Contents.json
신규 색상 세트 추가(Contents.json). display-p3 색공간 및 다크 모드 출현 설정 포함.
애셋: 홈 아이콘 & 이미지셋
Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/Contents.json, .../cherrish_character.imageset/Contents.json, .../cherrish_logo.imageset/Contents.json, .../home_chellenge_bar{1,2,3,4}.imageset/Contents.json
다수 이미지셋 Contents.json 추가. 일부 스케일(2x/3x) 항목은 파일명 비어 있음. 메타 정보(author/version) 포함.

Sequence Diagram(s)

sequenceDiagram
    participant SwiftUI as CustomWheelPicker (SwiftUI View)
    participant Representable as PickerViewRepresentable (UIViewRepresentable)
    participant UIKit as UIPickerView
    participant Coordinator as Coordinator

    SwiftUI->>Representable: body -> makeUIView(context:)
    Representable->>UIKit: 생성 및 초기 설정 (delegate/dataSource = Coordinator)
    Representable->>Coordinator: context 연결
    Representable->>UIKit: selectRow(initialIndex)
    UIKit->>Coordinator: 사용자 스크롤/선택 이벤트 (didSelectRow)
    Coordinator->>Representable: 업데이트 바인딩(selection = rowIndex)
    Representable->>SwiftUI: 바인딩 변경 반영 (selection 바뀜)
    SwiftUI->>Representable: selection 외부 변경 -> updateUIView(_:context:)
    Representable->>UIKit: selectRow(updatedIndex, animated: true)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 분

Possibly related PRs

  • Style/#56 커스텀 피커 #57 — 동일한 CustomWheelPicker 구현(PickerViewRepresentable 및 Coordinator)을 추가한 PR로 코드 수준에서 직접 관련됨.

Suggested reviewers

  • wotjs020708
  • sum130
  • y-eonee

개요

SwiftUI 환경에서 UIKit의 UIPickerView를 활용한 커스텀 휠 피커 컴포넌트 CustomWheelPicker를 신규로 추가합니다. 정수 선택을 위한 바인딩 기능과 동기화 로직을 포함합니다.

변경 사항

응집 단위 / 파일 변경 요약
커스텀 휠 피커 컴포넌트
Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift
새로운 공개 구조체 CustomWheelPicker 추가: @Binding selection과 ClosedRange를 통한 정수 선택 관리, 구성 가능한 폭 설정(기본값 74.adjustedW). UIViewRepresentable을 통해 UIPickerView를 래핑하는 비공개 PickerViewRepresentable 구조체 구현. UIPickerViewDelegate/DataSource를 준수하는 Coordinator 클래스로 행 개수, 행 높이, 너비, 커스텀 레이블 렌더링(Pretendard 폰트, 정의된 색상) 제공. 초기 바인딩 동기화 및 외부 선택 변경 반영 처리. 회색 둥근 배경 컨테이너로 시각화.

예상 코드 리뷰 노력

🎯 2 (Simple) | ⏱️ ~12 분

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 커스텀 피커 구현이라는 PR의 주요 변경사항을 명확하게 요약하고 있습니다.
Description check ✅ Passed 설명이 구현 내용, 주요 코드, 사용법, 스크린샷을 포함하여 변경사항과 관련성이 높습니다.
Linked Issues check ✅ Passed PR이 issue #56의 커스텀 피커 컴포넌트 구현 목표를 완전히 충족하고 있습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 커스텀 피커 컴포넌트 구현이라는 범위 내에 있으며 관련 없는 변경은 없습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch style/#56-customPicler


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4c82b9 and 17faf6a.

⛔ Files ignored due to path filters (6)
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/cherrish_character.imageset/체리.svg is excluded by !**/*.svg
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/cherrish_logo.imageset/cherrish_logo.svg is excluded by !**/*.svg
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/home_chellenge_bar1.imageset/home_chellenge_bar.svg is excluded by !**/*.svg
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/home_chellenge_bar2.imageset/home_chellenge_bar2.svg is excluded by !**/*.svg
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/home_chellenge_bar3.imageset/home_chellenge_bar3.svg is excluded by !**/*.svg
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/home_chellenge_bar4.imageset/home_chellenge_bar4.svg is excluded by !**/*.svg
📒 Files selected for processing (10)
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/Color/home_gradient1.colorset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/Color/home_gradient2.colorset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/cherrish_character.imageset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/cherrish_logo.imageset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/home_chellenge_bar1.imageset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/home_chellenge_bar2.imageset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/home_chellenge_bar3.imageset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Assets.xcassets/home_icon/home_chellenge_bar4.imageset/Contents.json
  • Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift:
- Around line 39-40: When selecting the initial row in makeUIView of
CherrishPicker, avoid the unwanted scroll animation by passing animated: false
to picker.selectRow; locate the selection logic that computes let row =
selection - range.lowerBound and change the call picker.selectRow(row,
inComponent: 0, animated: true) to use animated: false so the initial state is
set without animation.
- Around line 75-86: The pickerView.subviews.forEach background-clear loop
inside pickerView(_:viewForRow:forComponent:reusing:) is inefficient because
that delegate method is called frequently; move the one-time subview background
initialization into PickerViewRepresentable.makeUIView (or guard it with a flag)
and remove the loop from the viewForRow implementation so pickerView,
viewForRow, and makeUIView no longer repeatedly clear subview backgrounds during
scrolling.
- Around line 34-43: In makeUIView, guard against selection being outside range
by clamping selection to range.lowerBound...range.upperBound (or
range.upperBound - 1 for half-open ranges) before computing row; replace direct
use of selection in the row calculation with a clampedSelection variable,
compute row = clampedSelection - range.lowerBound, and then call
picker.selectRow(row, inComponent: 0, animated: true); ensure you reference the
makeUIView(context:) method, the selection binding, and the range property when
adding this defensive logic.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 822c9c8 and c4c82b9.

📒 Files selected for processing (1)
  • Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift
🧰 Additional context used
🧬 Code graph analysis (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift (3)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Shadow.swift (1)
  • body (9-17)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/View+Color.swift (2)
  • gray300 (21-23)
  • gray1000 (49-51)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishButton.swift (2)
  • backgroundColor (78-87)
  • textColor (89-98)
🔇 Additional comments (2)
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift (2)

11-28: LGTM!

SwiftUI View 래퍼의 구조가 적절합니다. ZStack을 사용한 레이아웃과 .clipped()로 오버플로우를 방지하는 방식이 잘 구현되어 있습니다.


56-61: Coordinator의 parent 참조를 통한 업데이트 방식 검증 필요.

Coordinatorparentvar로 보유하고 있지만, SwiftUI의 재생성 사이클에서 parent 참조가 오래된(stale) 상태가 될 수 있습니다. 일반적인 패턴은 updateUIView에서 coordinator의 parent를 갱신하는 것입니다.

♻️ 권장 패턴
     func updateUIView(_ uiView: UIPickerView, context: Context) {
+        context.coordinator.parent = self
         let row = selection - range.lowerBound
         if uiView.selectedRow(inComponent: 0) != row {
             uiView.selectRow(row, inComponent: 0, animated: true)
         }
     }

Comment on lines 34 to 43
func makeUIView(context: Context) -> UIPickerView {
let picker = UIPickerView()
picker.delegate = context.coordinator
picker.dataSource = context.coordinator

let row = selection - range.lowerBound
picker.selectRow(row, inComponent: 0, animated: true)

return picker
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

selection이 range 범위를 벗어날 경우 방어 로직 고려.

selectionrange 범위 밖의 값으로 바인딩되면 음수 또는 범위를 초과하는 row 인덱스가 계산될 수 있습니다. 이는 예기치 않은 동작을 유발할 수 있으므로 클램핑(clamping) 처리를 권장합니다.

♻️ 수정 제안
     func makeUIView(context: Context) -> UIPickerView {
         let picker = UIPickerView()
         picker.delegate = context.coordinator
         picker.dataSource = context.coordinator
         
-        let row = selection - range.lowerBound
+        let clampedSelection = min(max(selection, range.lowerBound), range.upperBound)
+        let row = clampedSelection - range.lowerBound
         picker.selectRow(row, inComponent: 0, animated: false)
         
         return picker
     }
🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift
around lines 34 - 43, In makeUIView, guard against selection being outside range
by clamping selection to range.lowerBound...range.upperBound (or
range.upperBound - 1 for half-open ranges) before computing row; replace direct
use of selection in the row calculation with a clampedSelection variable,
compute row = clampedSelection - range.lowerBound, and then call
picker.selectRow(row, inComponent: 0, animated: true); ensure you reference the
makeUIView(context:) method, the selection binding, and the range property when
adding this defensive logic.

Comment on lines +39 to +40
let row = selection - range.lowerBound
picker.selectRow(row, inComponent: 0, animated: true)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

초기 선택 시 애니메이션 불필요.

makeUIView에서 초기 행을 선택할 때는 animated: false를 사용하는 것이 자연스럽습니다. 뷰가 처음 생성될 때 스크롤 애니메이션이 보이는 것은 의도치 않은 UX일 수 있습니다.

♻️ 수정 제안
-        picker.selectRow(row, inComponent: 0, animated: true)
+        picker.selectRow(row, inComponent: 0, animated: false)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let row = selection - range.lowerBound
picker.selectRow(row, inComponent: 0, animated: true)
let row = selection - range.lowerBound
picker.selectRow(row, inComponent: 0, animated: false)
🤖 Prompt for AI Agents
In
@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishPicker.swift
around lines 39 - 40, When selecting the initial row in makeUIView of
CherrishPicker, avoid the unwanted scroll animation by passing animated: false
to picker.selectRow; locate the selection logic that computes let row =
selection - range.lowerBound and change the call picker.selectRow(row,
inComponent: 0, animated: true) to use animated: false so the initial state is
set without animation.

Copy link
Contributor

@wotjs020708 wotjs020708 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SwiftUI에서 UIKit 연결하느라 고생하셨으욤 어푸푸 드립니다.

Copy link
Contributor

@y-eonee y-eonee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿

Coordinator(self)
}

class Coordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호..유킷->스유 데이텁전달 역할을 하는군여

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extension으로 분리하는 건 어떄요?

Copy link
Contributor

@sum130 sum130 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

새로운 내용 공부하고 정리하느라 고생했으요 굿
근데 저번 피알에도 달았지만 gif로 구현화면 꾸워주면 좋을 듯......... 직접 보면 좋겠슴요

struct CustomWheelPicker: View {
@Binding var selection: Int
let range: ClosedRange<Int>
var width: CGFloat = 74.adjustedW
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오.. 고정값줄 때 써도 되는군요 굿

@soseoyo12 soseoyo12 merged commit 8da6338 into develop Jan 14, 2026
1 check was pending
@y-eonee y-eonee deleted the style/#56-customPicler branch January 15, 2026 14:38
Kimgyuilli pushed a commit that referenced this pull request Jan 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Style] 커스텀 피커 컴포넌트

4 participants