ViewModifier là một giao thức trong SwiftUI cho phép tạo các bộ sửa đổi có thể tái sử dụng để thay đổi giao diện và hành vi của View. Theo Apple Developer Documentation, 2024, ViewModifier yêu cầu triển khai phương thức body(content:), nhận View gốc và trả về View đã được sửa đổi, đóng gói bất kỳ sự kết hợp nào của các bộ sửa đổi tích hợp sẵn thành một loại duy nhất. Nếu không có giao thức này, các nhà phát triển sẽ phải lặp lại các chuỗi bộ sửa đổi giống nhau ở mọi điểm sử dụng.
Điểm chính
ViewModifier là một giao thức SwiftUI xác định hợp đồng để tạo các bộ sửa đổi có thể áp dụng cho bất kỳ loại View nào. Nó được khai báo là protocol ViewModifier { associatedtype Body: View; func body(content: Content) -> Body }, trong đó Content là loại của View gốc được truyền vào bộ sửa đổi.
Giao thức ViewModifier xuất hiện trong iOS 13 cùng với phiên bản đầu tiên của SwiftUI và vẫn ổn định cho đến iOS 18+. Mục tiêu chính là cung cấp cho các nhà phát triển một cơ chế để đóng gói các chuỗi bộ sửa đổi lặp lại thành một loại có thể tái sử dụng duy nhất. Nếu không có ViewModifier, mỗi khi bạn cần áp dụng cùng một tập kiểu, bạn sẽ phải lặp lại tất cả các bộ sửa đổi một cách thủ công.
Theo Swift by Sundell (2023), ViewModifier là cách ưa tiên để tổ chức các kiểu trong các dự án SwiftUI khi cùng một tập bộ sửa đổi được sử dụng ở ba nơi trở lên. Đối với các kết hợp một lần, một chuỗi các bộ sửa đổi tích hợp sẵn trực tiếp trên View là đủ.
Giao thức ViewModifier yêu cầu triển khai một phương thức body(content:) và tùy chọn có thể cung cấp các thuộc tính để tùy chỉnh hành vi thông qua các tham số khởi tạo của bộ sửa đổi tùy chỉnh.
Giao thức ViewModifier xác định phương thức body(content:), nhận View gốc (loại Content) và trả về View đã sửa đổi (loại Body). SwiftUI áp dụng bộ sửa đổi vào View bằng cách truyền nó làm content và sử dụng kết quả để hiển thị.
struct CardStyle: ViewModifier {
func body(content: Content) -> some View {
content
.padding(16)
.background(Color.white)
.cornerRadius(12)
.shadow(radius: 4, x: 0, y: 2)
}
}
// Cách dùng:
Text("Xin chào, SwiftUI!")
.modifier(CardStyle())
Khi bạn gọi .modifier(CardStyle()), SwiftUI tạo một thể hiện của ModifiedContent<Text, CardStyle> lưu trữ View gốc và bộ sửa đổi. Trong quá trình kết xuất, SwiftUI gọi CardStyle.body(content: text), nhận được View đã sửa đổi với padding, background, cornerRadius và shadow.
Phân biệt quan trọng: ViewModifier.body được gọi mỗi khi View được cập nhật, vì vậy bên trong body không nên có các tính toán nặng hoặc tác dụng phụ. Nếu bộ sửa đổi phụ thuộc vào dữ liệu bên ngoài (state, environment), hãy truyền chúng qua các tham số khởi tạo.
Các bộ sửa đổi tích hợp sẵn của SwiftUI (font, foregroundColor, frame, padding) là các phương thức mở rộng của giao thức View trả về loại ModifiedContent. Chúng không triển khai trực tiếp ViewModifier — SwiftUI sử dụng các triển khai nội bộ được tối ưu hóa cho mỗi bộ sửa đổi tích hợp sẵn.
| Đặc điểm | Bộ sửa đổi tích hợp sẵn | ViewModifier tùy chỉnh |
|---|---|---|
| Triển khai | Phương thức mở rộng của View | Giao thức ViewModifier |
| Tái sử dụng | Chuỗi một lần | Sử dụng nhiều lần |
| Tham số | Cố định (màu, kích thước) | Bất kỳ qua bộ khởi tạo |
| Hiệu suất | Tối đa (tối ưu hóa nội bộ) | Hơi nhiều chi phí hơn |
| Loại trả về | ModifiedContent | ModifiedContent |
ViewModifier tùy chỉnh được chứng minh khi cùng một kết hợp bộ sửa đổi được sử dụng ở hai nơi trở lên. Đối với các ứng dụng một lần, một chuỗi bộ sửa đổi trực tiếp được ưa tiên hơn — mã nguồn vẫn dễ đọc và trình biên dịch tối ưu hóa tốt hơn.
Theo WWDC 2023, Apple khuyên bạn nên tạo ViewModifier tùy chỉnh cho các kiểu liên quan đến hệ thống thiết kế của ứng dụng: thẻ, nút, trường nhập liệu. Điều này đảm bảo tính nhất quán và đơn giản hóa việc bảo trì khi thiết kế thay đổi.
Mẫu 1: đóng gói hệ thống thiết kế. Trường hợp sử dụng phổ biến nhất của ViewModifier là tạo một nguồn chân lý duy nhất cho các kiểu trực quan trong một ứng dụng. Mỗi phần tử trong hệ thống thiết kế (thẻ, nút, tiêu đề) có bộ sửa đổi riêng.
struct PrimaryButton: ViewModifier {
var isEnabled: Bool
func body(content: Content) -> some View {
content
.font(.headline.weight(.semibold))
.foregroundColor(.white)
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
.background(isEnabled ? Color.blue : Color.gray)
.cornerRadius(8)
.opacity(isEnabled ? 1.0 : 0.6)
}
}
Mẫu 2: áp dụng bộ sửa đổi có điều kiện. Đôi khi bạn cần áp dụng một bộ sửa đổi chỉ trong một điều kiện nhất định. ViewModifier với tham số boolean cho phép đóng gói logic này bên trong body.
Mẫu 3: kết hợp bộ sửa đổi. Một ViewModifier có thể áp dụng ViewModifier khác bên trong body của nó. Điều này cho phép xây dựng một hệ thống phân cấp các bộ sửa đổi, nơi mỗi bộ chịu trách nhiệm cho khía cạnh riêng của trình bày trực quan. Ví dụ, CardStyle có thể áp dụng nội bộ ShadowStyle và BorderStyle.
Theo Point-Free (2024), kết hợp các bộ sửa đổi thông qua ViewModifier được ưa tiên hơn kế thừa: mỗi bộ sửa đổi chịu trách nhiệm cho một nhiệm vụ và chúng có thể được kết hợp độc lập. Điều này tuân theo nguyên tắc trách nhiệm duy nhất trong SwiftUI.
Hiệu suất của ViewModifier phụ thuộc vào số lượng trình bao bọc ModifiedContent được tạo ra với mỗi lần áp dụng. SwiftUI tối ưu hóa các chuỗi bộ sửa đổi thông qua diffing ở giai đoạn kết xuất, nhưng số lượng bộ sửa đổi quá mức có thể làm chậm các bản cập nhật.
| Số lượng bộ sửa đổi | Tác động đến hiệu suất | Khuyến nghị |
|---|---|---|
| 1–5 | Tối thiểu | Bình thường cho mọi View |
| 5–10 | Trung bình | Nhóm vào ViewModifier |
| 10–20 | Đáng kể | Kết hợp vào một bộ sửa đổi tùy chỉnh |
| 20+ | Nghiêm trọng | Xem xét lại kiến trúc View |
Tối ưu hóa: kết hợp nhiều bộ sửa đổi tuần tự cùng loại (ví dụ, nhiều padding) thành một. Chỉ sử dụng PreferenceKey khi thực sự cần thiết — các bộ sửa đổi đọc tùy chọn sẽ kích hoạt thêm một lần kết xuất.
Quy tắc chung: nếu một View có hơn 10 bộ sửa đổi — hãy trích xuất một số trong số chúng vào ViewModifier tùy chỉnh. Điều này sẽ cải thiện khả năng đọc và cho phép SwiftUI tối ưu hóa các bản cập nhật. Theo SwiftUI Lab (2024), việc nhóm các bộ sửa đổi vào ViewModifier giảm thời gian kết xuất từ 15–30% cho các View phức tạp.
Câu hỏi thường gặp
ViewModifier là một giao thức để tạo các bộ sửa đổi có thể tái sử dụng thay đổi giao diện hoặc hành vi của View. Nó yêu cầu triển khai phương thức body(content:), nhận View gốc và trả về View đã sửa đổi.
Các bộ sửa đổi tích hợp sẵn (font, padding) là phương thức mở rộng của giao thức View sử dụng các triển khai nội bộ được tối ưu hóa. ViewModifier là một giao thức cho các bộ sửa đổi tùy chỉnh đóng gói một sự kết hợp của các bộ tích hợp sẵn và có thể có các tham số khởi tạo.
Tạo ViewModifier tùy chỉnh khi cùng một kết hợp bộ sửa đổi được sử dụng ở ba nơi trở lên. Đối với các chuỗi một lần, hãy sử dụng bộ sửa đổi trực tiếp trên View — đơn giản và hiệu quả hơn.
Có, ViewModifier có thể chứa các thuộc tính @State hoặc @Environment. SwiftUI quản lý vòng đời của chúng giống như đối với View. Tuy nhiên, hãy nhớ rằng body được gọi trong mỗi bản cập nhật, vì vậy tránh các thao tác nặng trong phần thân của bộ sửa đổi.
Sử dụng if/else trong @ViewBuilder hoặc tạo một bộ sửa đổi với tham số boolean áp dụng hoặc bỏ qua các thay đổi một cách có điều kiện bên trong body. Ví dụ, PrimaryButton ở trên sử dụng isEnabled để áp dụng kiểu có điều kiện.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm