Contents
Chào mừng bạn đến với Fx Studio. Chủ đề bài viết lần này là Multiple storyboards. Hướng dẫn cách sử dụng nhiều Storyboard trong một iOS Project. Qua đây, bạn sẽ thấy được cách khắc phục những nhược điểm tồn tại lâu nay của Storyboard.
Nếu bạn chưa biết gì về nó, thì có thể tìm đọc ở bài viết dưới đây:
Còn nếu mọi việc đã ổn rồi, thì …
Bắt đầu thôi!
Chuẩn bị
Storyboard là một trong những tính năng được cập nhật mới trong iOS 5. Do đó, hầu như Xcode của bạn đang dùng lúc này đều đảm bảo có tính năng Storyboard trong iOS project rồi.
Như mình nói ở trên, hầu hết các dev iOS đều không thích Storyboard. Việc đầu tiên mà họ sẽ là khi tạo mới một iOS Project là sẽ xóa nó và thay đổi cấu hình project lại. Nếu bạn không biết cách xóa nó, thì hãy tham khảo bài viết dưới đây.
Về mặt kiến thức, yêu cầu bạn đã biết về lập trình iOS ở mức cơ bản. Mình sẽ không giải thích hay đi hướng dẫn những gì quán cơ bản, như là: IBAction, IBOutlet, UIViewController … Và nếu bạn chưa biết về lập trình iOS thì có thể đọc qua loạt bài về Lập trình iOS cho mọi người này nhóe!
Storyboards và nhược điểm
Ở bài viết trước, bạn đã tìm hiểu nhiều về Storyboard và cách tạo giao diện cơ bản trên iOS với chúng. Và mình đã nói về sự ảnh hưởng từ quá khứ & thói quen lập trình của dev iOS. Dẫn tới sự hạn chế sử dụng Storyboards trong các dự án iOS nói chung. Kinh khủng nhất là …
Nó sẽ bị xóa ngay sau khi tạo mới một iOS Project.
Có rất nhiều nhược điểm được liệt kê ra, ví dụ như:
- Khó kéo thả các view phức tạp
- IBOutlet & IBAction dễ gây crash app
- Vấn đề về reusable trong các Cell của UITableView & UICollectionView
- Sự phức tạp của hệ thống Segue Identifier
- Thời gian build lâu
- Code khá chậm
- Một mớ hỗn độn khi số lượng các màn hình nhiều lên trong 1 file Storyboard
- Vấn đề về điều hướng
- Không tốt khi làm việc theo team và dễ bị conflict code với người khác
- Không có tính tái sử dụng lại
- Màn hình máy tính nhỏ quá
- …
Cũng phải tới 7749 lý do được đưa ra, nhằm cũng cố mục đích xóa nó ra khỏi dự án. Hoặc làm cái cớ cho bạn tránh việc đổ vỏ các dự án liên quan tới Storyboards. Tuy nhiên, với sự ra đời của chip M1. Hầu như các vấn đề trên đều đã được giải quyết. Cái hạn chế tồn tại duy nhất và trường tồn với thới gian, chính là:
Suy nghĩ của bạn
Và cách giải pháp tiếp theo chính là việc tách và sử dụng nhiều Storyboards trong cùng một dự án.
Tách Storyboards
Chúng ta sẽ bắt tay vào việc demo ngay. Bạn hãy tạo một iOS Project của riêng bạn hoặc có thể làm theo ví dụ của mình. Bạn hãy yên tâm, vì giao diện cũng rất chi là đơn giản. Chúng ta sẽ bắt đầu với 2 màn hình đơn giản như sau.
Bạn hãy tưởng tượng đó là một Storyboard với rất nhiều màn hình.
Khi đó việc load file sẽ rất là lâu.
Và khi bạn tách chúng nhỏ thì sẽ ổn hơn rất nhiều. Bạn sẽ làm theo các bước sau:
-
- Chọn các màn hình liên quan với nhau
- Chọn Menu > Editor > Refactor to Storyboard
- Đặt tên cho Storyboard mới
Kết quả nhận được như sau:
- Tại file Storyboard gốc
- Tại file Storyboard mới
Khá nhanh & khá đơn giản, khi bạn đã có thể tách các Storyboard. Và không gây ảnh hưởng gì tới toàn bộ. Bạn hãy build và cảm nhận kết quả nào!
Kết nối với một Storyboard có sẵn
Chúng ta sẽ có một trường hợp khác, đó là bạn đã có nhiều Storyboards rồi. Công việc lúc này, bạn sẽ tìm cách kết nối chúng lại với nhau. Công việc này sẽ thực hiện được dựa vào các
Storyboard Reference
Bắt đầu, bạn sẽ tạo thêm một luồng các màn hình mới. Mình gọi nó là LoginFlow.
Với các màn hình như sau:
-
- Login
- Register
- Forgot Password
Chúng ta sẽ dùng một UINavigationController để kết nối chúng và điều hướng giữa các màn hình. Việc điều hướng, bạn vẫn sử dụng tới các Segue và kéo thả mà thôi (mình đã trình bày ở bài viết trước đó).
Bạn sẽ kết nối vào Storyboard khác thông qua việc tạo các Storyboard Reference trong các file Storyboard đó.
Bước tiếp theo, bạn chọn đúng Storyboard liên kết tới tại Attributes Inspector nhóe!
Bước cuối cùng, bạn kéo thả một Segue từ một màn hình nào đó tới Storyboard Reference nhóe.
Quan trong nhất là bạn phải xác định “Is Initial View Controller” của Storyboard Reference nữa nhóe! Build lại project và cảm nhận kết quả tiếp nha!
Kết nối tới một màn hình trong một Storyboard
Trường hợp tiếp theo, bạn sẽ giải quyết vấn đề tái sử dụng lại các màn hình hay các View Controller trong project. Khắc phục được nhược điểm
Tái sử dụng & xung đột code
Lúc này, mỗi người một storyboard và họ sẽ tự quản lý cả một luồng màn hình mà họ đảm nhận. Do đó, về mặt logic của một cá nhân sẽ dễ nắm bắt hơn. Người khác có thể nhìn vào và thấy được tổng thể luồng màn hình di chuyển. Đây chính là ưu điểm của Storyboards. Và khi bạn muốn sử dụng hay gọi lại màn hình của người khác, thì hãy triệu hồi chính màn hình đó trong file storyboard của bạn.
Demo tiếp tục với các màn hình của luồng màn hình Tabbar, với UITabbarController và các màn hình như sau:
Bạn sẽ không cần quan tâm tới chúng nhiều đâu. Vì chúng ta sẽ dùng riêng một màn hình HomeVC mà thôi. Và khi bạn muốn dùng tới HomeVC ở nơi khác, thì hãy định danh nó như sau:
- Chọn màn hình mà bạn muốn sử dụng
- Tại mục Identify Inspector
- Cập nhật thêm Storyboard ID
Bạn có thể đặt tên tùy ý, tốt nhất là tránh trùng lặp với nhau. Sau đó, bạn sẽ làm giống như với cách tạo Storyboard Reference, những sẽ điền thêm Storyboard ID.
Kết quả như sau:
(Cập nhật luôn 2 trường hợp ở trên trong cùng một file Storyboard.)
Hãy build project và cảm nhận kết quả nhóe!
Sử dụng các màn hình trong Storyboard bằng code
Trường hợp này, dành cho các bạn không muốn sử dụng Storyboards, mà lại trúng các dự án có Storyboard. Mục đích tối thượng sẽ là:
Không đổ vỏ!
Vì cuộc đời đôi khi là thế, bạn không tự quyết định được cách bạn sống. Và tốt nhất là chung sống với chúng, học cách thích nghi nhóe.
Với demo, bạn sẽ tìm một màn hình khác ở bất kỳ Storyboard nào mà bạn muốn sử dụng. Tiếp theo, bạn sẽ tạo Storyboard ID cho nó. Tại function nào mà bạn muốn sử dụng màn hình đó, thì tham khảo đoạn code sau:
@IBAction func showVC(_ sender: Any) { let storyboard = UIStoryboard(name: "TabbarFlow", bundle: .main) let vc = storyboard.instantiateViewController(withIdentifier: "VideosVC") as! VideosVC self.present(vc, animated: true) { print("show VC") } }
Khá đơn giản và dễ hiểu, trong đó:
- Bước 1 là bạn sẽ lấy được
storyboard
mà bạn muốn lấy. Thông qua tên của chính nó. - Bước 2 là bạn sẽ lấy được
viewcontroller
mà bạn muốn lấy. Thông qua Storyboard ID của nó. - Cuối cùng, bạn sẽ sử dụng nó như một đối tượng bình thường.
Okay & build lại để cảm nhận kết quả nhóe!
Change Root
Vấn đề cuối cùng sẽ là thay đổi luồng màn hình chính của cả project. Hay dân gian gọi là:
Change root
Một công việc bắt buộc bạn phải làm. Dù cho việc sử dụng Storyboard hay các XIB files đi nữa. Còn với Multiple Storyboards thì cũng tương tự như với cách không sử dụng Storyboard trong việc change root này.
Đâu tiên, bạn đã có các luồng màn hình từ các ví dụ trên:
- Tutorial
- Login
- Tabbar
Tiếp theo, chúng ta sẽ cấu hình chúng trong file SceneDelegate và thêm function để thực hiện change root.
enum RootType { case tutorial case login case tabbar } func changeRoot(type: RootType) { switch type { case .tutorial: let storyboard = UIStoryboard(name: "TutorialFlow", bundle: .main) let vc = storyboard.instantiateViewController(withIdentifier: "TutorialVC") as! TutorialVC self.window?.rootViewController = vc case .login: let storyboard = UIStoryboard(name: "LoginFlow", bundle: .main) let navi = storyboard.instantiateViewController(withIdentifier: "LoginNavi") as! UINavigationController self.window?.rootViewController = navi case .tabbar: let storyboard = UIStoryboard(name: "TabbarFlow", bundle: .main) let tabbar = storyboard.instantiateViewController(withIdentifier: "tabbar") as! UITabBarController self.window?.rootViewController = tabbar } }
Và bạn có thể khởi tạo project với việc xét root
là một màn hình từ một Storyboard nhóe. Tham khảo đoạn code sau:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) let storyboard = UIStoryboard(name: "TutorialFlow", bundle: .main) let vc = storyboard.instantiateViewController(withIdentifier: "TutorialVC") as! TutorialVC window.rootViewController = vc self.window = window window.makeKeyAndVisible() }
Cuối cùng, tại các function diễn ra sự thay đổi root
thì chúng ta sẽ gọi function changeRoot(:_)
trên. Ví dụ, tại Login sang Tabbar như sau:
@IBAction func gotoTabbar(sender: Any) { guard let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate else { fatalError("could not get scene delegate ") } sceneDelegate.changeRoot(type: .tabbar) }
Trong đó:
- Bạn phải tìm cách lấy được
sceneDelegate
bằng mọi giá - Gọi
changeRoot()
để thực hiện công việc
Hoàn thiện tất cả và kết nối chúng lại với nhau. Sau đó, bạn hãy build và tiếp tục cả nhận kết quả nhóe!
Tạm kết
- Tìm hiểu các nhược điểm khi sử dụng Storyboard trong project
- Tách các Storyboard từ các Storyboard
- Kết nối các Storyboard với nhau thông qua Storyboard Reference
- Kết nối các màn hình riêng lẻ của các Storyboard trong Storyboard khác
- Tìm các màn hình bằng code và sử dụng chúng trong project
- Change root trong project với nhiều Storyboards
Okay! Tới đây, mình xin kết thúc bài viết về Multiple Storyboards trong iOS. Nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.
- Bạn có thể checkout code tại đây.
Cảm ơn bạn đã đọc bài viết này!
Related Posts:
Written by chuotfx
Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!
Leave a Reply Cancel reply
Fan page
Tags
Recent Posts
- Prompt Engineering trong 10 phút
- Một số ví dụ sử dụng Prompt cơ bản khi làm việc với AI
- Prompt trong 10 phút
- Charles Proxy – Phần 1 : Giới thiệu, cài đặt và cấu hình
- Complete Concurrency với Swift 6
- 300 Bài code thiếu nhi bằng Python – Ebook
- Builder Pattern trong 10 phút
- Observer Pattern trong 10 phút
- Memento Pattern trong 10 phút
- Strategy Pattern trong 10 phút
You may also like:
Archives
- December 2024 (3)
- September 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (4)
- April 2024 (2)
- March 2024 (5)
- January 2024 (4)
- February 2023 (1)
- January 2023 (2)
- November 2022 (2)
- October 2022 (1)
- September 2022 (5)
- August 2022 (6)
- July 2022 (7)
- June 2022 (8)
- May 2022 (5)
- April 2022 (1)
- March 2022 (3)
- February 2022 (5)
- January 2022 (4)
- December 2021 (6)
- November 2021 (8)
- October 2021 (8)
- September 2021 (8)
- August 2021 (8)
- July 2021 (9)
- June 2021 (8)
- May 2021 (7)
- April 2021 (11)
- March 2021 (12)
- February 2021 (3)
- January 2021 (3)
- December 2020 (3)
- November 2020 (9)
- October 2020 (7)
- September 2020 (17)
- August 2020 (1)
- July 2020 (3)
- June 2020 (1)
- May 2020 (2)
- April 2020 (3)
- March 2020 (20)
- February 2020 (5)
- January 2020 (2)
- December 2019 (12)
- November 2019 (12)
- October 2019 (19)
- September 2019 (17)
- August 2019 (10)