SwiftUI: การสร้างอินเทอร์เฟซที่ทันสมัยสำหรับ iOS

คู่มือการสร้างอินเทอร์เฟซที่ทันสมัยด้วย SwiftUI: ไวยากรณ์แบบ declarative, คอมโพเนนต์, แอนิเมชัน และแนวปฏิบัติที่ดีที่สุดสำหรับ iOS 18

คู่มือ SwiftUI สำหรับการสร้างอินเทอร์เฟซ iOS ที่ทันสมัย

SwiftUI ได้เปลี่ยนแปลงวิธีการพัฒนาอินเทอร์เฟซบนแพลตฟอร์ม Apple อย่างสิ้นเชิง ด้วยไวยากรณ์แบบ declarative และการผสานกับระบบ native เฟรมเวิร์กนี้ช่วยให้สร้างแอปพลิเคชันที่สวยงามด้วยโค้ดที่น้อยกว่าที่เคย iOS 18 นำเสนอการปรับปรุงประสิทธิภาพที่สำคัญพร้อมความสามารถใหม่หลายประการ

Why SwiftUI in 2026?

SwiftUI มีความสมบูรณ์แล้วใน iOS 18 โดยมีการ render ที่ถูกปรับให้เหมาะสม การจัดการหน่วยความจำที่ดีขึ้น และการผสาน UIKit ที่ง่ายขึ้น ถือเป็นมาตรฐานสำหรับแอปพลิเคชัน iOS ใหม่

ทำความเข้าใจรูปแบบ Declarative

ก่อนเริ่มเขียนโค้ด ควรทำความเข้าใจว่า SwiftUI แตกต่างจากเฟรมเวิร์กเดิมอย่างไร ใน UIKit (เฟรมเวิร์กรุ่นก่อน) นักพัฒนาต้องบอก iOS วิธีการสร้างอินเทอร์เฟซทีละขั้นตอน เช่น "สร้าง label วางไว้ตรงนี้ เปลี่ยนสีเมื่อผู้ใช้กดปุ่ม" นี่คือรูปแบบ imperative

SwiftUI ทำงานแตกต่างออกไป นักพัฒนาจะอธิบายสิ่งที่ต้องการแสดงผล แล้วเฟรมเวิร์กจะจัดการส่วนที่เหลือเอง ความแตกต่างนี้เปรียบได้กับการนำทาง GPS: รูปแบบ imperative ให้คำแนะนำเลี้ยวทีละจุด ส่วนรูปแบบ declarative เพียงระบุจุดหมายปลายทาง

View แรก

ใน SwiftUI ทุกองค์ประกอบของอินเทอร์เฟซคือ View โดย View เป็น struct ที่อธิบายสิ่งที่ควรแสดงบนหน้าจอ ต่อไปนี้คือหน้าจอแรกที่มีหัวข้อ หัวข้อย่อย และปุ่ม:

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
    }
}

สังเกตโครงสร้าง: เริ่มด้วยการประกาศสิ่งที่ต้องการ (ข้อความ ปุ่ม) จากนั้นจัดเรียงองค์ประกอบในแนวตั้ง (VStack) และใช้สไตล์ผ่าน modifier (.font(), .padding())

ประเด็นสำคัญ: ใน SwiftUI ไม่มีการ "สร้าง" วัตถุ UI ด้วยตนเอง แต่จะอธิบายอินเทอร์เฟซที่ต้องการ SwiftUI จะจัดการการสร้าง อัปเดต และทำลายองค์ประกอบจริงเอง

Modifier: การแปลง View

Modifier คือเมธอดที่เรียกต่อกันเป็นลูกโซ่หลัง view เพื่อแปลงรูปแบบ สามารถเปรียบได้กับฟิลเตอร์ที่ใส่ทับซ้อนกันทีละชั้น ลำดับมีความสำคัญเพราะ modifier แต่ละตัวจะสร้าง view ใหม่ที่ครอบ view เดิม

ตัวอย่างที่แสดงให้เห็นว่าลำดับสำคัญอย่างไร:

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

ความแตกต่างคือ: ในกรณีแรก padding อยู่ "ภายใน" background ส่วนกรณีที่สอง padding อยู่ "ภายนอก" รายละเอียดเล็กน้อยแต่สำคัญมากสำหรับการจัดวางเลย์เอาต์

การจัดระเบียบอินเทอร์เฟซด้วย Stacks

SwiftUI มี container หลักสามแบบสำหรับจัดระเบียบ view ลองนึกภาพว่าเป็นกล่องที่จัดเรียงเนื้อหาในรูปแบบที่แตกต่างกัน

VStack, HStack และ ZStack

  • VStack (Vertical Stack): จัดเรียงองค์ประกอบจากบนลงล่าง
  • HStack (Horizontal Stack): จัดเรียงองค์ประกอบจากซ้ายไปขวา
  • ZStack (Z-axis Stack): วางองค์ประกอบซ้อนทับกัน

มาสร้างการ์ดโปรไฟล์ผู้ใช้ที่รวม stack ทั้งสามแบบ เป้าหมายคือแสดงรูปภาพพร้อมตรายืนยันตัวตน ชื่อ และตำแหน่งของผู้ใช้:

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)
    }
}

เทคนิคสำคัญคือ Spacer() ซึ่งเป็นองค์ประกอบที่มองไม่เห็นแต่กินพื้นที่ว่างทั้งหมด หากไม่มี Spacer องค์ประกอบจะอยู่ตรงกลาง แต่เมื่อมี Spacer เนื้อหาจะถูกดันไปทางซ้ายและ chevron จะอยู่ทางขวา

Xcode Tip

ใช้ ⌘ + click บน view ใดก็ได้ใน Xcode เพื่อเปิด visual inspector สามารถเพิ่ม modifier ได้โดยไม่ต้องพิมพ์โค้ดเอง

การจัดการ State ด้วย @State และ @Binding

การจัดการ state เป็นหัวใจสำคัญของ SwiftUI โดย state คือข้อมูลใดก็ตามที่สามารถเปลี่ยนแปลงได้และต้องอัปเดตอินเทอร์เฟซ เมื่อ state เปลี่ยน SwiftUI จะคำนวณ view ที่ได้รับผลกระทบใหม่โดยอัตโนมัติ

@State: State ภายในของ View

@State คือ property wrapper ที่บอก SwiftUI ว่า "เฝ้าดูตัวแปรนี้ และรีเฟรช view เมื่อค่าเปลี่ยน" เหมาะสำหรับ state ภายในของ view เดียว

มาสร้างตัวนับแบบโต้ตอบเพื่อทำความเข้าใจกลไก:

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)
                }
            }
        }
    }
}

เมื่อกดปุ่ม ค่า count จะเปลี่ยน SwiftUI ตรวจจับการเปลี่ยนแปลงนี้และเรียก body ใหม่เพื่ออัปเดตการแสดงผล ไม่จำเป็นต้องอัปเดต label ด้วยตนเอง ทุกอย่างเป็นอัตโนมัติ

@Binding: การแชร์ State ระหว่าง View

บางครั้ง view ลูกจำเป็นต้องแก้ไข state ของ view แม่ นี่คือจุดที่ @Binding เข้ามา โดยสร้างการเชื่อมต่อแบบสองทางกับ @State ที่มีอยู่

ตัวอย่างที่เป็นรูปธรรม: ช่องกรอกชื่อผู้ใช้พร้อมการตรวจสอบแบบเรียลไทม์

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()
    }
}

View ลูกรับ binding และสามารถแก้ไขค่าได้:

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)
        }
    }
}

เมื่อผู้ใช้พิมพ์ใน TextField ค่า username จะถูกแก้ไขผ่าน binding View แม่เห็นการเปลี่ยนแปลงนี้และสามารถนำไปใช้ได้ นี่คือการสื่อสารแบบสองทางที่ชัดเจน

Warning

ควรใช้ @State สำหรับ state ที่เรียบง่ายและอยู่ภายในเท่านั้น สำหรับข้อมูลที่แชร์ระหว่างหลายหน้าจอหรือลอจิกที่ซับซ้อน แนะนำให้ใช้ @Observable (iOS 17+) หรือรูปแบบ MVVM

พร้อมที่จะพิชิตการสัมภาษณ์ iOS แล้วหรือยังครับ?

ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ

การแสดงรายการแบบไดนามิก

รายการปรากฏอยู่ทุกที่ในแอปพลิเคชันมือถือ SwiftUI มี List สำหรับแสดงคอลเลกชันข้อมูลพร้อมสไตล์ native ของ iOS (เส้นแบ่ง การดำเนินการเมื่อปัด เป็นต้น)

การสร้างรายการแบบง่าย

การแสดงรายการต้องมีสองสิ่ง: ข้อมูลและวิธีระบุตัวตน โปรโตคอล Identifiable ช่วยให้ SwiftUI ทราบว่า view ใดสอดคล้องกับข้อมูลใด

เริ่มจากการกำหนดโมเดลข้อมูล:

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
}

จากนั้นสร้างรายการ แนวคิดคือวนซ้ำข้อมูลด้วย ForEach และสร้างแถวสำหรับแต่ละรายการ:

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")
        }
    }
}

และนี่คือ view สำหรับแต่ละแถว ซึ่งแยกออกมาเป็นคอมโพเนนต์ต่างหากเพื่อความอ่านง่าย:

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 ออกเป็น struct ต่างหากทำให้โค้ดอ่านง่ายขึ้นและนำกลับมาใช้ซ้ำได้ ถือเป็นแนวปฏิบัติที่ดีของ SwiftUI

การเพิ่มการดำเนินการ: ลบและจัดเรียงใหม่

รายการใน iOS รองรับการลบ (ปัดซ้าย) และการจัดเรียงใหม่ (ลากและวาง) โดย native SwiftUI ทำให้สิ่งนี้ง่ายมากด้วย .onDelete และ .onMove:

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)
    }
}

เพียง 4 บรรทัดโค้ดเพิ่มเติม (.onDelete, .onMove, EditButton และสองฟังก์ชัน) ก็ทำให้รายการโต้ตอบได้อย่างเต็มรูปแบบ นี่คือพลังของ SwiftUI

การสร้างแอนิเมชัน

SwiftUI มีความเชี่ยวชาญด้านแอนิเมชัน ต่างจาก UIKit ที่ต้องเขียนโค้ดจำนวนมากสำหรับแอนิเมชัน ในที่นี้ทุกอย่างเป็นแบบ declarative: อธิบาย state สุดท้ายแล้ว SwiftUI จะสร้างแอนิเมชันการเปลี่ยนผ่านให้

แอนิเมชันโดยนัยด้วย withAnimation

วิธีที่ง่ายที่สุดในการสร้างแอนิเมชันคือครอบการเปลี่ยนแปลง state ด้วย withAnimation โดย SwiftUI จะตรวจจับสิ่งที่เปลี่ยนแปลงและสร้างแอนิเมชันให้คุณสมบัติที่ได้รับผลกระทบโดยอัตโนมัติ

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)
        }
    }
}

เมื่อกดปุ่ม isExpanded จะสลับค่า ด้วย withAnimation การเปลี่ยนแปลงขนาดของสี่เหลี่ยมจะถูกสร้างแอนิเมชันด้วยเอฟเฟกต์สปริง ไม่จำเป็นต้องระบุว่าจะสร้างแอนิเมชันอะไร SwiftUI จะจัดการให้เอง

Transition: แอนิเมชันการปรากฏและหายไป

Transition กำหนดวิธีที่ view ปรากฏหรือหายไป โดยค่าเริ่มต้นจะเป็นการจางหาย (opacity) แต่สามารถปรับแต่งได้:

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)
    }
}

การ์ดปรากฏด้วยเอฟเฟกต์ซูมจากตรงกลาง (scale + opacity) และหายไปด้วยการเลื่อนไปด้านข้าง (slide) แอนิเมชันเล็กเหล่านี้ทำให้อินเทอร์เฟซดูมีชีวิตชีวาและเป็นมืออาชีพ

Performance

SwiftUI ปรับแต่งแอนิเมชันโดยอัตโนมัติ แนะนำให้ใช้ .spring() เพื่อให้ได้ความรู้สึกที่เป็นธรรมชาติ และหลีกเลี่ยงแอนิเมชันที่ยาวเกินไป (> 0.5 วินาที) ซึ่งอาจสร้างความรำคาญให้ผู้ใช้

การโหลดข้อมูลแบบ Asynchronous

ในแอปพลิเคชันจริง ข้อมูลมักมาจาก API และ Swift Concurrency (async/await) ผสานกับ SwiftUI ได้อย่างสมบูรณ์ผ่าน modifier .task

รูปแบบ Loading / Error / Success

นี่คือรูปแบบมาตรฐานสำหรับแสดงข้อมูลจาก API โดยจัดการสาม state: กำลังโหลด เกิดข้อผิดพลาด และสำเร็จ

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
    }
}

Modifier .task มีความสำคัญอย่างยิ่ง: เริ่มทำงาน async เมื่อ view ปรากฏ และยกเลิกโดยอัตโนมัติเมื่อ view หายไป ปัญหา memory leak จึงเป็นไปไม่ได้

บทสรุป

SwiftUI กลายเป็นส่วนที่ขาดไม่ได้ของการพัฒนา iOS สมัยใหม่ ด้วย iOS 18 เฟรมเวิร์กนี้มีความสมบูรณ์เพียงพอสำหรับแอปพลิเคชัน production

ประเด็นสำคัญ

  • รูปแบบ Declarative: อธิบายผลลัพธ์ที่ต้องการ ไม่ใช่วิธีการสร้าง
  • @State และ @Binding: จัดการ state แบบ reactive และส่งต่อระหว่าง view
  • Stacks: ผสมผสาน VStack, HStack และ ZStack สำหรับเลย์เอาต์ที่ยืดหยุ่น
  • List: แสดงคอลเลกชันด้วยโค้ดน้อยที่สุดพร้อมการโต้ตอบแบบ native
  • แอนิเมชัน: ใช้ withAnimation สำหรับการเปลี่ยนผ่านที่ราบรื่นแบบอัตโนมัติ
  • Async/await: โหลดข้อมูลด้วย .task และจัดการ state ของ loading/error

รายการตรวจสอบ

  • เข้าใจความแตกต่างระหว่าง imperative (UIKit) และ declarative (SwiftUI)
  • เชี่ยวชาญ modifier และลำดับการใช้งาน
  • รู้ว่าเมื่อไหร่ควรใช้ @State, @Binding หรือ @Observable
  • สร้างเลย์เอาต์ด้วย Stacks
  • สร้างรายการพร้อมการดำเนินการ (ลบ ย้าย)
  • สร้างแอนิเมชันการเปลี่ยนแปลง state ด้วย withAnimation

เริ่มฝึกซ้อมเลย!

ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ

SwiftUI เปิดประตูสู่การสร้างแอปพลิเคชันที่สวยงามทั่วทั้งระบบนิเวศ Apple วิธีที่ดีที่สุดในการเรียนรู้คือการลงมือปฏิบัติ: สร้างโปรเจกต์ส่วนตัวเล็กๆ แล้วทดลองกับแต่ละแนวคิดจากบทความนี้

แท็ก

#swiftui
#ios
#swift
#ui
#apple

แชร์

บทความที่เกี่ยวข้อง

การปรับแต่งประสิทธิภาพ SwiftUI LazyVStack และรายการที่ซับซ้อน

ประสิทธิภาพ SwiftUI: การปรับแต่ง LazyVStack และรายการที่ซับซ้อน

เทคนิคการปรับแต่งสำหรับ LazyVStack และรายการ SwiftUI ลดการใช้หน่วยความจำ ปรับปรุงประสิทธิภาพการเลื่อน และหลีกเลี่ยงข้อผิดพลาดที่พบบ่อย

ViewModifier ของ SwiftUI สำหรับสร้าง design system ที่นำกลับมาใช้ใหม่ได้ใน iOS

ViewModifier แบบกำหนดเองใน SwiftUI: รูปแบบที่นำกลับมาใช้ใหม่ได้สำหรับ Design System

สร้าง ViewModifier แบบกำหนดเองใน SwiftUI สำหรับ design system ที่สอดคล้องกัน รูปแบบ แนวทางปฏิบัติที่ดีที่สุด และตัวอย่างที่ใช้งานได้จริงสำหรับการจัดสไตล์ view ของ iOS อย่างมีประสิทธิภาพ

การเปรียบเทียบ @Observable และ @State ใน SwiftUI สำหรับนักพัฒนา iOS

SwiftUI @Observable vs @State: ใช้ตัวไหนเมื่อไหร่ในปี 2026

เข้าใจความแตกต่างระหว่าง @Observable และ @State ใน SwiftUI เพื่อเลือกเครื่องมือจัดการ state ที่เหมาะกับแอป iOS