SwiftUI: Alert
Alert, kullanıcılarla etkileşimde olan bir arayüz elemanıdır.
Merhaba sevgili TurkishKit okuyucuları! 👋🏼 Bugün sizlerle Alert
objesinin ne olduğunu ve uygulamalarımızda nasıl kullanabileceğimizi öğreneceğiz. Hazırsanız hemen başlayalım! 🎊
Alert Nedir?
Alert
objesinin objesi, UIKit “framework”ünde bulunan UIAlertController
objesinin SwiftUI’a taşınmış versiyonudur diyebiliriz. Bu obje iOS 8'den beridir uygulamalarda kullanılan, oldukça bilinen bir arayüz elemanıdır. Bu arayüz elemanını Apple’ın herhangi bir uygulamasında görmeniz mümkündür.
Bu arayüz elemanını genellikle bir kullanıcı hatasını göstermek için ya da kullanıcıdan bir tercih yapmasını istediğimiz zaman kullanırız.
SwiftUI’da Alert
objesini kodlamak oldukça kolaydır. Makalenin ilerleyen taraflarında da bu arayüz elamanını nasıl kodlayabileceğimizi öğreneceğiz.
Alert Objesine Genel Bakış
Yeni bir SwiftUI projesi oluşturalım ve kodlamaya başlayalım. İlk olarak Alert
objemizi ve aldığı parametreleri inceleyelim.
Alert(
title: Text(“Uyarı Başlığı”),
message: Text(“Uyarı İçeriği”),
dismissButton: .default(Text(“Tamam”)),
primaryButton: .default(Text(“Oluştur”)),
action: {},
secondaryButton: .destructive(Text("İptal"))
)
title: Uyarımızın başlığı.
message: Uyarımızın açıklaması
dismissButton, primaryButton, secondaryButton: Uyarımıza ait butonlar
Alert
yazıp parantez açtığımızda Alert
nesnesine ait diğer parametreleri görebiliriz.
Alert Oluşturma
Makalenin başında Alert
objesini daha çok kullanıcılara yapılan bir aksiyonun sonucunu göstermek amacıyla kullandığımızı anlatmıştık. Bu kullanım amacına uygun şekilde küçük bir soru çözme uygulaması geliştireceğiz.
Bu uygulamayı geliştirirken basit bir Alert
objesinin nasıl oluşturabileceğimizden ve UIViewControllerRepresentable
ile daha komplike Alert
objeleri nasıl geliştirebileceğinizi öğreneceksiniz.
Bu uygulamada Alert
objesi dışında daha birçok arayüz elemanı mevcut ama makalemizin konusu sadece Alert
olduğu için diğerlerini es geçmek için uygulamanın başlangıç projesini indirmeliyiz.
Başlangıç projesi “Starter” klasörünün içerisindedir. Projeyi açtıktan sonra yapacağımız ilk iş “QuestionView.swift” dosyasına gidip bir Alert
objesi oluşturmaya başlamaktır. Buradaki Alert
objemiz kullanıcının soruyu doğru çözüp çözmediğini göstermeye yarayacaktır.
Basit Bir Alert Objesi Oluşturma
İlk önce objemizin kullanıcı tarafından görüntülenmesini kontrol etmemizi sağlayacak “showingAlert” isimli bir Bool
elemanı oluşturalım.
@State var showingAlert = false
Ekranın içerisindeki butona bastığımızda bu değerin değişmesi için butonumuzun action
özelliğinin içerisinde showingAlert
değerini true
olarak ayarlayalım.
Button(action: {
if answer == question.result {
result = true
} else {
result = false
} showingAlert = true
}) {
//...
En tepedeki VStack
objesinin sonuna alert “modifier”ını kullanarak Alert
objesini tanımlayalım.
.alert(isPresented: $showingAlert, content: {
Alert(title: Text(result ? "Doğru!" : "Yanlış"), message: Text(result ? "Cevabın doğru. Tebrikler! 🥳" : "Cevabın yanlış. Bir daha deneyebilirsin."), dismissButton: .cancel())
})
Bu şekilde basit bir Alert
objesi oluşturmuş olduk! 🥳
İsterseniz makalenin başında gösterdiğim özellikler ile bu örneği geliştirebilirsiniz. 😉
UIViewControllerRepresentable ile Özel Alert Objeleri Oluşturmak
Uygulamamızın ilk sayfasında bir tane daha Alert
objesi oluşturmamız gerekiyor çünkü bu sayfada onunla soru oluşturacağız. Yalnız, bu Alert
objesini SwiftUI’da oluşturabilmemiz için biraz dolambaçlı ama havalı bir yoldan geçmemiz gerekecek, çünkü bu objenin içerisinde (tıpkı UIAlertController
ile yapabildiğimiz gibi) TextField
elemanları kullanacağız. Bunu sadece şu anlık SwiftUI yapabilmek mümkün değil. O yüzden, UIViewControllerRepresentable
ile bazı elemanlar oluşturmamız gerekiyor.
Oluşturmamız gereken ilk eleman TextAlert
modelidir. Bu veri modelini kullanarak Alert
objesiyle nasıl işlemler yapabileceğimizi ve TextField
elemanlarının görünüşünü ayarlayabiliyoruz.
struct TextAlert { // MARK: - Properties
var title: String
var firstPlaceholder = "İlk Sayı"
var secondPlaceholder = "İkinci Sayı"
var thirdPlaceholder = "İşlem: +, -, / veya *"
var accept: String = "Tamam"
var cancel: String = "Vazgeç"
var action: ([String?]) -> ()
}
Artık Alert
objesi yerine kullanacağımız AlertWrapper
elemanını oluşturabiliriz. Bu elemanın bizim SwiftUI’da kullandığımız Alert
objesinin versiyonlaştırmasıdır diyebiliriz. “AlertWrapper” isminde yeni bir Swift dosyası oluşturup aşağıdaki kodları dosyada yazmanız durumunda AlertWrapper
objesini projede kullanabilirsiniz.
struct AlertWrapper<Content: View>: UIViewControllerRepresentable { // MARK: - Properties
@Binding var isPresented: Bool
let alert: TextAlert
let content: Content // MARK: - Functions
func makeUIViewController(context: UIViewControllerRepresentableContext<AlertWrapper>) -> UIHostingController<Content> {
UIHostingController(rootView: content)
} // MARK: - Models
final class Coordinator {
var alertController: UIAlertController? init(_ controller: UIAlertController? = nil) {
self.alertController = controller
}
} func makeCoordinator() -> Coordinator {
return Coordinator()
}func updateUIViewController(_ uiViewController: UIHostingController<Content>, context: UIViewControllerRepresentableContext<AlertWrapper>) {
uiViewController.rootView = content
if isPresented && uiViewController.presentedViewController == nil {
var alert = self.alert
alert.action = {
self.isPresented = false
self.alert.action($0)
}
context.coordinator.alertController = UIAlertController(alert: alert)
uiViewController.present(context.coordinator.alertController!, animated: true)
} if !isPresented && uiViewController.presentedViewController == context.coordinator.alertController {
uiViewController.dismiss(animated: true)
}
}
}
Bir önceki başlıkta alert
“modifier”ını yazdığımız sadelikte kod yazmak için View
sınıfı için AlertWrapper
objesini çıktı olarak veren bir fonksiyon tanımlayacağız.
extension View {
func alert(isPresented: Binding<Bool>, _ alert: TextAlert) -> some View {
AlertWrapper(isPresented: isPresented, alert: alert, content: self)
}
}
A sınıfında hâlâ bir hata olduğunu siz de fark etmişsinizdir. O hatanın sebebi, UIAlertController
sınıfının TextAlert
sınıfını tanıyarak işlem yapamasıdır. Bu hatayı gidermek için bir UIAlertController
için bir “extension” tanımlayalım.
extension UIAlertController {
convenience init(alert: TextAlert) {
self.init(title: alert.title, message: nil, preferredStyle: .alert)
addTextField {
$0.placeholder = alert.firstPlaceholder
$0.keyboardType = .numberPad
} addTextField {
$0.placeholder = alert.secondPlaceholder
$0.keyboardType = .numberPad
}
addTextField {
$0.placeholder = alert.thirdPlaceholder
$0.keyboardType = .numbersAndPunctuation
} addAction(UIAlertAction(title: alert.cancel, style: .cancel) { _ in
alert.action([""])
}) let firstTextField = textFields![0]
let secondTextField = textFields![1]
let thirdTextField = textFields![2]
addAction(UIAlertAction(title: alert.accept, style: .default) { _ in
alert.action(["\(firstTextField.text ?? "")", "\(secondTextField.text ?? "")", "\(thirdTextField.text ?? "")"])
})
}
}
Bunun sayesinde TextField
elemanlarımızın çıktılarını uygulama içerisinde kullanabileceğiz.
Artık bu yaptıklarımızı “MainView” içerisinde kullanmaya başlayabiliriz. İlk önce objemizin görünüp görünmemesi için kullandığımız klasik değerimizi tanımlayalım.
@State var showingAlert = false
Butona bastığımız zaman AlertWrapper
objesinin görünmesi için butonun action
özelliğinin içerisinde daha önce yaptığımız gibi “showingAlert” değerini true
olarak tanımlayalım.
Button(action: {
showingAlert = true
}) {
Image(systemName: "plus.circle")
}
Son olarak yapmamız gereken şey alert
“modifier”ını kullanarak objemizi finalize etmek. Öncekinden farklı olarak burada Alert
objesi yerine TextAlert
modelinin action özelliğini kullanarak AlertWrapper
objemizi kullanıyoruz.
.alert(
isPresented: $showingAlert,
TextAlert(title: "Soru Oluştur!", action: { action in
var isOperator = false
let _operator: Question.Operations!
let chosenOperator: String = action[2]! switch chosenOperator {
case "+":
_operator = .arti case "-":
_operator = .eksi case "/":
_operator = .bolu case "*":
_operator = .carpi default:
isOperator = true
_operator = .arti
} let newQuestion = Question(firstNumber: Int(action[0]!) ?? 0, secondNumber: Int(action[1]!) ?? 0, _operator: _operator) if !isOperator {
questions.insert(newQuestion, at: 0)
}
})
)
“modifier”ın üst kısımları TextField
objesinden gelen String
değerini ele alıp Operators
türüne çevirmek içindir.
Artık projemizi çalıştırabiliriz! Siz de projenizi çalıştırdığınızda (uygulamanın sağ üstündeki butona tıkladığınızda) aşağıdaki gibi bir Alert
objesi ile karşılaşacaksınızdır.
Ayrıca bir soru oluşturduktan sonra oluşan soru elemanına tıklarsanız, makalenin başlarında yaptığımız basit Alert
objesini de deneyimleyebilirsiniz.
Uygulamanın final versiyonuna yukarıda başlangıç projesini indirmek için eklediğim bağlantıdan erişebilirsiniz.
Bir makalemizin daha sonuna gelmiş bulunuyoruz. Bu yazımızda Alert
objesini ele aldık. İlerleyen zamanlarda paylaşacağımız yeni makalelerde görüşmek üzere, hoşça kalın! 👋