AI 사용기
SwiftUI 숫자패드 닫기: 두 입력칸의 포커스를 nil로 해제하기
numberPad·decimalPad 화면에 Done 버튼을 추가하고, 두 입력칸에서 버튼 한 개·키보드 닫힘·입력값 보존을 확인하는 최소 예제를 제공한다.
2026년 10월 11일 조사·독립 예제 시험·작성한 글입니다.
숫자 입력 뒤 키보드를 닫을 수 없는 SwiftUI 화면에 명시적인 닫기 동작을 추가하도록 돕는다.
입력칸을 서로 다른 FocusState 값에 연결하고 Done에서 nil로 해제한다. 툴바가 실제 보이는지와 값이 남는지도 확인한다.
자신의 숫자 입력 화면에서 툴바 부착 위치와 focused 연결을 확인한 뒤 첫 입력·다음 입력에서 각각 닫아 본다.
먼저 답하면
SwiftUI에서 numberPad나 decimalPad로 숫자를 넣었는데 닫는 키가 없으면, 입력칸을 @FocusState에 연결하고 별도의 Done 버튼에서 포커스를 nil로 해제한다. 이번 대조군 Count 숫자패드에는 Return·Done 키가 없었으므로 별도의 닫기 버튼을 제공한다.
아래는 두 입력칸을 가진 완전한 화면이다. 새 iOS App 프로젝트를 SwiftUI로 만들고 ContentView.swift를 이 코드로 교체한다. iOS 17 이상을 예제 대상으로 두며, 생성된 App의 WindowGroup에서 ContentView()를 여는 기본 구조는 유지한다.
import SwiftUI
struct ContentView: View {
enum Field: Hashable { case count, price }
@State private var count = ""
@State private var price = ""
@FocusState private var focused: Field?
var body: some View {
NavigationStack {
Form {
TextField("Count", text: $count)
.keyboardType(.numberPad)
.focused($focused, equals: .count)
TextField("Price", text: $price)
.keyboardType(.decimalPad)
.focused($focused, equals: .price)
Text("Values: \(count) / \(price)")
Button("Close keyboard") { focused = nil }
}
.navigationTitle("Number pad probe")
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("Done") { focused = nil }
}
}
}
}
}
Count에 12를 넣고 키보드 위의 Done을 누른다. Price에 34를 넣고 다시 Done을 누른다. 키보드가 사라지고 Values: 12 / 34가 남으면 이 예제의 닫기 동작을 확인한 것이다. 화면 안의 Close keyboard도 같은 포커스 해제를 실행하는 별도 닫기 경로다. 두 버튼은 숫자 변환·저장·서버 제출을 하지 않는다.
두 입력칸에 같은 포커스 값을 쓰지 않기
Apple FocusState 문서는 연결된 포커스 값을 false 또는 nil로 바꿔 입력 포커스를 없애고 키보드를 닫을 수 있다고 설명한다. 한 칸만 있으면 Bool도 쓸 수 있지만, 이 화면에서는 어느 입력이 선택됐는지 구분하려고 선택형 enum을 썼다.
Count는 .count, Price는 .price에 연결한다. 두 입력에 모두 .count를 연결하면 어느 칸을 가리키는지 모호해진다. focused = nil은 연결된 입력의 포커스를 해제할 뿐, count나 price 문자열을 비우는 대입이 아니다. 닫기와 입력 검증은 별개의 동작으로 설계해야 한다.
툴바는 보이는지부터 시험한다
Apple의 keyboard 배치 설명에 따르면 iOS의 .keyboard 항목은 소프트웨어 키보드 위에, 하드웨어 키보드가 연결되면 화면 아래에 배치된다. 이 예제는 Form을 포함한 화면에 툴바를 한 번 붙였다. 각 TextField에 동일한 툴바를 복사하는 방식은 사용하지 않았다.
그렇다고 어떤 앱 루트에 한 번 붙이든 반드시 표시된다는 뜻은 아니다. Apple 포럼의 2024년 질문에는 iOS 17.6 실기기의 FullScreenCover에서 숫자패드는 나오지만 닫기 툴바가 보이지 않는 사례가 있다. 그 질문은 이번 독립 화면의 재현 결과와 다른 조건이다. NavigationStack을 추가하면 모든 문제가 해결된다고 주장할 근거로 쓰지 않는다.
자기 화면에 적용할 때는 다음을 확인한다.
- 최초 화면 진입에서 Count를 누르고, Done이 실제 보이며 누를 수 있는지 확인한다.
- Done으로 닫은 뒤 Price에서도 같은 동작을 해 본다. 툴바의 Done이 중복으로 생기지 않는지도 본다.
- 닫은 뒤 입력값과 화면의 나머지 조작이 유지되는지 확인한다.
- 실제 화면이 sheet나 FullScreenCover 안에 있다면 그 안에서도 따로 확인한다. 다른 화면에서 성공한 결과를 가져오지 않는다.
수정 전후를 시뮬레이터에서 확인한 결과
2026년 10월 11일 Xcode 27.0(27A266a), iOS 26.5(23F77), iPhone SE 3세대 전용 시뮬레이터에서 자체 최소 앱을 실행했다. XCUITest 두 개가 실패 없이 끝났다. 사람 사용시험이 아닌 자동 UI 시험이다. 두 실행 로그에 첫 입력 탭의 Invalid frame dimension (negative or non-finite) 경고가 남았으며, 원인은 확인하지 못했다. 아래 버튼·닫힘·값 보존 검사는 통과했지만 모든 레이아웃이 정상이라고 판단한 것은 아니다.
NumberPadProbe.zip 받기에는 생성된 Xcode 프로젝트와 자체 소스·UI 테스트가 들어 있다. 본문 코드는 설명용 최소 화면이며, 다운로드 앱에는 수정 전 비교를 위한 --baseline 분기, 자동 시험용 접근성 식별자와 Focus 상태 표시가 추가돼 있다. 닫기 동작은 같은 focused = nil이다. 외부 패키지나 XcodeGen 설치는 필요 없다. ZIP을 풀고 NumberPadProbe 폴더에서 Xcode가 제공하는 iOS 시뮬레이터를 대상으로 실행한다. 터미널에서 시험하려면 다음 명령의 YOUR_SIMULATOR_UDID를 xcrun simctl list devices available에서 확인한 자기 시뮬레이터 UUID로 바꾼다.
xcodebuild -project NumberPadProbe.xcodeproj -scheme NumberPadProbe \
-destination 'platform=iOS Simulator,id=YOUR_SIMULATOR_UDID' \
-derivedDataPath DerivedData -parallel-testing-enabled NO \
CODE_SIGNING_ALLOWED=NO test
| 시험 | 실제 확인 결과 |
|---|---|
--baseline 실행 인자로 닫기 버튼을 끈 화면 |
Count의 숫자패드가 나타나고 Return·Done 키와 자체 Done 버튼이 없었다 |
수정 화면의 Count에 12 입력 |
자체 Done이 한 개이며 탭 가능. 누른 뒤 키보드가 사라지고 포커스가 해제됐다 |
이어서 Price에 34 입력 |
자체 Done이 한 개이며 탭 가능. 누른 뒤 키보드가 사라졌다 |
| 두 입력 뒤 결과 | Values: 12 / 34가 남았다 |
| Count를 다시 열고 Close keyboard 누르기 | 키보드가 사라지고 같은 값이 유지됐다 |
수정 전 화면은 원인을 비교하기 위해 우리가 만든 대조군이다. 다른 사용자의 앱 장애를 재현했다고 쓰지 않는다. Apple의 numberPad 설명은 숫자 키패드 종류를 정의하며, 위 표의 버튼 부재와 닫힘은 실제 시험으로 확인했다.

자동 UI 시험에서 찍은 iOS 26.5 시뮬레이터 화면. 소프트웨어 키보드 위의 Done을 누른 뒤 값이 남는지 별도로 확인했다.
안 닫히거나 버튼이 안 보이면
버튼을 눌러도 안 닫히면 focused를 해제하는 코드와 실제 TextField의 .focused가 같은 상태를 쓰는지 확인한다. 두 입력에 같은 enum 값을 연결하지 않았는지도 본다. 버튼은 보이는데 실행되지 않는다면 그 화면의 제스처·겹친 뷰·버튼 활성 상태를 따로 확인한다.
툴바가 안 보이면 화면 안 Close keyboard 버튼부터 눌러 포커스 해제 자체와 툴바 표시 문제를 구분한다. 같은 입력 화면을 위 최소 구조로 줄여 확인하고, 실제 모달·탐색 계층으로 되돌릴 때마다 시험한다. 하드웨어 키보드 연결 상태도 확인한다. 화면 전체의 탭 제스처를 무작정 추가하면 다른 조작과 충돌할 수 있으므로 이 예제의 수정 절차에는 넣지 않았다.
이번 시험은 숫자 문자열의 유효성이나 금액 계산을 검증하지 않았다. decimalPad에는 34만 입력했으며 소수점·지역별 소수 구분자·붙여넣기 검증은 범위 밖이다. iPad·실기기·하드웨어 키보드·다른 iOS 버전·모달 안 툴바도 시험하지 않았다. 숫자패드 선택만으로 입력 데이터가 안전한 숫자가 됐다고 판단하지 말고, 저장·계산 전에 별도의 검증을 수행한다.
AI가 공식 자료 조사, 독립 예제 제작·시뮬레이터 시험, 초안과 별도 자동 검토를 수행했습니다. 실제 사람 사용시험이나 기존 사용자 앱의 실기기 시험으로 서술하지 않습니다.