Skip to content

Fix/#157 keyboard#170

Merged
y-eonee merged 2 commits intodevelopfrom
fix/#157-keyboard
Jan 23, 2026
Merged

Fix/#157 keyboard#170
y-eonee merged 2 commits intodevelopfrom
fix/#157-keyboard

Conversation

@wotjs020708
Copy link
Contributor

🔗 연결된 이슈

📄 작업 내용

  • 키보드 기기 대응 완료

@wotjs020708 wotjs020708 requested a review from a team January 22, 2026 15:45
@wotjs020708 wotjs020708 self-assigned this Jan 22, 2026
@wotjs020708 wotjs020708 requested review from soseoyo12, sum130 and y-eonee and removed request for a team January 22, 2026 15:45
@wotjs020708 wotjs020708 added 재선🐻 Fix 버그 수정 labels Jan 22, 2026
@wotjs020708 wotjs020708 linked an issue Jan 22, 2026 that may be closed by this pull request
1 task
@coderabbitai
Copy link

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

둘러보기

TargetDdaySettingView에서 키보드 나타남/숨김 시 뷰를 자동으로 스크롤하는 기능을 추가했습니다. ScrollViewReader, 키보드 높이 추적 상태, 키보드 알림 핸들러, 그리고 입력 필드로의 자동 스크롤 로직을 구현했습니다.

변경사항

응집도 / 파일 변경 요약
키보드 반응형 스크롤 구현
Cherrish-iOS/.../TargetDdaySettingView.swift
ScrollViewReader로 감싸기, keyboardHeight 상태 추가, 키보드 willShow/willHide 알림 핸들러 구현, onChange로 키보드 높이 변경 시 자동 스크롤, DateTextBox에 .id("inputField") 추가, 레이아웃 리팩토링 및 Yes/No 상태 섹션 바인딩 조정

예상 코드 리뷰 난이도

🎯 3 (보통) | ⏱️ ~20분

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive PR 제목이 키보드 기기 대응 작업과 관련이 있지만 구체성이 부족하고 'Fix/#157'이라는 이슈 번호가 혼동을 야기합니다. 제목을 '키보드 기기 대응' 또는 'TargetDdaySettingView에 키보드 인식 스크롤 기능 추가'로 변경하여 더 명확하게 변경사항을 설명하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed PR 설명이 키보드 기기 대응 작업과 관련이 있으며 연결된 이슈 #169를 명시하고 있습니다.
Linked Issues check ✅ Passed ScrollViewReader 추가, 키보드 높이 추적, 자동 스크롤 기능 등이 구현되어 이슈 #169의 '키보드 기기 대응' 요구사항을 충족합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 TargetDdaySettingView 파일의 키보드 대응 기능 구현에 초점을 맞추고 있으며 범위를 벗어나는 내용이 없습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 fix/#157-keyboard

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: 1

🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TargetDdaySettingView.swift`:
- Around line 107-122: Replace the separate keyboardWillShow/keyboardWillHide
handlers with a single listener for
UIResponder.keyboardWillChangeFrameNotification; in that handler read
keyboardFrame from
notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] and the
animation duration from UIKeyboardAnimationDurationUserInfoKey, compute the
effective height by subtracting the view's safe area bottom inset (use your
geometry/proxy or a stored safeAreaInset variable) and set keyboardHeight inside
withAnimation(.easeOut(duration: duration)) so the change is synchronized; keep
the scrollTo("inputField", anchor: .center) call triggered when keyboardHeight >
0 but ensure it runs after the animated height change (same animation block or
DispatchQueue.main.asyncAfter matching duration) so the input field isn't
obscured.

Comment on lines +107 to 122
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
keyboardHeight = keyboardFrame.height
}
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
withAnimation(.easeOut(duration: 0.25)) {
keyboardHeight = 0
}
}
.onChange(of: keyboardHeight) { _, newValue in
if newValue > 0 {
withAnimation(.easeOut(duration: 0.25)) {
proxy.scrollTo("inputField", anchor: .center)
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "TargetDdaySettingView.swift" -type f 2>/dev/null

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 170


🏁 Script executed:

cat -n Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TargetDdaySettingView.swift | sed -n '100,130p'

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 1342


🏁 Script executed:

wc -l Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TargetDdaySettingView.swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 172


🏁 Script executed:

cat -n Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TargetDdaySettingView.swift | head -50

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 1826


🏁 Script executed:

rg "keyboardHeight|keyboardWill" Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TargetDdaySettingView.swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 576


🌐 Web query:

iOS UIResponder keyboard notifications keyboardWillChangeFrameNotification vs keyboardWillShow keyboardWillHide

💡 Result:

Short answer

  • keyboardWillShow/keyboardDidShow and keyboardWillHide/keyboardDidHide are high-level "visibility" notifications (keyboard being shown or hidden). Use them when you only care about whether the keyboard is appearing or disappearing. [1][2]
  • keyboardWillChangeFrame/keyboardDidChangeFrame fire whenever the keyboard’s frame is about to change (or has changed) — that covers showing/hiding plus frame moves: size changes, language/layout switch, docking/undocking, split keyboard, inputAccessory changes, user dragging the keyboard, etc. Use these when you need the keyboard’s actual frame/height or to animate UI with the keyboard. [3][1]

Practical notes

  • The change-frame notifications include userInfo keys you’ll typically need: UIKeyboardFrameBeginUserInfoKey / UIKeyboardFrameEndUserInfoKey, UIKeyboardAnimationDurationUserInfoKey and UIKeyboardAnimationCurveUserInfoKey — read the end frame and animation info and animate your layout to match. [3]
  • On iPad the distinction matters more (docking/undocking and dragging can change frame without a simple show/hide). [3]
  • Many apps subscribe to keyboardWillChangeFrameNotification (and keyboardWillHide) as a robust way to adjust insets/constraints; some guard against spurious show/hide notifications by tracking a keyboardShowing flag. [3][2]

Sources

  1. Apple Developer: UIResponder.keyboardWillShow / keyboardWillHide pages. [1][2]
  2. Explanation and examples (UIKeyboard notifications, including keyboardWillChangeFrame): apeth.com and community threads. [3]

🌐 Web query:

iOS keyboard frame changes rotation orientation UIResponder notifications

💡 Result:

Short summary / recipe

  • Observe UIResponder.keyboardWillChangeFrameNotification (and keyboardDidChangeFrameNotification if you need the final state). Use WillChangeFrame to animate in sync with the keyboard. [1][2]

  • Read the end frame from notification.userInfo[UIResponder.keyboardFrameEndUserInfoKey] (CGRect wrapped in NSValue). These frames are in screen coordinates and may not reflect your view’s orientation, so convert into your view/window coordinates before using: e.g. let endFrameInView = view.convert(keyboardEndFrame, from: nil) or window?.convert(...). Also check UIKeyboardIsLocalUserInfoKey to ignore another-app keyboards. [2][3]

  • Match the keyboard animation: read UIKeyboardAnimationDurationUserInfoKey and UIKeyboardAnimationCurveUserInfoKey from userInfo and animate your layout changes with the same duration/curve (or use UIView.animate with options: animationCurve << 16 mapping, or use UIViewPropertyAnimator). That keeps movement smooth during rotation. [1][3]

  • Handle rotation edge cases:

    • Rotation can cause keyboard frame changes (keyboardWillChangeFrame fires) rather than separate show/hide events; rely on endFrame to decide whether keyboard is visible (endFrame.origin.y >= UIScreen.main.bounds.height => hidden). [2]
    • On iPad and with floating/split keyboards or external keyboards, frames/behavior differ — prefer adjusting safeAreaInsets or bottom constraints instead of moving the whole view. [1][3]

Minimal example (Swift):

  • add observer for keyboardWillChangeFrameNotification
  • in handler:
    • guard let frame = (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
    • let frameInView = view.convert(frame, from: nil)
    • let duration = userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval ?? 0.25
    • let curve = (userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int) ?? 0
    • update bottom constraint = max(0, view.bounds.maxY - frameInView.minY)
    • animate layoutIfNeeded with duration and matching curve.

References

  • Apple UIResponder keyboard notifications (docs). [1]
  • Keyboard frame keys & screen-coordinate conversion discussion (StackOverflow / Managing the Keyboard). [2]
  • Practical guides / examples showing convertRect, animation matching and iPad considerations. [3]

If you want, I can paste a ready-to-use Swift handler class using these practices.


🌐 Web query:

iOS keyboard safe area inset calculation UIScreen bounds keyboardFrameEndUserInfoKey

💡 Result:

Short answer — use the keyboard’s end frame in the keyboard’s coordinate space and convert it into your view’s coordinate space, then take the intersection height with your view bounds (that intersection is the keyboard overlap / safe-area bottom inset to apply). This avoids orientation/rotation and home‑indicator double-counting.

Recommended Swift pattern (concise):

  • Observe UIResponder.keyboardWillChangeFrameNotification / .keyboardDidChangeFrame.
  • From notification: get the CGRect and the UIScreen (notification.object on iOS 16.1+).
  • Convert the keyboard rect into your view’s coordinate space using the screen’s coordinateSpace (or window conversion).
  • Compute intersection with view.bounds; use intersection.height as the inset.

Example:

let info = notification.userInfo!
let endFrame = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
if let screen = notification.object as? UIScreen {
let converted = screen.coordinateSpace.convert(endFrame, to: view)
let overlap = view.bounds.intersection(converted)
let bottomInset = overlap.isNull ? 0 : overlap.height
// apply bottomInset (or animate constraint using animation info from userInfo)
}

Notes:

  • If you instead take keyboard height directly, subtract window.safeAreaInsets.bottom to avoid adding the home‑indicator area twice.

키보드 프레임 변경(회전/타입 전환)에 높이가 갱신되지 않습니다.

keyboardWillShow/Hide 알림만 사용하면 키보드 회전, 입력기 타입 변경, 키보드 높이 변화 중에는 업데이트되지 않아 입력창이 가려질 수 있습니다. keyboardWillChangeFrameNotification으로 통합하고, 알림의 UIKeyboardAnimationDurationUserInfoKey를 사용해 애니메이션을 동기화하며, 안전 영역 인셋 차감을 고려해 주세요.

🔧 개선 제안
-            .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
-                if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
-                    keyboardHeight = keyboardFrame.height
-                }
-            }
-            .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
-                withAnimation(.easeOut(duration: 0.25)) {
-                    keyboardHeight = 0
-                }
-            }
+            .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)) { notification in
+                guard
+                    let info = notification.userInfo,
+                    let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect,
+                    let duration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double
+                else { return }
+                let screenHeight = UIScreen.main.bounds.height
+                let height = max(0, screenHeight - keyboardFrame.minY)
+                withAnimation(.easeOut(duration: duration)) {
+                    keyboardHeight = height
+                }
+            }
📝 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
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
keyboardHeight = keyboardFrame.height
}
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
withAnimation(.easeOut(duration: 0.25)) {
keyboardHeight = 0
}
}
.onChange(of: keyboardHeight) { _, newValue in
if newValue > 0 {
withAnimation(.easeOut(duration: 0.25)) {
proxy.scrollTo("inputField", anchor: .center)
}
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)) { notification in
guard
let info = notification.userInfo,
let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect,
let duration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double
else { return }
let screenHeight = UIScreen.main.bounds.height
let height = max(0, screenHeight - keyboardFrame.minY)
withAnimation(.easeOut(duration: duration)) {
keyboardHeight = height
}
}
.onChange(of: keyboardHeight) { _, newValue in
if newValue > 0 {
withAnimation(.easeOut(duration: 0.25)) {
proxy.scrollTo("inputField", anchor: .center)
}
}
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TargetDdaySettingView.swift`
around lines 107 - 122, Replace the separate keyboardWillShow/keyboardWillHide
handlers with a single listener for
UIResponder.keyboardWillChangeFrameNotification; in that handler read
keyboardFrame from
notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] and the
animation duration from UIKeyboardAnimationDurationUserInfoKey, compute the
effective height by subtracting the view's safe area bottom inset (use your
geometry/proxy or a stored safeAreaInset variable) and set keyboardHeight inside
withAnimation(.easeOut(duration: duration)) so the change is synchronized; keep
the scrollTo("inputField", anchor: .center) call triggered when keyboardHeight >
0 but ensure it runs after the animated height change (same animation block or
DispatchQueue.main.asyncAfter matching duration) so the input field isn't
obscured.

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.

ㅇㅍㄹㅂㅇㅍㄹㅂ

Comment on lines +107 to +121
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
keyboardHeight = keyboardFrame.height
}
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
withAnimation(.easeOut(duration: 0.25)) {
keyboardHeight = 0
}
}
.onChange(of: keyboardHeight) { _, newValue in
if newValue > 0 {
withAnimation(.easeOut(duration: 0.25)) {
proxy.scrollTo("inputField", anchor: .center)
}
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

@soseoyo12 soseoyo12 left a comment

Choose a reason for hiding this comment

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

수고하셨습니당

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.

구우우웃! 수고했어용 오푸푸!

@y-eonee y-eonee merged commit c8fa69b into develop Jan 23, 2026
3 checks passed
@y-eonee y-eonee deleted the fix/#157-keyboard branch January 23, 2026 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Fix 버그 수정 재선🐻

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[fix] 키보드 기기 대응

4 participants

Comments