SwiftUI: PencilKit ile Çizim
Kendi çizim uygulamanızı geliştirin!
👋 Hepinize merhaba sevgili TurkishKit okurları! Uzun bir aradan sonra yine heyecan verici bir proje ile sizinleyiz.
Bu yazımızda birlikte SwiftUI ve PencilKit kullanarak Apple Pencil’ın bütün özelliklerinden yararlanabileceğiniz bir çizim uygulaması geliştireceğiz. Fakat merak etmeyin, bir Apple Pencil’a sahip değilseniz bile bu uygulamayı geliştirebilir ve kullanabilirsiniz. Üstelik hem iPhone ve iPad destekliyor! 😌
🚀 Giriş
İşe her zaman olduğu gibi yeni bir proje oluşturmakla başlıyoruz. Uygulamanızı Mac bilgisayarınızdaki Xcode uygulamasını kullanarak geliştirebileceğiniz gibi, ben iPad ile yeni çıkan Swift Playgrounds 4 sürümünü kullanmak istiyorum. İlk kez WWDC21 konferansında duyurulan bu yeni sürüm, iPad’inizi kullanarak uygulama geliştirmenize ve App Store’da yayınlamanıza olanak veriyor. Oldukça heyecanlı!
Eğer siz de Playgrounds 4 ile çalışmak isterseniz en az iPadOS 15.2 sürümüne güncellediğinizden ve Playgrounds uygulamasının son sürümüne sahip olduğunuzdan emin olun.
💡İpucu: Playgrounds uygulamasında uygulama ikonunuzu aşağıda gördüğünüz gibi düzenleyebilirsiniz.
Sanatımızı yapmak için bir tuvale ihtiyacımız var. 😄 Bu yüzden ilk olarak ContentView
üzerinde bir değişiklik yapmadan CanvasView
isminde yeni bir Swift dosyası oluşturup kendimize Apple Pencil ile çizim yapabileceğimiz bir görünüm, yani tuvalimizi oluşturmalıyız. Playgrounds uygulamasında yeni bir Swift dosyası oluşturmanız için gereken adımlar aşağıda yer almakta.
PencilKit şu anda SwiftUI üzerinde bulunmadığından daha önceki makalelerimizden birinde de bahsettiğimiz UIViewRepresentable
protokolüne başvuracağız.
İlk adım yeni Swift dosyasına SwiftUI
ve PencilKit
Framework’lerini eklemek. Ardından aşağıdaki gibi CanvasView
isminde yeni bir struct
oluşturup içine PKCanvasView
tipinde bir parametre ekliyoruz.
Kendi kendinize bunun oldukça kısa olduğunu düşünüyor olabilirsiniz. Ancak merak etmeyin, bu sadece başlangıç. Sonraki adımlarda birçok extension
kullanarak bu struct
yapılarının üstüne birçok ekleme yapacağız.
import SwiftUI
import PencilKitstruct CanvasView {
@Binding var canvasView: PKCanvasView
}
Gördüğünüz üzere yukarıda bir UIKit gürünümü olan, Binding
bir PKCanvasView
değişkeni ekliyoruz. Yani CanvasView
, UIViewRepresentable
protokolünü kullanarak SwiftUI ile kullanılabilir hale getireceğimiz ana UIKit görünümünü dışarıdan alacak. Sonraki adımlarda ContentView
üzerinde PKCanvasView
tipinde bir State
değişkeni oluşturup CanvasView
içine atayacağız. Doğal olarak bütün bu uğraşın nedenini düşünüyor olabilirsiniz.
Bu yöntem ile PKCanvasView
UIKit görünümünün özelliklerine ContentView
üzerinden kolayca erişebileceğiz. Mesela tuvali temizlemek, ya da arkadaşlarınızla paylaşmak için tuval üzerindeki çizimi dışa aktarmak istediğinizde! 😁
Sonraki adımda struct
yapımızın bir extension
aracılığıyla UIViewRepresentable
protokolüne uymasını sağlıyoruz. Böylece CanvasView
görünümünü SwiftUI ile kullanabileceğiz.
extension CanvasView: UIViewRepresentable {
func makeUIView(context: Context) -> PKCanvasView {
// Varsayılan çizim aracını ayarlıyoruz:
canvasView.tool = PKInkingTool(.pen, color: .purple, width: 10)
// Parmak ile çizime izin veriyoruz
canvasView.drawingPolicy = .anyInput return canvasView
}func updateUIView(_ uiView: PKCanvasView, context: Context) { }
}
Yukarıda standard UIViewRepresentable
yapısına ek olarak canvasView.tool
parametresini ayarlayarak kullanıcı uygulamamızı ilk açtığında seçili olan çizim aracını belirliyoruz. Ardından canvasView.drawingPolicy
parametresini yukarıdaki gibi ayarlayarak bütün giriş metodlarına izin veriyoruz. Böylece uygulamamızın Apple Pencil’a ihtiyaç duymadan çalışmasını sağlıyoruz.
Artık çizim yapmak için ihtiyacımız olan minimum kodu tamamladık. Şimdiyse ContentView.swift
dosyasına geri dönüp ana arayüz için çalışalım.
İlk adım PencilKit
teknolojisini bu dosyaya da bir import
komutuyla eklemek olacak. Bunu SwiftUI
‘ın import
komutundan hemen sonra eklemelisiniz.
import PencilKit
Şimdi ContentView
struct
yapısına geçebiliriz. İçeriği aşağıdaki gibi gözükmeli. Daha önce de bahsettiğimiz gibi önce State
olarak bir PKCanvasView
görünümü tanımlıyor ve onu CanvasView
görünümümüze atıyoruz. Aynı zamanda CanvasView
görünümünü ilerleyen adımlarda ekleyeceğimiz temizleme ve paylaşma butonları için bir NavigationView
içine yerleştirmeliyiz.
struct ContentView: View {
// canvasView isimli bir UIKit PKCanvasView gürünümü tanımlıyoruz
@State private var canvasView = PKCanvasView() var body: some View {
NavigationView {
// Oluşturduğumuz UIViewRepresentable görünümünü ekliyor
// ve içine UIKit PKCanvasView görünümünü atıyoruz.
CanvasView(canvasView: $canvasView)
}
.navigationViewStyle(.stack)
}
}
🥳 Tebrikler! Uygulamanın temeli artık hazır. Uygulamanızı aşağıdaki gibi çalıştırıp çizim yapmayı hemen deneyebilirsiniz, ancak bir çizim uygulaması bundan çok daha fazlasına sahip olmalı. Hadi o zaman işe bir temizleme butonu ekleyerek devam edelim! 🙌
🧽 Tuvali Temizleme
Bu işlem belkide tahmin ettiğinizden çok daha kolay olacak! İlk adım tabii ki bir temizleme butonu eklemek. 😁
Temizleme butonunu bir tool bar yani araç çubuğu üzerine ekleyeceğiz. Şimdi CanvasView
görünümünüze bu niteleyicileri ekleyin, sonuç aşağıdaki gibi gözükmeli.
// ContentView içindeki CanvasView görünümü:CanvasView(canvasView: $canvasView)
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button(action: {
// Silme diyaloğunu görüntüleme kodu buraya gelecek
}) {
Label(“Clear”, systemImage: “trash”)
}
}
}
Önce toolbar
niteleyicisinin içine bir tane araç çubuğu içeriği, yani ToolBarItemGroup
objesi ekliyoruz ve sağa yerleştiriyoruz.
Silme işlemi kalıcı olduğundan, kullanıcının butona yanlışlıkla dokunma olasılığına karşı silmeden önce kullanıcıya bir onay diyaloğu sunmalıyız. Bunun içinse ilk adım ContentView
içine diyaloğun gösterilip gösterilmediğini kontrol eden bir State
değişkeni eklemek.
@State private var showingDeleteConfirmation = false
Harika! Şimdiyse butonun içindeki satır yorumu yerine bu kodu ekleyerek butona dokunulduğunda değişkenin değerinin true
olarak ayarlanmasını sağlamalıyız.
showingDeleteConfirmation = true
Sıra onay diyaloğunu eklemekte. Az önce kodladığımız butona aşağıda gördüğünüz şekilde .confirmationDialog
niteleyicisini ekleyin.
.confirmationDialog(“Clear canvas”, isPresented: $showingDeleteConfirmation) {
// Temizleme butonu
Button(“Clear”, role: .destructive) {
// UIKit PKCanvasView görünümünün çizimine yeni bir çizim atıyoruz
canvasView.drawing = PKDrawing()
}
// İptal butonu
Button(“Cancel”, role: .cancel) { }
} message: {
// Diyalog mesajı
Text(“Do you want to delete all of your work? This cannot be undone.”)
}
Eklediğimiz temizleme butonun action
argümanı, doğrudan UIKit PKCanvasView
görünümünün çizimi temsil eden drawing
değişkenine erişip, değerini yeni bir çizime ayarlıyor. Böylece tuvalimizi temizlemiş oluyoruz.
İptal butonuna ise .cancel
rolünü atadığımızdan action
parametresine hiçbir şey eklememize gerek kalmıyor. SwiftUI bizim için bütün işi çözüyor.
Böylelikle artık tek tuşla bütün tuvalimizi temizleyebiliyoruz! 🙌
🎨 Daha Fazla Araç!
Siz de takdir edesiniz ki tek bir kalem, istediğiniz gibi bir çizim yapmak için yeterli olmayabilir. Şimdi bir adım daha ileri giderek uygulamamıza PencilKit’in sunduğu tüm araç takımını ekleyeceğiz. Bu farklı kalem seçenekleri ve renkler dışında silgi, seçim aracı, cetvel ve ileri/geri alma fonksiyonlarını da ekliyor. Hadi işe koyulalım!
Proje dosyalarından CanvasView.swift
dosyasına geri dönün. İlk adım CanvasView
struct
yapısının içinde aşağıdaki gibi bir araç takımı, yani PKToolPicker
objesi oluşturmak.
@State private var toolPicker = PKToolPicker()
Mükemmel! Bir sonraki adım ise elimizdeki bu araç takımını göstermek. Bunu sağlayacak metodu struct
yapısına eklemek için aşağıdaki gibi yeni bir extension
yazıyoruz. Ayrıca kullandığımız private
anahtar kelimesi sayesinde extension
yapısını içeriği, sadece bu struct
içinden erişilebilir hale geliyor.
private extension CanvasView { // Araç takımını gösteren metot
func showToolPicker() {
// CanvasView aktifken araç takımını göster
toolPicker.setVisible(true, forFirstResponder: canvasView)
// CanvasView görünümünü araç değişiminde güncelle
toolPicker.addObserver(canvasView)
// CanvasView görünümünü ana görünüm yap
canvasView.becomeFirstResponder()
}
}
Metodumuzun içinde ilk olarak araç takımımızın görünürlüğünü CanvasView
görünürlüğüne bağlıyoruz. Ardından addObserver
metodu ile CanvasView
görünümünün araç takımında meydana gelen güncellemelerden haberdar olduğundan emin oluyoruz. Son olarak da CanvasView
görünümünü ana görünüm olarak ayarlayarak araç takımımızın göründüğünden emin oluyoruz.
Şimdi de fonksiyonumuzu aşağıdaki gibiUIViewRepresentable
protokolüne uyan extension
içindeki makeUIView
metodunun içine, return
komutundan hemen önce çağırıyoruz.
showToolPicker()
🥳 Artık uygulamanızı çalıştırdığınızda Apple Notlar uygulamasından alışık olduğumuz PencilKit araç takımını kullanabilirsiniz.
🖼 Sanatınızı Paylaşın!
Artık eserinizi oluşturdunuz, ve onu dünya ile paylaşma vakti! Belki de en önemli adım olan bu bölümde, uygulamamıza ekleyeceğimiz paylaşma menüsü sayesinde sanatınızı kaydedebilecek ve herkesle paylaşabileceksiniz. Hadi işe koyulalım! 🙌
Paylaşma menüsü de SwiftUI’da bulunmadığından, yine UIViewRepresentable
kullanmamız gerek. İlk adım ShareSheet.swift
isminde yeni bir dosya oluşturmak, ardından aşağıdaki gibi ShareSheet
isminde bir struct
yapısı oluşturuyoruz — tabii ki UIViewRepresentable
protokolünde.
struct ShareSheet: UIViewControllerRepresentable {
// Menünün görünürlüğünü kontrol ediyor
@Environment(\.presentationMode) private var presentationMode
// Paylaşılacak içerik
let activityItems: [Any] func makeUIViewController(context: UIViewControllerRepresentableContext<ShareSheet>) -> UIActivityViewController {
// Paylaşma görünümü objesini oluşturuyoruz
let viewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
// Paylaşma tamamlandığında çalışan metod
viewController.completionWithItemsHandler = { (_,_,_,_) in
// Menüyü kapatıyoruz
presentationMode.wrappedValue.dismiss()
}
return viewController
}func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ShareSheet>) { }
}
İlk olarak struct yapımızda menünün görünürlüğünü kontrol eden bir Environment
değişkeni ve paylaşılacak içeriği tutan bir değişken oluşturuyoruz.
Ardından UIViewRepresentable
protokol metotlarında biri olan makeUIViewController
metodunun içinde paylaşma menüsü ojesini oluşturuyoruz. Sonra da paylaşma menüsünün bir closure
‘ı olan completionWithItemsHandler
içerisine daha önce oluşturduğumuz değişkeni kullanarak menünün gizlenmesi için gereken kodu yazıyoruz. Bu closure
, paylaşma iştemi tamalandıktan sonra çalıştırılıyor, böylece paylaşma tamamlandıktan sonra menünün kendiliğinden kapanmasını sağlıyoruz.
Paylaşma menüsü SwiftUI için artık hazır, şimdiyse sıra onu çizimimizi paylaşmak için ana görünüme eklemek. ContentView.swift
dosyasına geri dönüp menünün görünürlüğünü kontrol eden aşağıdaki değişkeni ContentView
struct
yapısının içine, hemen showingDeleteConfirmation
değişkenin altına ekleyin.
@State private var showingShareSheet = false
Ardından daha önce oluşturduğumuz araç çubuğu, yani toolbar
içerisine paylaş butonunu ekliyoruz. Aşağıdaki kodu ToolbarItemGroup
içine ilk sıraya ekleyin., böylece paylaş butonu silme butonunun soluna yerleşecek.
Button(action: {
// Paylaş menüsünü görünür yapıyoruz
showingShareSheet = true
}) {
Label(“Share Drawing”,systemImage: “square.and.arrow.up”)
}
Aynı silme onay diyaloğunda olduğu gibi, bu butonun action
parametresinde de görünürlüğü kontrol eden değişkenin değerini true
olarak ayarlayıp butona dokunulduğunda menüyü açıyoruz.
Harika! Şimdi de bu değişkenin kontrol edeceği sheet
görünümünü ekleyelim, onun içerisine de paylaşma menüsünü. 😄 toolbar
niteleyicisinin hemen altında yer almalı.
💡 İpucu: Swift Playgrounds ve Xcode editöründe bir standart, köşeli ya da süslü bir parantezin eşini kolayca bulmak için üzerine çift tıklayabilirsiniz!
.sheet(isPresented: $showingShareSheet) {
// Paylaş menüsü
ShareSheet(activityItems: [canvasView.drawing.image(from: canvasView.bounds, scale: UIScreen.main.scale)])
}
Yukarıda canvasView
objesinin barındırdığı çizimi resim dosyası olarak ShareSheet
görünümünün paylaşılacak içerik parametresine atıyoruz. Böylece çizimi diğer uygulamalarla bir fotoğraf olarak paylaşabiliyoruz. Daha da iyisi, dışarı aktarılan resim PNG
formatında olduğundan tamamen saydam bir arka plana sahip!
Artık çalışmalarınızı kolayca cihazınıza kaydedebilir, ve sevdiklerinizle paylaşabilirsiniz!
🥳 Tebrikler! Çizim uygulamanız artık hazır. Unutmayın ki sadece bu çizim uygulamasıyla sınırlı kalmak zorunda değilsiniz. PencilKit teknolojisini aynı zamanda hali hazırdaki bir projenize de bu adımları takip ederek entegre edebilirsiniz. 😉
Umuyoruz ki bu makale size faydalı olmuştur ve yeni bilgiler öğrenmişsinizdir. 😌 Sorularınız olursa bize yourum yazmayı unutmayın, ve tabii ki bir sonraki yazımıza kendinize çok iyi bakın. Harika bir 2022 geçirmeniz dileğiye…