SwiftUI: iOS icin Modern Arayuzler Olusturma

SwiftUI ile modern kullanici arayuzleri olusturma rehberi: deklaratif sozdizimi, bilesenler, animasyonlar ve iOS 18 icin en iyi uygulamalar.

Modern iOS arayuzleri olusturmak icin SwiftUI rehberi

SwiftUI, tum Apple platformlarinda arayuz gelistirmeyi koklu bir bicimde donusturdu. Deklaratif sozdizimi ve yerel entegrasyonu sayesinde bu framework, daha once mumkun olandan cok daha az kodla zarif uygulamalar olusturmaya olanak tanir. iOS 18 ile birlikte performans alaninda onemli iyilestirmeler ve yeni yetenekler sunulmaktadir.

Why SwiftUI in 2026?

SwiftUI, iOS 18 ile tam olgunluga ulasti. Optimize edilmis render, iyilestirilmis bellek yonetimi ve basitlestirilmis UIKit entegrasyonu sunmaktadir. Yeni iOS uygulamalari icin standart haline gelmistir.

Deklaratif Paradigmayi Anlamak

Kod yazmaya baslamadan once SwiftUI'yi farkli kilan seyin ne oldugunu kavramak gerekir. UIKit'te (eski framework) gelistirici, iOS'a arayuzu adim adim nasil olusturacagini soylemek zorundaydi: "bir etiket olustur, buraya yerlestir, kullanici dokundugunda rengini degistir". Bu imperatif (buyurgan) paradigmadir.

SwiftUI farkli calisir: gelistirici ne goruntulemek istedigini tarif eder ve framework gerisini halleder. Aradaki fark, donus donus yol tarifi vermekle (imperatif) yalnizca varilacak yeri belirtmek (deklaratif) arasindaki fark gibidir.

Ilk View

SwiftUI'de her arayuz ogesi bir View'dir. View, ekranda neyin gorunmesi gerektigini tanimlayan bir struct'tir. Asagida bir baslik, alt baslik ve buton iceren ilk ekran yer almaktadir:

ContentView.swiftswift
import SwiftUI

// Each screen is a struct that implements the View protocol
struct ContentView: View {

    // The "body" property describes what the view displays
    // "some View" means "a type of View, but Swift figures it out automatically"
    var body: some View {

        // VStack = "Vertical Stack": stacks elements vertically
        // spacing: 20 = 20 points of space between each element
        VStack(spacing: 20) {

            // A simple text with style modifiers
            Text("Welcome to SharpSkill")
                .font(.largeTitle)      // Large title font
                .fontWeight(.bold)      // Bold text

            Text("Prepare for your iOS interviews")
                .font(.subheadline)     // Smaller font
                .foregroundColor(.secondary)  // Gray secondary color

            // Button with an action (closure) and a label
            Button("Get Started") {
                print("Button tapped!")
            }
            .buttonStyle(.borderedProminent)  // Filled blue button style
        }
        .padding()  // Adds margins around the VStack
    }
}

Yapiya dikkat edilmesi onemlidir: istenen ogeler (metinler, buton) tanimlanir, dikey olarak istiflenirler (VStack) ve stiller modifier'lar (.font(), .padding()) araciligiyla uygulanir.

Temel prensip: SwiftUI'de UI nesneleri "olusturulmaz" -- istenen arayuz tarif edilir. SwiftUI, gercek ogelerin olusturulmasini, guncellenmesini ve yok edilmesini kendi basina yonetir.

Modifier'lar: View'leri Donusturmek

Modifier'lar, bir view'den sonra zincirlenen ve onu donusturen metotlardir. Ust uste uygulanan filtreler gibi calisirlar. Sira onemlidir cunku her modifier bir oncekini saran yeni bir view olusturur.

Asagidaki ornek, siralanmanin neden kritik oldugunu gostermektedir:

ModifiersOrder.swiftswift
// Example 1: padding THEN background
Text("SwiftUI")
    .padding()           // 1. Adds 16pt of space around the text
    .background(.blue)   // 2. Blue background covers text + padding
    .foregroundColor(.white)
// Result: white text on blue rectangle with margins

// Example 2: background THEN padding (reversed order!)
Text("SwiftUI")
    .background(.blue)   // 1. Tight blue background around text only
    .padding()           // 2. Transparent padding around blue background
    .foregroundColor(.white)
// Result: white text on small blue rectangle, surrounded by empty space

Fark nedir? Birinci durumda padding arka planin "icinde"dir. Ikinci durumda ise "disinda"dir. Incelikli ama duzen tasariminda ustunluk saglamak icin temel bir ayrinti.

Arayuzleri Stack'lerle Duzenlemek

SwiftUI, view'leri duzenlemek icin uc ana kapsayici sunar. Bunlar, iceriklerini farkli sekillerde dizilten kutular olarak dusunulebilir.

VStack, HStack ve ZStack

  • VStack (Vertical Stack): ogeleri yukaridan asagiya istifler
  • HStack (Horizontal Stack): ogeleri soldan saga hizalar
  • ZStack (Z-axis Stack): ogeleri ust uste katmanlar

Asagida her uc stack'i birlestiren bir kullanici profil karti olusturulmaktadir. Amac: dogrulama rozeti ile birlikte bir fotograf, ardindan kullanicinin adi ve rolu gostermek.

ProfileCard.swiftswift
struct ProfileCard: View {
    var body: some View {
        // Main HStack: photo on left, info on right
        HStack(spacing: 16) {

            // ZStack to overlay the badge on the photo
            ZStack(alignment: .bottomTrailing) {
                // Profile image (circle)
                Image("avatar")
                    .resizable()
                    .frame(width: 60, height: 60)
                    .clipShape(Circle())

                // Green "verified" badge at bottom right
                Image(systemName: "checkmark.circle.fill")
                    .foregroundColor(.green)
                    .background(Circle().fill(.white))  // White circle behind
            }

            // VStack to stack name and role vertically
            VStack(alignment: .leading, spacing: 4) {
                Text("Marie Dupont")
                    .font(.headline)

                Text("iOS Developer")
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            }

            // Spacer pushes everything to the left
            Spacer()

            // Chevron on right indicates it's tappable
            Image(systemName: "chevron.right")
                .foregroundColor(.gray)
        }
        .padding()
        .background(Color(.systemGray6))
        .cornerRadius(12)
    }
}

Buradaki kilit nokta Spacer()'dir: mevcut tum alani kaplayan gorunmez bir oge. Bu olmadan ogeler ortaya hizalanir. Spacer sayesinde sola itilirler ve chevron saga sabitlenmis olarak kalir.

Xcode Tip

Xcode'da herhangi bir view uzerinde ⌘ + click kullanilarak gorsel inspektore erisilebilir. Kod yazmadan modifier eklemek mumkundur.

@State ve @Binding ile Durum Yonetimi

Durum yonetimi SwiftUI'nin kalbini olusturur. Durum (state), degisebilen ve arayuzu guncellemesi gereken herhangi bir veridir. Durum degistiginde SwiftUI etkilenen view'leri otomatik olarak yeniden hesaplar.

@State: Bir View'in Yerel Durumu

@State, SwiftUI'ye "bu degiskeni izle ve degistiginde view'i yenile" diyen bir property wrapper'dir. Tek bir view'in yerel durumu icin idealdir.

Mekanizmayi anlamak icin asagida interaktif bir sayac yer almaktadir:

CounterView.swiftswift
struct CounterView: View {
    // @State creates a "source of truth" for this view
    // private because state shouldn't be modified from outside
    @State private var count = 0

    var body: some View {
        VStack(spacing: 30) {
            // This Text updates automatically when count changes
            Text("\(count)")
                .font(.system(size: 72, weight: .bold))

            HStack(spacing: 40) {
                // Decrement button
                Button(action: {
                    count -= 1  // Modifies state → view refreshes
                }) {
                    Image(systemName: "minus.circle.fill")
                        .font(.largeTitle)
                }

                // Increment button
                Button(action: {
                    count += 1
                }) {
                    Image(systemName: "plus.circle.fill")
                        .font(.largeTitle)
                }
            }
        }
    }
}

Bir butona dokunuldugunda count degeri degisir. SwiftUI bu degisikligi algilar ve goruntuyu guncellemek icin body'yi yeniden calistirir. Etiketi elle guncellemek gerekmez -- her sey otomatik olarak gerceklesir.

@Binding: View'ler Arasinda Durum Paylasimi

Bazen bir alt view (child), ust view'in (parent) durumunu degistirmek zorunda kalir. @Binding tam burada devreye girer: mevcut bir @State'e cift yonlu bir baglanti olusturur.

Asagida somut bir ornek bulunmaktadir: gercek zamanli dogrulamali bir kullanici adi giris alani.

UsernameValidation.swiftswift
// Parent view: owns the state
struct SignupForm: View {
    @State private var username = ""       // Source of truth
    @State private var isValid = false     // Validation state

    var body: some View {
        VStack(spacing: 20) {
            // We pass BINDINGS (with $) to the child view
            UsernameField(username: $username, isValid: $isValid)

            Button("Create Account") {
                // Submit the form
            }
            .disabled(!isValid)  // Disabled if invalid
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

Alt view binding'leri alir ve bunlari degistirebilir:

swift
// Child view: receives and modifies state via @Binding
struct UsernameField: View {
    @Binding var username: String   // Connection to parent's @State
    @Binding var isValid: Bool

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            TextField("Username", text: $username)
                .textFieldStyle(.roundedBorder)
                .onChange(of: username) { oldValue, newValue in
                    // Validation: at least 3 characters
                    isValid = newValue.count >= 3
                }

            // Visual feedback
            HStack {
                Image(systemName: isValid ? "checkmark.circle" : "xmark.circle")
                Text("Minimum 3 characters")
            }
            .font(.caption)
            .foregroundColor(isValid ? .green : .red)
        }
    }
}

Kullanici TextField'a yazdiginda, username binding araciligiyla degistirilir. Ust view bu degisikligi gorur ve kullanabilir. Temiz bir cift yonlu iletisimdir.

Warning

@State yalnizca basit, yerel durumlar icin kullanilmalidir. Birden fazla ekran arasinda paylasilan veriler veya karmasik mantik icin @Observable (iOS 17+) veya MVVM kaliplarini tercih etmek daha dogrudur.

iOS mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Dinamik Listeleri Goruntuleme

Listeler mobil uygulamalarin her yerinde bulunur. SwiftUI, veri koleksiyonlarini yerel iOS stiliyle (ayiricilar, kayma eylemleri vb.) goruntulemek icin List sunar.

Basit Bir Liste Olusturma

Bir listeyi goruntulemek icin iki sey gereklidir: veri ve onu tanimlama yolu. Identifiable protokolu, SwiftUI'ye hangi view'in hangi veriye karsilik geldigini bildirir.

Once veri modeli tanimlanir:

Models/Interview.swiftswift
// Identifiable lets SwiftUI track each element
struct Interview: Identifiable {
    let id = UUID()           // Auto-generated unique identifier
    let technology: String
    let difficulty: String
    let questionCount: Int
}

Simdi liste. Fikir, ForEach ile veriler uzerinde yinelemek ve her oge icin bir satir olusturmaktir:

InterviewListView.swiftswift
struct InterviewListView: View {
    // Data to display (in reality, this would come from an API)
    @State private var interviews = [
        Interview(technology: "iOS", difficulty: "Intermediate", questionCount: 25),
        Interview(technology: "Android", difficulty: "Advanced", questionCount: 30),
        Interview(technology: "React", difficulty: "Beginner", questionCount: 20)
    ]

    var body: some View {
        // NavigationStack enables the navigation bar
        NavigationStack {
            List {
                // ForEach iterates over each interview
                // Thanks to Identifiable, no need to specify id:
                ForEach(interviews) { interview in
                    InterviewRow(interview: interview)
                }
            }
            .navigationTitle("My Interviews")
        }
    }
}

Her satir icin view, okunabilirlik acisindan ayri bir bilesene cikartilmistir:

InterviewRow.swiftswift
struct InterviewRow: View {
    let interview: Interview

    var body: some View {
        HStack {
            // Left column: title and subtitle
            VStack(alignment: .leading, spacing: 4) {
                Text(interview.technology)
                    .font(.headline)

                Text(interview.difficulty)
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            }

            Spacer()

            // Badge with question count
            Text("\(interview.questionCount) Q")
                .font(.caption)
                .fontWeight(.medium)
                .padding(.horizontal, 8)
                .padding(.vertical, 4)
                .background(Color.blue.opacity(0.1))
                .cornerRadius(8)
        }
        .padding(.vertical, 4)
    }
}

InterviewRow'u ayri bir struct'a cikarmak kodu daha okunabilir ve yeniden kullanilabilir hale getirir. Bu, SwiftUI'de yerlesik bir en iyi uygulamadir.

Eylem Ekleme: Silme ve Yeniden Siralama

iOS listeleri dogal olarak silme (sola kaydir) ve yeniden siralama (surukle ve birak) destekler. SwiftUI bunu .onDelete ve .onMove ile son derece kolaylastirir:

InterviewListView.swift (enhanced version)swift
struct InterviewListView: View {
    @State private var interviews = [/* ... data ... */]

    var body: some View {
        NavigationStack {
            List {
                ForEach(interviews) { interview in
                    InterviewRow(interview: interview)
                }
                // Swipe to delete
                .onDelete(perform: deleteInterview)
                // Drag and drop to reorder
                .onMove(perform: moveInterview)
            }
            .navigationTitle("My Interviews")
            .toolbar {
                // "Edit" button that activates edit mode
                EditButton()
            }
        }
    }

    // Deletes elements at specified indices
    private func deleteInterview(at offsets: IndexSet) {
        interviews.remove(atOffsets: offsets)
    }

    // Moves elements from one position to another
    private func moveInterview(from source: IndexSet, to destination: Int) {
        interviews.move(fromOffsets: source, toOffset: destination)
    }
}

Yalnizca 4 ek satir kod (.onDelete, .onMove, EditButton ve iki fonksiyon) ile tamamen interaktif bir liste elde edilir. SwiftUI'nin gucu budur.

Arayuzleri Animasyonlandirma

SwiftUI animasyonlarda one cikar. Animasyonlarin cok fazla kod gerektirdigi UIKit'in aksine, burada her sey deklaratiftir: son durum tarif edilir ve SwiftUI gecisi animasyonlandirir.

withAnimation ile Ortuk Animasyonlar

Animasyonlamanin en basit yolu, bir durum degisikligini withAnimation icine sarmaktir. SwiftUI neyin degistigini algilar ve etkilenen gorsel ozellikleri otomatik olarak animasyonlandirir.

AnimatedCard.swiftswift
struct AnimatedCard: View {
    @State private var isExpanded = false

    var body: some View {
        VStack {
            RoundedRectangle(cornerRadius: 20)
                .fill(.blue)
                // Dimensions change based on state
                .frame(
                    width: isExpanded ? 300 : 150,
                    height: isExpanded ? 200 : 100
                )

            Button(isExpanded ? "Collapse" : "Expand") {
                // withAnimation animates ALL visual changes
                // resulting from this state change
                withAnimation(.spring(response: 0.5, dampingFraction: 0.7)) {
                    isExpanded.toggle()
                }
            }
            .padding(.top)
        }
    }
}

Butona dokunuldugunda isExpanded degeri degisir. withAnimation sayesinde dikdortgenin boyut degisikligi yay efektiyle animasyonlandirilir. Neyin animasyonlandirilacagini belirtmek gerekmez -- SwiftUI bunu kendisi belirler.

Gecisler: Gorunme ve Kaybolmayi Animasyonlandirma

Gecisler (transition) bir view'in nasil gorunecegini veya kaybolacagini belirler. Varsayilan olarak fade (opacity) uygulanir, ancak ozellestirilebilir:

TransitionDemo.swiftswift
struct TransitionDemo: View {
    @State private var showDetails = false

    var body: some View {
        VStack(spacing: 20) {
            Button("Show Details") {
                withAnimation(.easeInOut(duration: 0.3)) {
                    showDetails.toggle()
                }
            }

            // This view appears/disappears with a transition
            if showDetails {
                DetailCard()
                    // Asymmetric transition: different for entry and exit
                    .transition(
                        .asymmetric(
                            insertion: .scale.combined(with: .opacity),  // Entry: zoom + fade
                            removal: .slide                               // Exit: slide
                        )
                    )
            }
        }
    }
}

struct DetailCard: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Interview Details")
                .font(.headline)
            Text("25 questions • 45 minutes")
                .foregroundColor(.secondary)
        }
        .padding()
        .background(Color(.systemGray6))
        .cornerRadius(16)
    }
}

Bu ornekte kart merkezden buyuyerek (scale + opacity) gorunur ve yana kayarak (slide) kaybolur. Bu mikro-animasyonlar arayuze canli ve profesyonel bir hava katar.

Performance

SwiftUI animasyonlari otomatik olarak optimize eder. Dogal bir his icin .spring() tercih edilmeli ve kullanicilari rahatsiz edecek asiri uzun animasyonlardan (> 0.5s) kacinilmalidir.

Asenkron Veri Yukleme

Gercek uygulamalarda veriler genellikle bir API'den gelir. Swift Concurrency (async/await), .task modifier'i araciligiyla SwiftUI ile kusursuz bir sekilde entegre olur.

Loading / Error / Success Kalıbi

Asagida API verileri icin standart goruntulenme kalıbi yer almaktadir. Uc durum ele alinir: yukleme, hata ve basari.

AsyncDataView.swiftswift
struct AsyncDataView: View {
    @State private var questions: [Question] = []
    @State private var isLoading = true
    @State private var errorMessage: String?

    var body: some View {
        Group {
            if isLoading {
                // State: loading in progress
                ProgressView("Loading...")

            } else if let error = errorMessage {
                // State: error
                VStack(spacing: 16) {
                    Image(systemName: "exclamationmark.triangle")
                        .font(.largeTitle)
                        .foregroundColor(.orange)
                    Text(error)
                    Button("Retry") {
                        Task { await loadQuestions() }
                    }
                }

            } else {
                // State: success, display data
                List(questions) { question in
                    Text(question.title)
                }
            }
        }
        // .task runs automatically when the view appears
        .task {
            await loadQuestions()
        }
        // Pull-to-refresh
        .refreshable {
            await loadQuestions()
        }
    }

    private func loadQuestions() async {
        isLoading = true
        errorMessage = nil

        do {
            // Async API call
            questions = try await QuestionService.shared.fetchQuestions()
        } catch {
            errorMessage = "Unable to load questions"
        }

        isLoading = false
    }
}

.task modifier'i hayati onem tasir: view gorundugundu asenkron bir gorev baslatir ve view kayboldugundu otomatik olarak iptal eder. Bellek sizintisi riski ortadan kalkar.

Sonuc

SwiftUI, modern iOS gelistirme icin vazgecilmez hale gelmistir. iOS 18 ile framework, uretim uygulamalari icin mukemmel uygunluk saglayan bir olgunluga ulasmistir.

Temel Cikarimlar

  • Deklaratif paradigma: ne istendigini tarif etmek, nasil insa edilecegini degil
  • @State ve @Binding: durumu reaktif olarak yonetmek ve view'ler arasinda yaymak
  • Stack'ler: esnek duzenler icin VStack, HStack ve ZStack'i birlestirmek
  • List: minimum kodla koleksiyonlari goruntulemek ve yerel etkileşimler saglamak
  • Animasyonlar: otomatik akici gecisler icin withAnimation kullanmak
  • Async/await: .task ile veri yuklemek ve yukleme/hata durumlarini yonetmek

Checklist

  • Imperatif (UIKit) ve deklaratif (SwiftUI) arasindaki farki kavramak
  • Modifier'lari ve uygulama siralarini kavramak
  • @State, @Binding ve @Observable'in ne zaman kullanilacagini bilmek
  • Stack'lerle duzen olusturmak
  • Eylemlerle (silme, tasima) liste uygulamak
  • withAnimation ile durum degisikliklerini animasyonlandirmak

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

SwiftUI, tum Apple ekosistemi genelinde zarif uygulamalar olusturmanin kapilarini acar. Ogrenmenin en iyi yolu pratik yapmaktir: kucuk bir kisisel proje olusturmak ve bu makaledeki her kavramla deney yapmak tavsiye edilir.

Etiketler

#swiftui
#ios
#swift
#ui
#apple

Paylaş

İlgili makaleler