WWDC21: SwiftUI’a Gelen Yenilikler

Gelen yeniliklerle birlikte daha özelleştirilebilir olan SwiftUI’yı birlikte inceleyelim.

Can Balkaya
TurkishKit
5 min readJun 11, 2021

--

Giriş

SwiftUI, WWDC19’da ilk ortaya çıkışından beri bütün geliştiricilerin ilgisini çekmişti. WWDC20’de bu ilgi WidgetKit gibi bazı “framework”ler ile sadece SwiftUI kullanılabileceği söylendiğinde daha da arttı. WWDC21’de tanıtılan yenilikler ile birlikte SwiftUI gerçekten farklı bir boyuta geldiğini söylemem gerekiyor.

Makalenin başında söylemem gerekiyor ki burada WWDC21’de SwiftUI hakkında sadece tanıtılan temel yenilikleri bulabilirsiniz. İlerleyen zamanlarda yayınlayacağımız makalelerde bu yeniliklere değiniyor olacağız.

List

List objesi bir SwiftUI uygulamasındaki en yaygın obje olabilir. Bu sene List objesine gelen yenilikler ile birlikte neredeyse UITableView objesini aratmayacak gibi. Tabii ki hâlâ UITableView objesinin bütün özelliklerini barındırmıyor.

Genel olarak bu sene gelen yeniliklerle birlikte List objesinin içerisindeki hücrelerin stillerini ve renklerini özelleştirebiliyoruz. Bunun için gelen yeni “modifier”ları aşağıdan görebilirsiniz:

struct ContentView: View {

// MARK: - Properties
@State private var names = ["Sergen", "Ege", "Can", "Berkin", "Emirhan"]

// MARK: - View
var body: some View {
NavigationView {
List {
ForEach(names, id: \.self) { name in
Text(name)
}
}
.listRowSeparator(.visible, edges: .all)
.listSectionSeparator(.visible, edges: .all)
.listSectionSeparatorTint(Color.purple)
.listRowSeparatorTint(Color.red)
.navigationTitle("Names")
}
}
}

Ayrıca, artık List objesinin içerisindeki hücreleri kaydırırken ortaya çıkan butonların görünümlerini ve konumlarını değiştirebiliyoruz.

struct ContentView: View {

// MARK: - Properties
@State private var names = ["Sergen", "Ege", "Can", "Berkin", "Emirhan"]

// MARK: - View
var body: some View {
NavigationView {
List {
ForEach(names, id: \.self) { name in
Text(name)
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button("Remove", role: .destructive) {
names.removeAll { $0 == name }
}
}
.swipeActions(edge: .leading, allowsFullSwipe: true) {
Button("Copy") {
names.append(name)
}
}
}
}.navigationTitle("Names")
}
}
}

SF Symbols & TabView

Apple’ın Human Interface Guidelines’ında yazdığı gibi bir Tab Bar objesinin bir elemanı seçildiği zaman o eleman diğerlerine göre daha dolu ve canlı gözükmelidir. Eskiden SwiftUI’ın TabView objesinin elemanlarının Human Interface Guidelines’a uygun olması için elemanların görsellerinde kullanılan SF Symbols elemanlarını “fill” olarak seçerdik. Bu yıl ile birlikte artık SF Symbols’ın “fill” hallerini kullanmak zorunda değiliz çünkü SwiftUI o anki duruma göre sembolleri yönetebiliyor.

What’s New In SwiftUIApple Developer

Bu şekilde Tab Bar ikonlarınızın çok yönlü olmasını sağlayabilirsiniz. Örneğin üstteki TabView objesindeki elemanların görsellerini yukarıda bahsettiğimiz şekilde bir Mac uygulaması olarak çalıştırırsak ikonların Mac platformuna özel şekilde değiştiğini görürsünüz.

What’s New In SwiftUIApple Developer

Refreshable

Bu sene ile birlikte güncellenebilen veya yeniden getirilebilen ekranların içerisindeki elemanları yenilemek için artık refreshable “modifier”ını kullanabiliriz. Bu sayede yukarında aşağıya doğru kaydırma hareketi ile bir liste içerisindeki elemanları yineleyebiliriz:

struct ContentView: View {

// MARK: - Properties
@State private var names = ["Sergen", "Ege", "Can", "Berkin", "Emirhan"]

// MARK: - View
var body: some View {
NavigationView {
List {
ForEach(names, id: \.self) { name in
Text(name)
}
}
.refreshable {
names.append("❤️ TurkishKit")
}
.navigationTitle("Names")
}
}
}

Refreshable ile alakalı yazdığımız yazıya aşağıdan ulaşabilirsiniz:

TimelineView

TimelineView bu yıl hayatımıza giren bir başka SwiftUI objesidir. Eskiden SwiftUI ile oluşturulmuş bir ekranın içerisindeki bir değerin değiştirilmesi için @State veya @Environment “property wrapper”larını kullanmak gerekiyordu. Artık TimelineView ile tanımladığınız belli saatler arasında UI elemanlarınızı güncelleyebiliyoruz.

Bir saat uygulamasında kullanabilecek bir örnek verelim:

TimelineView(PeriodicTimelineSchedule(from: startDate, by: 1)) { context in
AnalogTimerView(date: context.date)
}

Text

Bunu sene tanıtılan AttributedString değer türü ile birlikte artık Text içerisinde kullandığımız String elemanlarını renklerini ve stillerini özelleştirebiliyoruz ve hatta ekstra işlevler tanımlayabiliyoruz.

Aşağıdaki örnekte AttributedString ile bir String değerini markdown haline getiriyoruz:

struct ArticleView: View {

// MARK: - Properties
let post: Article
var markdown: AttributedString {
try! AttributedString(markdown: article.content)
}

// MARK: - View
var body: some View {
HStack {
AsyncImage(url: article.image)
VStack {
Text(article.title)
Text(markdown)
}
}
}
}

Ayrıca Text objesi içerisinde yazdığımız String elemanlarında markdown operatörleri kullanabiliyoruz.

struct ContentView: View {

// MARK: - View
var body: some View {
Text("**TurkishKit ❤️**")
}
}

AttributedString ile alakalı yazdığımız makaleye buradan ulaşabilirsiniz:

Search

Ben de geçen seneden beri SwiftUI’a UIKit’in UISearchBar objesinin bir benzerinin gelmesini bekliyordum. Bu sene sonunda searchable “modifier”ı ile çok kolay bir şekilde arama çubuğu ve arama özelliklerini kullanabiliyoruz.

struct ContentView: View {

// MARK: - Properties
@State private var query: String = ""
@State private var names = ["Sergen", "Ege", "Can", "Berkin", "Emirhan"]

// MARK: - View
var body: some View {
NavigationView {
List {
ForEach(names, id: \.self) { name in
Text(name)
}
}
.searchable("Search term", text: $query, placement: .automatic)
.onChange(of: query) { print($0) }
.navigationTitle("Messages")
}
}
}

AsyncImage

AsyncImage objesi URLSession kullanarak internetten görsel indirmenize ve sunmanıza olanak tanır. Kullanımı oldukça kolay olduğunu söyleyebilirim.

struct Article: Hashable {

// MARK: - Properties
let image: URL
let title: String
let content: String
}

struct ArticleView: View {

// MARK: - Properties
let article: Article

// MARK: - View
var body: some View {
HStack {
AsyncImage(url: article.image)
VStack {
Text(article.title)
Text(article.content)
.foregroundColor(.secondary)
}
}
}
}

AsyncImage ile alakalı yazdığımız yazıya aşağıdan ulaşabilirsiniz:

@FocusState

WWDC21’de tanıtılan “Odak” modunu SwiftUI uygulamarımıza da entegre etmek için Apple bize @FocusState adında bir “property wrapper” sunuyor. Bu sayede @FocusState ile tanımlanan değere göre uygulamanızın özelliklerini değiştirebilirsiniz.

struct LoginForm: View {

// MARK: - Enumerations
enum Field: Hashable {
case usernameField
case passwordField
}

// MARK: - Properties
@State private var username = ""
@State private var password = ""
@FocusState private var focusedField: Field?

// MARK: - View
var body: some View {
VStack {
TextField("Username", text: $username)
.focused($focusedField, equals: .usernameField)

SecureField("Password", text: $password)
.focused($focusedField, equals: .passwordField)

Button("Sign In") {
if username.isEmpty {
focusedField = .usernameField
} else if password.isEmpty {
focusedField = .passwordField
} else {
handleLogin(username, password)
}
}
}
}
}

Material

Bu sene iOS’te derinlik hissi uyandırmak için kullanabileceğiniz yarı saydam bir efekt oluşturan Material objelerini kullanabiliriz. SwiftUI’ın önceki sürümlerinde Material objelerine erişimimiz yoktu. Neyse ki SwiftUI’ın yeni sürümü bize ultra inceden ultra kalına kadar çok çeşitli objeler sağlıyor.

Örnek olarak Label objesinin verilebilir:

ZStack {
Color.teal
Label("Flag", systemImage: "flag.fill")
.padding()
.background(.regularMaterial)
}

Sonuç

Makalenin başında da söyleceğimiz. Kişisel olarak SwiftUI şu anki haliyle yeni bir uygulama geliştirmek veya önceden geliştirilmiş bir uygulamanın yeni bölümlerini geliştirmek için oldukça elverişli.

iOS 15’in -Türkiye dahil 😅- dünya genelinde iOS ekosistemini domine etmeye başladığı zaman “production-ready” projelerimde SwiftUI’ı sonuna kadar kullanmak için sabırsızlanıyorum!

Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!

Twitter | Instagram | Facebook

--

--