UIKit ve SwiftUI'da text field'ları klavyenin üstünde tutmak
Yazılım klavyesinin layout'la ilişkisi ve bugünün araçları: UIKit'te UIKeyboardLayoutGuide, SwiftUI'da klavye safe area'sı; focus ve klavyeyi kapatmak için @FocusState, onSubmit ve scrollDismissesKeyboard.
Bir uygulamayı en hızlı bozuk gösteren şeylerden biri, yazdığınız alanın üstünü kapatan bir klavye. Altta "Giriş yap" butonu olan bir login formu, bir sohbet giriş çubuğu, uzun bir kayıt formu: klavye açıldığı anda ekranın bir kısmı arkasında kayboluyor. iPad'de yüzen klavye ise her seferinde ekranın farklı bir yerini kapatabiliyor.
Bugün hem UIKit'in hem SwiftUI'ın bunun için yerleşik araçları var ve bunlar elle yazılan birçok kodun yerini alıyor. Bu yazıda klavyenin layout'la ilişkisini, UIKeyboardLayoutGuide'ın ve SwiftUI'ın klavye safe area'sının nasıl çalıştığını, focus ve klavyeyi kapatma işini ve hâlâ sık düşülen tuzakları anlatıyorum.
Klavye layout'u nasıl etkiliyor
Yazılım klavyesi sizin view hiyerarşinizin parçası değil. Pencerenin üzerine kayarak geliyor ve ekranın alt kısmında bir text field ya da "Devam" butonu varsa üstünü kapatıyor. Sistem ona nasıl yapacağını söylemediğiniz sürece layout'unuzu değiştirmiyor.
iOS 15'ten önce bunu söylemek hep aynı ritüel demekti: keyboardWillShow / keyboardWillHide (ya da daha iyisi keyboardWillChangeFrameNotification) dinlenir, userInfo içinden bitiş frame'i okunur, view'un koordinat sistemine çevrilir, safe area düşülür, sonra ya bir constraint'in constant'ı değiştirilir ya da scroll view'un contentInset'i ayarlanır. İdeal olanı bunu klavyenin animasyon eğrisiyle aynı anda yapmaktır. Bu sırada en az bir detayı atlamak çok kolay: iPad'deki yüzen klavye, cihaz döndürme ya da observer'ı kaldırmak.
iOS 14 ve iOS 15 ile ne değişti
iOS 15'ten beri her UIView'un klavyeyi sizin yerinize takip eden bir keyboardLayoutGuide'ı (UIKeyboardLayoutGuide) var. iOS 14'ten beri de SwiftUI klavyeyi bir safe area bölgesi olarak ele alıyor (SafeAreaRegions.keyboard), yani layout sistemi klavyeden zaten kaçınıyor. Deployment target'ınız iOS 15 veya üstüyse (2026'da büyük ihtimalle öyle) notification tabanlı yaklaşım artık legacy kod.
UIKit: UIKeyboardLayoutGuide
Fikir basit: guide'ın üst kenarı klavyenin üst kenarı. Klavye kapalıyken safe area'nın altında duruyor. İçeriğinizi ona bağlarsanız gerisini, animasyon dahil, Auto Layout hallediyor.
import UIKit
final class LoginViewController: UIViewController {
private let emailField = UITextField()
private let loginButton = UIButton(configuration: .filled()) // iOS 15+
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
emailField.borderStyle = .roundedRect
emailField.placeholder = "E-posta"
loginButton.configuration?.title = "Giriş yap"
let stack = UIStackView(arrangedSubviews: [emailField, loginButton])
stack.axis = .vertical
stack.spacing = 12
stack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
stack.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
// Bütün numara bu: klavyenin (ya da safe area'nın) 16 pt üstünde dur.
stack.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor, constant: -16)
])
// iPad: yüzen ya da ayrılmış klavyeyi de takip et (iOS 15+).
view.keyboardLayoutGuide.followsUndockedKeyboard = true
}
}
Bilmeye değer iki property var:
followsUndockedKeyboard(iOS 15+) varsayılan olarakfalse. Bu durumda guide yalnızca sabit (docked) klavyeyi takip ediyor. iPad'de yüzen ya da ayrılmış klavyeyi de takip etmesini istiyorsanıztrueyapın.usesBottomSafeArea(iOS 17+), klavye kapalıyken guide'ın alt safe area'ya uyup uymayacağını belirliyor. Bir giriş çubuğunun ekranın en altına yapışmasını istiyorsanızfalseyapın.
Scroll view'lar: frame'i küçült ya da inset'i ayarla
Formlar genelde bir scroll view içinde olur. İki yaklaşım var, varsayılan olarak ilkini öneriyorum.
Scroll view'u guide'a bağlamak. Scroll view'un frame'i klavyenin başladığı yerde biter, yani her alana kaydırarak hâlâ ulaşılabilir. Düzenlenen alanın kendiliğinden görünür olmasını istiyorsanız scrollRectToVisible'ı kendiniz çağırın:
final class FormViewController: UIViewController, UITextFieldDelegate {
private let scrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.keyboardDismissMode = .interactive // aşağı kaydırınca kapanır
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor)
])
}
func textFieldDidBeginEditing(_ textField: UITextField) {
let rect = textField.convert(textField.bounds, to: scrollView)
scrollView.scrollRectToVisible(rect.insetBy(dx: 0, dy: -16), animated: true)
}
}
contentInset'i ayarlamak. Klasik yöntem bu. İçeriğin klavyenin arkasında da çizilmeye devam etmesi gerektiğinde, örneğin yarı saydam bir sohbet arka planında, hâlâ doğru seçim bu. Ayrı show/hide notification'ları yerine keyboardWillChangeFrameNotification kullanın ve inset ile birlikte verticalScrollIndicatorInsets'i (iOS 11.1+) de güncelleyin:
@objc private func keyboardWillChangeFrame(_ note: Notification) {
guard let endFrame = note.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
let frameInView = view.convert(endFrame, from: view.window)
let overlap = max(0, view.bounds.maxY - frameInView.minY - view.safeAreaInsets.bottom)
scrollView.contentInset.bottom = overlap
scrollView.verticalScrollIndicatorInsets.bottom = overlap
}
Inset yaklaşımı için özel bir nedeniniz yoksa guide'a bağlayın. Daha az kod ve daha fazla uç durumu kendisi hallediyor.
SwiftUI: klavye safe area'sı ve focus
iOS 14 ve sonrasında SwiftUI, klavye bir safe area bölgesi olduğu için içeriği zaten klavyenin yolundan çekiyor. iOS 13 için yazılmış özel "alanı yukarı taşı" kodları güncel sistemlerde framework'le çatışmaya eğilimli.
SwiftUI'da asıl ihtiyacınız olan şey focus yönetimi. Aşağıda eksiksiz bir kayıt formu var:
import SwiftUI
struct SignUpForm: View {
enum Field: Hashable { case name, email, password }
@State private var name = ""
@State private var email = ""
@State private var password = ""
@FocusState private var focusedField: Field? // iOS 15+
var body: some View {
NavigationStack { // iOS 16+
ScrollView {
VStack(spacing: 16) {
TextField("Ad Soyad", text: $name)
.focused($focusedField, equals: .name)
.submitLabel(.next) // iOS 15+
TextField("E-posta", text: $email)
.keyboardType(.emailAddress)
.textInputAutocapitalization(.never)
.focused($focusedField, equals: .email)
.submitLabel(.next)
SecureField("Parola", text: $password)
.focused($focusedField, equals: .password)
.submitLabel(.join)
}
.textFieldStyle(.roundedBorder)
.padding()
}
.scrollDismissesKeyboard(.interactively) // iOS 16+
.onSubmit { // iOS 15+
switch focusedField {
case .name: focusedField = .email
case .email: focusedField = .password
default:
focusedField = nil // klavyeyi kapatır
register()
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) { // iOS 15+
Spacer()
Button("Bitti") { focusedField = nil }
}
}
.navigationTitle("Kayıt")
}
}
private func register() { /* ... */ }
}
Birkaç not:
- Klavyeyi kapatmak artık sadece
focusedField = nil. Eski SwiftUI örneklerinde sık görülen,UIApplication.shared'aresignFirstRespondergönderme numarasına gerek kalmadı. .onSubmitbağlandığı view'un içindeki text field'lar için çalışıyor, yani tek bir handler bütün formu yönetebiliyor..scrollDismissesKeyboard.immediatelyve.neverdeğerlerini de alıyor. Mesajlar uygulamasındaki hissi veren.interactively.
Hareket etmesin: ignoresSafeArea(.keyboard)
Bazen bir şeylerin hareket etmemesini istersiniz: tam ekran bir arka plan görseli ya da klavyenin alt kısmı düz bir şekilde örtmesi gereken bir layout. Bu view'lara .ignoresSafeArea(.keyboard) (iOS 14+) uygulayın:
ZStack {
Image("background")
.resizable()
.scaledToFill()
.ignoresSafeArea(.keyboard) // arka plan yerinde kalır
VStack {
Spacer()
TextField("Mesaj", text: $draft)
.padding()
}
}
Sık görülen tuzaklar
- Yaklaşımları karıştırmak.
keyboardLayoutGuide'a bağlı bir constraint artı hâlâcontentInsetdeğiştiren eski bir notification handler, içeriği iki kez kaydırır. Geçiş yaparken eski observer'ı silin. - Constraint çakışmaları. Bir view hem klavye guide'ına hem de sabit bir üst constraint'e bağlıysa, klavye açıldığında birinin esnemesi gerekir. Birinin önceliğini düşürün ya da yüksekliği bir scroll view'un emmesine izin verin.
- Modifier yanlış view'da.
.ignoresSafeArea(.keyboard)'u nereye bağladığınız önemli. Derinlerdeki bir alt view'a değil, layout'u değişmemesi gereken container'a koyun ve sonucu cihazda kontrol edin. - iPad. Yüzen klavyeyi ve donanım klavyesini test edin. Donanım klavyesiyle yalnızca kısayol çubuğunu görebilirsiniz ve elle yazılmış frame hesabı bu durumda kolayca yanlış sonuç verebilir.
- Eski SwiftUI geçici çözümleri.
GeometryReaderartı klavye publisher'ları ya da SwiftUI'ın ilk dönemi için yazılmış bir "adaptive keyboard" modifier'ı, iOS 14 ve sonrasındaki yerleşik davranışla genelde çatışır. Başka bir şeyi debug etmeden önce bunları kaldırın.
Kontrol listesi
- UIKit, iOS 15+: içeriği ya da scroll view'un altını
view.keyboardLayoutGuide.topAnchor'a bağlayın. - iPad'de yüzen klavye sizin için önemliyse
followsUndockedKeyboard = trueyapın. iOS 17+ içinusesBottomSafeArea'ya bakın. contentInsetvekeyboardWillChangeFrameNotificationikilisini yalnızca içeriğin klavyenin arkasında görünmeye devam etmesi gerekiyorsa kullanın.- SwiftUI, iOS 14+: klavye safe area'sına güvenin, gereken yerde
.ignoresSafeArea(.keyboard)ile dışarıda kalın. - Alanlar arası geçiş ve klavyeyi kapatmak için
@FocusStateile.submitLabel/.onSubmit(iOS 15+) kullanın. - Tap gesture numaraları yerine
.scrollDismissesKeyboard(.interactively)(iOS 16+) kullanın. - Geçiş yaparken eski klavye notification kodunu silin.
Eskiden elle yazılan klavye kodunun büyük kısmı artık sistemin bir özelliği. Yeni kodda genelde tek bir constraint ya da tek bir @FocusState işi görüyor.
- ---
- baslik: "UIKit ve SwiftUI'da text field'ları klavyenin üstünde tutmak"
- ozet: "Yazılım klavyesinin layout'la ilişkisi ve bugünün araçları: UIKit'te UIKeyboardLayoutGuide, SwiftUI'da klavye safe area'sı; focus ve klavyeyi kapatmak için @FocusState, onSubmit ve scrollDismissesKeyboard."
- tarih: 2026-09-05
- etiketler:
- - ios
- - uikit
- - swiftui
- kategoriler:
- - ios
- ---
- Bir uygulamayı en hızlı bozuk gösteren şeylerden biri, yazdığınız alanın üstünü kapatan bir klavye. Altta "Giriş yap" butonu olan bir login formu, bir sohbet giriş çubuğu, uzun bir kayıt formu: klavye açıldığı anda ekranın bir kısmı arkasında kayboluyor. iPad'de yüzen klavye ise her seferinde ekranın farklı bir yerini kapatabiliyor.
- Bugün hem UIKit'in hem SwiftUI'ın bunun için yerleşik araçları var ve bunlar elle yazılan birçok kodun yerini alıyor. Bu yazıda klavyenin layout'la ilişkisini, `UIKeyboardLayoutGuide`'ın ve SwiftUI'ın klavye safe area'sının nasıl çalıştığını, focus ve klavyeyi kapatma işini ve hâlâ sık düşülen tuzakları anlatıyorum.
- ## Klavye layout'u nasıl etkiliyor
- Yazılım klavyesi sizin view hiyerarşinizin parçası değil. Pencerenin üzerine kayarak geliyor ve ekranın alt kısmında bir text field ya da "Devam" butonu varsa üstünü kapatıyor. Sistem ona nasıl yapacağını söylemediğiniz sürece layout'unuzu değiştirmiyor.
- iOS 15'ten önce bunu söylemek hep aynı ritüel demekti: `keyboardWillShow` / `keyboardWillHide` (ya da daha iyisi `keyboardWillChangeFrameNotification`) dinlenir, `userInfo` içinden bitiş frame'i okunur, view'un koordinat sistemine çevrilir, safe area düşülür, sonra ya bir constraint'in constant'ı değiştirilir ya da scroll view'un `contentInset`'i ayarlanır. İdeal olanı bunu klavyenin animasyon eğrisiyle aynı anda yapmaktır. Bu sırada en az bir detayı atlamak çok kolay: iPad'deki yüzen klavye, cihaz döndürme ya da observer'ı kaldırmak.
- ## iOS 14 ve iOS 15 ile ne değişti
- iOS 15'ten beri her `UIView`'un klavyeyi sizin yerinize takip eden bir `keyboardLayoutGuide`'ı (`UIKeyboardLayoutGuide`) var. iOS 14'ten beri de SwiftUI klavyeyi bir safe area bölgesi olarak ele alıyor (`SafeAreaRegions.keyboard`), yani layout sistemi klavyeden zaten kaçınıyor. Deployment target'ınız iOS 15 veya üstüyse (2026'da büyük ihtimalle öyle) notification tabanlı yaklaşım artık legacy kod.
- ## UIKit: UIKeyboardLayoutGuide
- Fikir basit: guide'ın üst kenarı klavyenin üst kenarı. Klavye kapalıyken safe area'nın altında duruyor. İçeriğinizi ona bağlarsanız gerisini, animasyon dahil, Auto Layout hallediyor.
- ```swift
- import UIKit
- final class LoginViewController: UIViewController {
- private let emailField = UITextField()
- private let loginButton = UIButton(configuration: .filled()) // iOS 15+
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = .systemBackground
- emailField.borderStyle = .roundedRect
- emailField.placeholder = "E-posta"
- loginButton.configuration?.title = "Giriş yap"
- let stack = UIStackView(arrangedSubviews: [emailField, loginButton])
- stack.axis = .vertical
- stack.spacing = 12
- stack.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(stack)
- NSLayoutConstraint.activate([
- stack.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
- stack.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
- // Bütün numara bu: klavyenin (ya da safe area'nın) 16 pt üstünde dur.
- stack.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor, constant: -16)
- ])
- // iPad: yüzen ya da ayrılmış klavyeyi de takip et (iOS 15+).
- view.keyboardLayoutGuide.followsUndockedKeyboard = true
- }
- }
- ```
- Bilmeye değer iki property var:
- - `followsUndockedKeyboard` (iOS 15+) varsayılan olarak `false`. Bu durumda guide yalnızca sabit (docked) klavyeyi takip ediyor. iPad'de yüzen ya da ayrılmış klavyeyi de takip etmesini istiyorsanız `true` yapın.
- - `usesBottomSafeArea` (iOS 17+), klavye kapalıyken guide'ın alt safe area'ya uyup uymayacağını belirliyor. Bir giriş çubuğunun ekranın en altına yapışmasını istiyorsanız `false` yapın.
- ### Scroll view'lar: frame'i küçült ya da inset'i ayarla
- Formlar genelde bir scroll view içinde olur. İki yaklaşım var, varsayılan olarak ilkini öneriyorum.
- **Scroll view'u guide'a bağlamak.** Scroll view'un frame'i klavyenin başladığı yerde biter, yani her alana kaydırarak hâlâ ulaşılabilir. Düzenlenen alanın kendiliğinden görünür olmasını istiyorsanız `scrollRectToVisible`'ı kendiniz çağırın:
- ```swift
- final class FormViewController: UIViewController, UITextFieldDelegate {
- private let scrollView = UIScrollView()
- override func viewDidLoad() {
- super.viewDidLoad()
- scrollView.translatesAutoresizingMaskIntoConstraints = false
- scrollView.keyboardDismissMode = .interactive // aşağı kaydırınca kapanır
- view.addSubview(scrollView)
- NSLayoutConstraint.activate([
- scrollView.topAnchor.constraint(equalTo: view.topAnchor),
- scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- scrollView.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor)
- ])
- }
- func textFieldDidBeginEditing(_ textField: UITextField) {
- let rect = textField.convert(textField.bounds, to: scrollView)
- scrollView.scrollRectToVisible(rect.insetBy(dx: 0, dy: -16), animated: true)
- }
- }
- ```
- **`contentInset`'i ayarlamak.** Klasik yöntem bu. İçeriğin klavyenin arkasında da çizilmeye devam etmesi gerektiğinde, örneğin yarı saydam bir sohbet arka planında, hâlâ doğru seçim bu. Ayrı show/hide notification'ları yerine `keyboardWillChangeFrameNotification` kullanın ve inset ile birlikte `verticalScrollIndicatorInsets`'i (iOS 11.1+) de güncelleyin:
- ```swift
- @objc private func keyboardWillChangeFrame(_ note: Notification) {
- guard let endFrame = note.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
- let frameInView = view.convert(endFrame, from: view.window)
- let overlap = max(0, view.bounds.maxY - frameInView.minY - view.safeAreaInsets.bottom)
- scrollView.contentInset.bottom = overlap
- scrollView.verticalScrollIndicatorInsets.bottom = overlap
- }
- ```
- Inset yaklaşımı için özel bir nedeniniz yoksa guide'a bağlayın. Daha az kod ve daha fazla uç durumu kendisi hallediyor.
- ## SwiftUI: klavye safe area'sı ve focus
- iOS 14 ve sonrasında SwiftUI, klavye bir safe area bölgesi olduğu için içeriği zaten klavyenin yolundan çekiyor. iOS 13 için yazılmış özel "alanı yukarı taşı" kodları güncel sistemlerde framework'le çatışmaya eğilimli.
- SwiftUI'da asıl ihtiyacınız olan şey focus yönetimi. Aşağıda eksiksiz bir kayıt formu var:
- ```swift
- import SwiftUI
- struct SignUpForm: View {
- enum Field: Hashable { case name, email, password }
- @State private var name = ""
- @State private var email = ""
- @State private var password = ""
- @FocusState private var focusedField: Field? // iOS 15+
- var body: some View {
- NavigationStack { // iOS 16+
- ScrollView {
- VStack(spacing: 16) {
- TextField("Ad Soyad", text: $name)
- .focused($focusedField, equals: .name)
- .submitLabel(.next) // iOS 15+
- TextField("E-posta", text: $email)
- .keyboardType(.emailAddress)
- .textInputAutocapitalization(.never)
- .focused($focusedField, equals: .email)
- .submitLabel(.next)
- SecureField("Parola", text: $password)
- .focused($focusedField, equals: .password)
- .submitLabel(.join)
- }
- .textFieldStyle(.roundedBorder)
- .padding()
- }
- .scrollDismissesKeyboard(.interactively) // iOS 16+
- .onSubmit { // iOS 15+
- switch focusedField {
- case .name: focusedField = .email
- case .email: focusedField = .password
- default:
- focusedField = nil // klavyeyi kapatır
- register()
- }
- }
- .toolbar {
- ToolbarItemGroup(placement: .keyboard) { // iOS 15+
- Spacer()
- Button("Bitti") { focusedField = nil }
- }
- }
- .navigationTitle("Kayıt")
- }
- }
- private func register() { /* ... */ }
- }
- ```
- Birkaç not:
- - **Klavyeyi kapatmak** artık sadece `focusedField = nil`. Eski SwiftUI örneklerinde sık görülen, `UIApplication.shared`'a `resignFirstResponder` gönderme numarasına gerek kalmadı.
- - **`.onSubmit`** bağlandığı view'un içindeki text field'lar için çalışıyor, yani tek bir handler bütün formu yönetebiliyor.
- - **`.scrollDismissesKeyboard`** `.immediately` ve `.never` değerlerini de alıyor. Mesajlar uygulamasındaki hissi veren `.interactively`.
- ### Hareket etmesin: ignoresSafeArea(.keyboard)
- Bazen bir şeylerin *hareket etmemesini* istersiniz: tam ekran bir arka plan görseli ya da klavyenin alt kısmı düz bir şekilde örtmesi gereken bir layout. Bu view'lara `.ignoresSafeArea(.keyboard)` (iOS 14+) uygulayın:
- ```swift
- ZStack {
- Image("background")
- .resizable()
- .scaledToFill()
- .ignoresSafeArea(.keyboard) // arka plan yerinde kalır
- VStack {
- Spacer()
- TextField("Mesaj", text: $draft)
- .padding()
- }
- }
- ```
- ## Sık görülen tuzaklar
- - **Yaklaşımları karıştırmak.** `keyboardLayoutGuide`'a bağlı bir constraint *artı* hâlâ `contentInset` değiştiren eski bir notification handler, içeriği iki kez kaydırır. Geçiş yaparken eski observer'ı silin.
- - **Constraint çakışmaları.** Bir view hem klavye guide'ına hem de sabit bir üst constraint'e bağlıysa, klavye açıldığında birinin esnemesi gerekir. Birinin önceliğini düşürün ya da yüksekliği bir scroll view'un emmesine izin verin.
- - **Modifier yanlış view'da.** `.ignoresSafeArea(.keyboard)`'u nereye bağladığınız önemli. Derinlerdeki bir alt view'a değil, layout'u değişmemesi gereken container'a koyun ve sonucu cihazda kontrol edin.
- - **iPad.** Yüzen klavyeyi ve donanım klavyesini test edin. Donanım klavyesiyle yalnızca kısayol çubuğunu görebilirsiniz ve elle yazılmış frame hesabı bu durumda kolayca yanlış sonuç verebilir.
- - **Eski SwiftUI geçici çözümleri.** `GeometryReader` artı klavye publisher'ları ya da SwiftUI'ın ilk dönemi için yazılmış bir "adaptive keyboard" modifier'ı, iOS 14 ve sonrasındaki yerleşik davranışla genelde çatışır. Başka bir şeyi debug etmeden önce bunları kaldırın.
- ## Kontrol listesi
- 1. UIKit, iOS 15+: içeriği ya da scroll view'un altını `view.keyboardLayoutGuide.topAnchor`'a bağlayın.
- 2. iPad'de yüzen klavye sizin için önemliyse `followsUndockedKeyboard = true` yapın. iOS 17+ için `usesBottomSafeArea`'ya bakın.
- 3. `contentInset` ve `keyboardWillChangeFrameNotification` ikilisini yalnızca içeriğin klavyenin arkasında görünmeye devam etmesi gerekiyorsa kullanın.
- 4. SwiftUI, iOS 14+: klavye safe area'sına güvenin, gereken yerde `.ignoresSafeArea(.keyboard)` ile dışarıda kalın.
- 5. Alanlar arası geçiş ve klavyeyi kapatmak için `@FocusState` ile `.submitLabel` / `.onSubmit` (iOS 15+) kullanın.
- 6. Tap gesture numaraları yerine `.scrollDismissesKeyboard(.interactively)` (iOS 16+) kullanın.
- 7. Geçiş yaparken eski klavye notification kodunu silin.
- Eskiden elle yazılan klavye kodunun büyük kısmı artık sistemin bir özelliği. Yeni kodda genelde tek bir constraint ya da tek bir `@FocusState` işi görüyor.