Hello, SwiftUI !

การใช้ Xcode เพื่อสร้างส่วนติดต่อผู้ใช้ (UI) แบบ Declarative ด้วย SwiftUI

การพัฒนาแอปพลิเคชันบนอุปกรณ์ของ Apple ไม่ว่าจะเป็น iPhone, iPad หรือ Mac ให้ทำงานได้เต็มประสิทธิภาพและเชื่อมต่อกับบริการต่างๆ ภายในระบบนิเวศของ Apple อย่างราบรื่นนั้น จำเป็นต้องอาศัยการเขียนโปรแกรมด้วยภาษา Swift ซึ่งเป็นภาษาหลักที่ออกแบบขึ้นโดยเฉพาะสำหรับแพลตฟอร์มของ Apple โดยให้ความสำคัญกับความปลอดภัย ความรวดเร็ว และการจัดการหน่วยความจำอย่างมีประสิทธิภาพ

Xcode เป็น Integrated Development Environment (IDE) หลักของ Apple ซึ่งทำหน้าที่เป็น Code Editor ที่มีความสามารถในการแสดงผลแบบ Live Preview ทำให้ผู้พัฒนาสามารถทดลอง แก้ไข และตรวจสอบผลลัพธ์ในการเขียนโค้ดได้ทันทีโดยไม่ต้องรันแอปทุกครั้ง

SwiftUI คือ เฟรมเวิร์กสำหรับสร้างส่วนติดต่อผู้กับใช้ (User Interface: UI) ที่ทันสมัยและมีประสิทธิภาพ โดยใช้ภาษา Swift ในรูปแบบที่เรียกว่า Declarative ซึ่งช่วยให้นักพัฒนาเขียนโค้ดเพื่อสร้าง UI ได้ง่ายและรวดเร็วขึ้นกว่าเดิม

ความยุ่งยากในการสร้างส่วนติดต่อกับผู้ใช้ (UI) ด้วย UIKit

การใช้ UIKit เพื่อสร้างส่วนติดต่อผู้ใช้เป็นแนวทางแบบ Imperative ซึ่งเน้นการระบุ ตรรกะการสั่งงานแบบกำหนดลำดับขั้นตอน (step-by-step instructions) อย่างละเอียด (How to do) นักพัฒนาจึงต้องออกแบบและควบคุมทุกกระบวนการด้วยตนเอง ตั้งแต่การสร้างวัตถุ UI (instantiate UIView objects) การกำหนดตำแหน่งและรูปแบบการจัดวางด้วย Auto Layout หรือ Constraints การกำหนดการตอบสนองของ UI ผ่านกลไก Event Handling หรือ Target–Action ไปจนถึงการอัปเดต UI ซึ่งต้องเขียนคำสั่งเพื่อปรับปรุงหน้าจอด้วยตนเองทุกครั้ง (manual UI updates) ลักษณะการพัฒนาในรูปแบบนี้ มักทำให้โค้ดมีความยาว ซับซ้อน และมีโอกาสเกิดความผิดพลาดได้ง่าย โดยเฉพาะในงานที่ต้องมีการจัดการกับ UI จำนวนมาก หรือเมื่อ UI มีสถานะที่เปลี่ยนแปลงบ่อยๆ

ตัวอย่างการสร้าง UI แบบ Imperative

import UIKit

class CounterViewController: UIViewController {
    
    private var count = 0
    
    // การสร้าง UI ด้วย UILabel เพื่อใช้ในการแสดงข้อความ Count: 0
    private let countLabel: UILabel = {
        let label = UILabel()
        label.text = "Count: 0"
        label.font = UIFont.systemFont(ofSize: 32, weight: .bold)
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    // ปุ่ม Increase
    private let increaseButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Increase", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 20)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        
        //เพิ่ม subviews 
        view.addSubview(countLabel)
        view.addSubview(increaseButton)
        
        //จัดการ Auto Layout
        NSLayoutConstraint.activate([
            countLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            countLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -40),
            
            increaseButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            increaseButton.topAnchor.constraint(equalTo: countLabel.bottomAnchor, constant: 20)
        ])
        
        //กำหนด event ให้ปุ่ม
        increaseButton.addTarget(self, action: #selector(increaseTapped), for: .touchUpInside)
    }
    
    @objc private func increaseTapped() {
        //ปรับค่าตัวแปร state
        count += 1
        
        //อัปเดต UI ด้วยตนเอง (Imperative)
        countLabel.text = "Count: \(count)"
    }
}

แม้ว่านักพัฒนาจะใช้ Interface Builder ใน Xcode เพื่อช่วยลดความซับซ้อนในขั้นตอนของการออกแบบและจัดวางส่วนติดต่อผู้ใช้ (UI Layout) ผ่านการลาก-วาง (Drag and Drop) แทนการเขียนโค้ดสร้างองค์ประกอบ UI ทั้งหมดด้วยตนเอง และใช้ @IBOutlet ในการเชื่อมโยง UI เข้ากับโค้ดใน Controller รวมทั้งใช้ @IBAction ในการกำหนดการตอบสนองของ UI ต่อเหตุการณ์ต่างๆ (เช่นการกดปุ่ม) ได้ง่ายขึ้น แต่ก็ยังไม่สามารถลดภาระสำคัญของ UIKit ได้ โดยเฉพาะในส่วนที่เกี่ยวข้องกับตรรกะการสั่งงานแบบเป็นขั้นตอน (logic imperative) เช่น การกำหนดลำดับการทำงานของ UI, การจัดการเหตุการณ์ (Event Handling) และการอัปเดตสถานะของ UI เมื่อข้อมูลมีการเปลี่ยนแปลง ซึ่งทั้งหมดยังคงเป็นหน้าที่ซึ่งนักพัฒนาต้องเขียนคำสั่งเพื่อควบคุมด้วยตนเองอย่างละเอียด

ตัวอย่างการใช้ Interface Builder และ @IBOutlet/@IBAction

import UIKit

class CounterViewController: UIViewController {
    
    private var count = 0

    // MARK: - IBOutlet Properties
    @IBOutlet weak var countLabel: UILabel!
    
    // MARK: - IBAction
    @IBAction func increaseTapped(_ sender: UIButton) {
        count += 1
        updateUI()
    }
    
    // MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()       
        view.backgroundColor = .systemBackground        
        updateUI()
    }
    
    // MARK: - Helper Methods
    private func updateUI() {
        countLabel.text = "Count: \(count)"
    }
}

การสร้างส่วนติดต่อกับผู้ใช้ (UI) แบบ Declarative

สำหรับ SwiftUI ซึ่งเป็นการสร้างส่วนติดต่อกับผู้ใช้แบบ Declarative นักพัฒนาจะมุ่งไปที่การอธิบายว่า “ต้องการให้ UI มีลักษณะอย่างไร” (What to show) มากกว่าการกำหนดขั้นตอนอย่างละเอียดว่า “ต้องจัดวางหรืออัปเดต UI อย่างไร” (How to do)

โดยนักพัฒนาสามารถระบุถึงโครงสร้างและลักษณะของ UI ที่ต้องการ และทำการผูกโยงกับสถานะของข้อมูล (State) ผ่านกลไกต่างๆ เช่น @State, @Binding หรือ @ObservedObject แล้วปล่อยให้ระบบเป็นผู้จัดการเพื่อเรนเดอร์การจัดวาง (Layout) และอัปเดต UI ให้สอดคล้องกับสถานะของข้อมูลโดยอัตโนมัติ ดังนั้น เมื่อ สถานะ (State) ของข้อมูล มีการเปลี่ยนแปลง ระบบก็จะทำการคำนวณและอัปเดต UI ที่เกี่ยวข้องให้ทันที โดยที่นักพัฒนาไม่จำเป็นต้องเขียนโค้ดเพื่ออัปเดต UI ด้วยตนเอง ส่งผลให้โค้ดที่ได้มีความกระชับ อ่านง่าย ลดความซับซ้อนเชิงลอจิก และลดโอกาสการเกิดข้อผิดพลาดจากการจัดการสถานะของ UI ได้อย่างมีนัยสำคัญ

ตัวอย่างการสร้าง UI แบบ Declarative

import SwiftUI

struct CounterView: View {
    @State private var count = 0
    
    var body: some View {
        VStack {
            Text("Count: \(count)")
                .font(.largeTitle)
            
            Button("Increase") {
                count += 1
            }
        }
        .padding()
    }
}

นักพัฒนายังสามารถกำหนดให้ Xcode แสดงผลแบบ Live Preview ผ่าน Canvas ได้แบบทันทีด้วยคำสั่ง ดังต่อไปนี้

#Preview("iPhone 17 Pro (Dark)") {
    CounterView()
        .preferredColorScheme(.dark)
}

แนวคิด Iterative UI Design กับการใช้ SwiftUI

การพัฒนาอินเทอร์เฟซผู้ใช้ (User Interface: UI) ในยุคปัจจุบันไม่ได้เป็นเพียงการจัดวางองค์ประกอบบนหน้าจอให้ใช้งานได้เท่านั้น แต่เป็นการออกแบบประสบการณ์ (User Experience: UX) ให้ผู้ใช้เกิดความรู้สึกที่ดีและมีปฏิสัมพันธ์อย่างราบรื่นในการใช้งาน การพัฒนา UI ที่ตอบสนองต่อความต้องการของผู้ใช้จึงต้องอาศัยกระบวนการที่สามารถทดลอง ปรับปรุง และเรียนรู้จากผลลัพธ์ได้อย่างต่อเนื่อง แนวคิดนี้เรียกว่า Iterative UI Design หรือการออกแบบ UI แบบวนซ้ำ

การออกแบบ UI แบบ Iterative เป็นกระบวนการที่สอดคล้องกับ หลักการการออกแบบซอฟต์แวร์แบบ Iterative & Incremental ที่จะแบ่งงานออกเป็นรอบ (iteration) แต่ละรอบประกอบด้วย การออกแบบ (Design) การสร้าง/พัฒนา (Build) การทดสอบและรับข้อเสนอแนะ (Test) และการนำผลการทดสอบมาปรับปรุงและพัฒนาใหม่ (Refine)

SwiftUI และ Xcode เป็นเครื่องมือที่สนับสนุนแนวคิดนี้อย่างสมบูรณ์ โดยใช้โครงสร้างแบบ Declarative ที่แยกส่วนของการออกแบบออกมาจากกระบวนการจัดการลำดับขั้นตอนภายในของ UI และการใช้ Live Preview เพื่อลดรอบการทดสอบเป็นผลให้ผู้พัฒนาสามารถสร้าง UI ที่มีคุณภาพสูงได้อย่างรวดเร็วและมีประสิทธิภาพ

ตัวอย่างในการออกแบบหน้าจอ “Welcome Screen” ของแอปด้วยแนวคิด Iterative UI Design

Iteration 1 – วางแก่นของ UI (Structure)

เป้าหมายหลัก: วาง “แก่นของเนื้อหา” (Core Content) ที่ต้องการให้ผู้ใช้เห็นทันทีเมื่อเปิดแอป สร้าง View หลัก เช่น Text, VStack (ยังไม่เน้น layout หรือความสวยงาม) ทำให้เห็นโครงสร้าง UI ที่เป็นภาพรวมก่อนปรับแต่ง และรับรองว่า SwiftUI Code รันได้ถูกต้อง ไม่มี error

Text("Welcome")
Text("Start your journey with our app.")

Iteration 2 – ปรับปรุงด้านการมองเห็น (Visual Enhancement)

เป้าหมายหลัก: ทำให้องค์ประกอบ UI มองเห็นง่ายขึ้น โดยกำหนดรูปแบบของฟอนต์ ขนาด สี ตำแหน่ง รวมทั้งสร้างโครงสร้างหน้าจอที่มีลำดับความสำคัญของข้อมูล (hierarchy) อย่างชัดเจน และตรวจสอบความสวยงามด้วย Xcode Preview

VStack(spacing: 20) {
    Text("Welcome")
        .font(.largeTitle)
        .bold()                     // ทำให้หัวเรื่องเด่นขึ้น
            
    Text("Start your journey with our app.")
        .font(.subheadline)
        .foregroundStyle(.secondary) // ข้อความรองให้สีอ่อนลง 
        .multilineTextAlignment(.center)
        .padding(.horizontal, 32)   
 }
 .padding()

Iteration 3 – ทำให้ UI ตอบสนองได้จริง (Interactivity)

เป้าหมาย: เพิ่มองค์ประกอบที่ผู้ใช้ “โต้ตอบ” ได้ เช่น ปุ่ม “Get Started” หรือ “Continue” เพื่อเชื่อมไปยังหน้าถัดไป หรือการทำให้เกิด action บางอย่าง

struct ContentView: View {
    
@State private var showMessage = false

var body: some View {
    VStack(spacing: 20) {
        Text("Welcome")
            .font(.largeTitle)
            .bold()
        
        Text("Start your journey with our app.")
            .font(.subheadline)
            .foregroundStyle(.secondary)
            .multilineTextAlignment(.center)
            .padding(.horizontal, 32)
        
        Button {
            showMessage = true      // เปลี่ยน state เมื่อกดปุ่ม
        } label: {
            Text("Get Started")
                .padding(.vertical, 12)
                .padding(.horizontal, 40)
                .background(.blue)
                .foregroundStyle(.white)
                .cornerRadius(22)
        }
        .buttonStyle(.plain)
    }
    .padding()
    .alert("You tapped Get Started", isPresented: $showMessage) {
        Button("OK", role: .cancel) { }
    }
}

Iteration 4 ทดสอบการใช้งาน (Usability Testing)

เป้าหมาย: ตรวจสอบว่า UI ใช้งานได้ดีใน “สภาพจริง” เช่น บนอุปกรณ์หลายขนาด, โหมดมืด, ขนาดตัวอักษรใหญ่ขึ้น, การแตะปุ่มสะดวกหรือไม่

ในรอบนี้ส่วนใหญ่จะเป็น “การทดสอบ” และ “สังเกต” ใน Xcode / Simulator มากกว่าการเขียนโค้ดเพิ่ม แต่เราสามารถเสริม Preview ให้รองรับหลายสถานการณ์ เช่น

#Preview("iPhone 17 Pro (Dark)") {
    ContentView()
        .preferredColorScheme(.dark)
}

Iteration 5 ปรับแต่งเพื่อความสมบูรณ์ (Refinement)

เป้าหมาย: ปรับจูนรายละเอียด (fine-tuning) ทั้งด้านการจัดวาง (layout), ความสวยงาม (visual) และการใช้งานได้ (usability) จากผลการทดสอบใน Iteration 5 เพื่อให้ส่วนต่างๆของหน้าจอพร้อมใช้งานได้จริง

import SwiftUI

struct ContentView: View {
    
    @State private var showMessage = false
    
    var body: some View {
        ZStack {
            // พื้นหลังแบบ gradient ดูมีมิติขึ้น
            LinearGradient(
                colors: [.blue.opacity(0.8), .purple.opacity(0.8)],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
            .ignoresSafeArea()
            
            VStack(spacing: 24) {
                Spacer()
                
                VStack(spacing: 20) {
                    Text("Welcome")
                        .font(.largeTitle)
                        .fontWeight(.bold)
                        .foregroundStyle(.white)
                        .multilineTextAlignment(.center)
                        .accessibilityAddTraits(.isHeader)
                    
                    Text("Start your journey with our app.\nLet’s build something great together.")
                        .font(.body)
                        .foregroundStyle(.white.opacity(0.9))
                        .multilineTextAlignment(.center)
                        .padding(.horizontal, 32)
                }
                
                Spacer()
                
                Button {
                    showMessage = true
                } label: {
                    Text("Get Started")
                        .font(.headline)
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 12)
                        .background(.white)
                        .foregroundStyle(.blue)
                        .cornerRadius(22)
                        .shadow(radius: 4)
                }
                .padding(.horizontal, 32)
                .padding(.bottom, 40)
                .accessibilityLabel("Get Started")
                .accessibilityHint("Double tap to begin using the app.")
            }
        }
        .alert("You tapped Get Started", isPresented: $showMessage) {
            Button("OK", role: .cancel) { }
        }
    }
}

แนวคิด Iterative UI Design มีความสัมพันธ์อย่างลึกซึ้งกับกระบวนการทางวิศวกรรมซอฟต์แวร์สมัยใหม่ เนื่องจากทั้งหมดล้วนตั้งอยู่บนหลักการเดียวกันคือ พัฒนาแบบวนซ้ำ (iteration), เรียนรู้จาก feedback, และค่อย ๆ ปรับปรุงคุณภาพของซอฟต์แวร์หรือ UI ให้ดีขึ้นอย่างต่อเนื่อง

  • Agile เน้นการพัฒนาซอฟต์แวร์เป็นรอบสั้น ๆ (sprints) ที่มีวัฏจักรของ ออกแบบ → พัฒนา → ทดสอบ → ปรับปรุง ซึ่งสอดคล้องอย่างยิ่งกับ Iterative UI Design

  • Design Thinking ประกอบด้วยขั้นตอนหลัก ได้แก่ Empathize → Define → Ideate → Prototype → Test ซึ่งมีความเป็น Iterative ในตัวอยู่แล้ว

  • Prototyping คือ การสร้างต้นแบบ (prototype) ที่สามารถทดสอบได้ก่อนสร้างระบบจริง ซึ่งตรงกับแนวทาง Iterative UI Design อย่างเป็นธรรมชาติ โดยจะเห็นได้ว่าแต่ละ Iteration เปรียบเสมือนเป็น prototype ของแอปในระดับต่างๆ

แนวทางในการจัดกิจกรรมการเรียนรู้

ดาวน์โหลดเอกสารประกอบการทำกิจกรรมในห้องปฏิบัติการ ที่นี่ ดาวน์โหลดสไลด์สำหรับใช้ประกอบการสอน ที่นี่

รายละเอียดเพื่อการอ้างอิง

ผู้เขียน ธิติ ธีระเธียร วันที่เผยแพร่ วันที่ 15 พฤศจิกายน 2568 วันที่ปรุงปรุงล่าสุด วันที่ 20 พฤศจิกายน 2568 เข้าถึงได้จาก https://ajthiti.gitbook.io/develop-in-swift/getting-started/hello-swiftui เงื่อนใขในการใช้งาน This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

Last updated