-
Notifications
You must be signed in to change notification settings - Fork 0
Fix/#157 keyboard #170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Fix/#157 keyboard #170
Conversation
π Walkthroughλλ¬λ³΄κΈ°TargetDdaySettingViewμμ ν€λ³΄λ λνλ¨/μ¨κΉ μ λ·°λ₯Ό μλμΌλ‘ μ€ν¬λ‘€νλ κΈ°λ₯μ μΆκ°νμ΅λλ€. ScrollViewReader, ν€λ³΄λ λμ΄ μΆμ μν, ν€λ³΄λ μλ¦Ό νΈλ€λ¬, κ·Έλ¦¬κ³ μ λ ₯ νλλ‘μ μλ μ€ν¬λ‘€ λ‘μ§μ ꡬννμ΅λλ€. λ³κ²½μ¬ν
μμ μ½λ 리뷰 λμ΄λπ― 3 (보ν΅) | β±οΈ ~20λΆ π₯ Pre-merge checks | β 4 | β 1β Failed checks (1 inconclusive)
β Passed checks (4 passed)
βοΈ Tip: You can configure your own custom pre-merge checks in the settings. β¨ Finishing touches
π§ͺ Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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.
| .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) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
find . -name "TargetDdaySettingView.swift" -type f 2>/dev/nullRepository: 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.swiftRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 172
π Script executed:
cat -n Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TargetDdaySettingView.swift | head -50Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 1826
π Script executed:
rg "keyboardHeight|keyboardWill" Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TargetDdaySettingView.swiftRepository: 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
- Apple Developer: UIResponder.keyboardWillShow / keyboardWillHide pages. [1][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.
| .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.
y-eonee
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
γ γ γΉγ γ γ γΉγ
| .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) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
μμ°κ΅Ώ μκ³ νμ ¨μ΅λλ€
soseoyo12
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
μκ³ νμ ¨μ΅λλΉ
sum130
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ꡬμ°μ°μ! μκ³ νμ΄μ© μ€νΈνΈ!
π μ°κ²°λ μ΄μ
π μμ λ΄μ©