Sử dụng UIPageViewController để làm Tutorial Screens

Giới Thiệu

Khi chạy 1 ứng dụng bất kỳ lần đầu thông thường trước khi vào sử dụng app sẽ có 1 màn hình hướng dẫn sử dụng các chức năng cơ bản của app, vậy làm thế nào để tạo ra được màn hình tutorial này, trong bài viết này tôi sẽ chỉ cho bạn 1 cách đơn giản tạo màn hình tutorial screens sử dụng UIPageViewController UIPageViewController được giới thiệu từ iOS 5 giúp cho developer thực thi chức năng page 1 cách dễ dàng. Chúng ta có thể cấu hình UIPageViewController:

  • Orientation của page: chiều ngang hay chiều dọc
  • Transition style: page turning style hay dots style
  • Axis

Trong bài viết này chúng ta sẽ tìm hiểu cách sử dụng UIPageViewController để thực hiện 1 app cho phép người dùng có thể scroll nhiều màn hình.

Demo App:

Chúng ta sẽ tạo ứng dụng hết sức đơn giản gồm 5 màn hình tưng ứng 5 pages khác nhau, mỗi màn hình sẽ gồm 1 label dùng để đánh dấu page, chúng ta sẽ swipe để chuyển các page này:

Tạo Project

Mở Xcode, tạo mới Project sử dụng Single View Application template, chúng ta hoàn toàn có thể tạo ứng dụng dạng Page-Based Applicaton, tuy nhiên để hiểu rõ được concept đằng sau UIPageViewController thì chúng ta nên tạo 1 project mới và bắt tay từ đầu với UIPageViewController Đặt tên Product Name là PageApp, chọn ngôn ngữ là Swift

Creating the Tutorial Screen

Bước tiếp theo chúng ta sẽ tạo view controller sử dụng để hiển thị 5 màn hình tutorials: Select File -> New -> File -> Cocoa Touch Class -> Đặt tên class là AppChildViewController kế thừa từ UIViewController, đồng thời tạo 1 view controller trong storyboard và đặt class cho nó là AppChildViewController Chọn AppChildViewController vừa tạo trong storyboard, thay background view của nó thành màu đen, kéo UILabel vào màn hình, đổi font size và chỉnh text cho nó thành "Screen #n", ta có kết quả như sau: Tạo IBOutlet cho label này, đồng thời tạo 1 biến index để đánh trang page:

class AppChildViewController: UIViewController {

    @IBOutlet weak var screenNumber: UILabel!
    var index: Int? = 0
    ...
    }

Trong viewDidAppear chúng ta sẽ hiển thị tên màn hình theo index tương ứng:

 override func viewDidLoad() {
        super.viewDidLoad()
        self.screenNumber.text = "Screen \(self.index)"
    }

Handling the View Controllers

UIPageViewController là 1 container chứa các view controller cho phép user di chuyển giữa các page, mà mỗi page này chính là 1 view controller. Để UIPageViewController có thể thực hiện được thì AppViewController cần phải implement UIPageViewControllerDataSource protocol, bằng cách thực hiện datasource này chúng ta nói cho page view controller biết được cái để hiển thị cho mỗi page. Mở file ViewController.swift khai báo 1 biến UIPageViewController

class ViewController: UIViewController {
    var pageViewController: UIPageViewController!
   ...
   }

Tiếp theo chúng ta cần thực hiện ít nhất 2 methods của protocol:

  • viewControllerAfter: cung cấp viewcontroller ngay sau view controller hiện tại
  • viewControllerBefore: view controller ngay trước view controller hiện tại
extension ViewController: UIPageViewControllerDataSource {
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        if let viewController = viewController as? AppChildViewController {
            var index = viewController.index
            
            index += 1
            
            if index == 5 {
                return nil
            }
            
            return self.viewControllerAtIndex(index: index)
        }
        
        return nil
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        if let viewController = viewController as? AppChildViewController {
            var index = viewController.index
            if index == 0 {
                return nil
            }
            
            index += -1
            
            return self.viewControllerAtIndex(index: index)
        }
        
        return nil
    }
}

Add phương thức sau vào cuối file ViewController.swift

func viewControllerAtIndex(index: Int) -> AppChildViewController {
        let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
        
        if let childVC = storyboard.instantiateViewController(withIdentifier: "AppChildViewController") as? AppChildViewController {
            childVC.index = index
            return childVC
        }
        
        return AppChildViewController()
    }

Cuối cùng để cho iOS biết được số dots được hiển thị trong page view controller và dot nào được selected khi mới mở page lên ta thêm 2 phương thức sau vào cuối file ViewController.swift:

func presentationCount(for pageViewController: UIPageViewController) -> Int {
       return 5
   }
   
   func presentationIndex(for pageViewController: UIPageViewController) -> Int {
       return 0
   }

Initializing the UIPageViewController

Bước cuối cùng chúng ta cần khởi tạo UIPageViewController, mở file ViewController.swift thêm dòng sau vào ViewDidLoad: self.pageViewController = UIPageViewController.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)

override func viewDidLoad() {
        super.viewDidLoad()
        pageViewController.dataSource = self
        
        pageViewController.view.frame = self.view.bounds
        
        let initialVC = self.viewControllerAtIndex(index: 0)
        let viewControllers: [AppChildViewController] = [initialVC]
        
        pageViewController.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
        self.view.addSubview(pageViewController.view)
        self.addChildViewController(pageViewController)
        self.pageViewController.didMove(toParentViewController: self)
}

Compile and run: Hola, chúng ta đã có được kết quả mong muốn. Dựa trên phần hướng dẫn cơ bản này chúng ta hoàn toàn có thể xử lý các bài toán khác nhau với màn hình tutorial như thêm ảnh từng screen, thêm các control khác nhau ...

Link tham khảo: