Auto Layout Tutorial in iOS 9 Part 1

Hiện nay, Apple đã cho ra nhiều thiết bị với các kích thước màn hình khác nhau như iphone 4s, 5, 6, 6+, ipad. Vậy làm thế nào để ứng dụng của bạn có thể hoạt động trên nhiều thiết bị có kích thước màn hình khác nhau đó mà giao diện không bị vỡ? Câu trả lời là bạn nên dùng auto layout.

1. Auto layout là gì?

Auto layout là hệ thống các ràng buộc (constraint) giữa các thành phần giao diện của chúng ta. Để với một giao diện có thể hiển thị đúng với thiết kế trên các thiết bị có kích thước màn hình khác nhau thì auto layout sẽ hỗ trợ việc đó.

2. Tại sao nên dùng auto layout

Một số đặc trưng sau sẽ giúp bạn trả lời câu hỏi có hay không nên dùng auto layout cho ứng dụng bạn sắp viết:

  • Lập trình đơn giản
  • Dễ dàng bảo trì ứng dụng
  • Đặc biệt rút ngắn được thời gian viết code khi ứng dụng của bạn chạy trên nhiều thiết bị có kích thước màn hình khác nhau

3. Sử dụng auto layout thế nào?

3.1 Bước đầu tiên bạn tạo project và sử dụng autosizing masks

  • Tạo một project sử dụng Single View Application template
  • Chọn Main.storyboard và bạn phải đảm bảo không sử dụng auto layout bằng cách kiểm tra checkbox như hình vẽ bên dưới (bỏ checkbox nếu có)

Screen-Shot-2015-09-05-at-1.28.56-PM-279x500.png

  • Tiếp theo bạn kéo thả 3 đối tượng view tạm thời gọi là top-left, top-right và bottom. Để phân biệt bạn chọn màu background cho từng view như hình vẽ

SwiftAutoLayoutUpdate5-382x500.png

  • Với kích thước các view như sau:

    Top left: Origin 20, 20. Size 130 x 254

    Top right: Origin 170, 20. Size 130 x 254

    Bottom: Origin 20, 294. Size 280 x 254

  • Nếu bạn lựa chọn simulator là 4 inch thì kết quả sẽ giống như hình vẽ sau:

Screen-Shot-2015-09-05-at-1.41.05-PM-700x468.png

  • Vậy vấn đề ở đây là khi chưa nhắc tới các màn hình có kích thước khác, hiện tại ở đây mới chỉ là xoay màn hình ngang, dọc thì các view của chúng ta đã không còn đúng (mong muốn) vị trí. Trong khi đó, thay vì vị trí các view hiển thị không đúng khi ta rotate màn hình sang chế đó landscape, ta muốn:

StrutsProblem-landscape-looks-good-480x289.png

  • Giải pháp đầu tiên chúng ta hãy thử dùng autosizing masks:

    Với view top-left Screen-Shot-2015-04-20-at-10.50.02-AM-387x320.png

    Với view top-right Screen-Shot-2015-04-20-at-10.50.49-AM-259x320.png

    Với view bottom

Screen-Shot-2015-04-20-at-10.51.47-AM-253x320.png

  • Với mỗi view chúng ta add autosizing masks như hình vẽ. Kết quả khi chạy ứng dụng sẽ như hình vẽ:

SwiftAutoLayoutUpdat10-480x320.png

  • Vẫn không như mong muốn. Vậy tại sao lại vậy? Để giải quyết vấn đề này chúng ta phải thêm code. Chúng ta add IBOutlet cho 3 view tương ứng
	@IBOutlet weak var topLeftView: UIView!
	@IBOutlet weak var topRightView: UIView!
	@IBOutlet weak var bottomView: UIView!
  • Overwrite viewWillLayoutSubview. UIKit sẽ gửi một vài thông điệp cho ViewController trước, trong và sau khi rotate. Để có thể thay đổi frame thì viewWillLayoutSubviews là lúc cần add code để thay đổi.
override func viewWillLayoutSubviews() {

    if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft || UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight {

            var rect = topLeftView.frame
            rect.size.width = 254
            rect.size.height = 130
            topLeftView.frame = rect

            rect = topRightView.frame
            rect.origin.x = 294
            rect.size.width = 254
            rect.size.height = 130
            topRightView.frame = rect

            rect = bottomView.frame
            rect.origin.y = 170
            rect.size.width = 528
            rect.size.height = 130
            bottomView.frame = rect

    } else {

            var rect = topLeftView.frame
            rect.size.width = 130
            rect.size.height = 254
            topLeftView.frame = rect

            rect = topRightView.frame
            rect.origin.x = 170
            rect.size.width = 130
            rect.size.height = 254
            topRightView.frame = rect

            rect = bottomView.frame
            rect.origin.y = 295
            rect.size.width = 280
            rect.size.height = 254
            bottomView.frame = rect
    }
  }
  • Cuối cùng khi bạn chạy ứng dụng sẽ hiển thị đúng theo mong muốn nếu bạn chọn thiết bị kích thước màn hình 4 inch. Nhưng với những thiết bị có kích thước màn hình khác thì giao diện hiển thị lại không như mong muốn của bạn. Vậy vấn đề ở đây là bạn mới chỉ giải quyết được một vấn đề đó là rotate. Còn một vấn đề quan trọng hơn cần phải giải quyết đó là hiển thị đúng mong muốn trên tất cả các thiết bị có kích thước khác nhau.

  • Làm thế nào có thể giải quyết được vấn đề trên? Câu trả lời là auto layout.

3.2 Quay trở lại với file Main.storyboard và bắt đầu sử dụng auto layout

  • Chúng ta cần đảm bảo ứng dụng có sử dụng auto layout bằng cách kiểm tra các checkbox như hình vẽ:

Screen-Shot-2015-09-05-at-1.54.04-PM-177x320.png

  • Những ràng buộc view đầu tiên

Screen-Shot-2015-09-05-at-2.09.01-PM-379x320.png

Chọn hai view top-left và top-right và add constraint equal width. Mục đích làm cho hai view này có độ rộng luôn bằng nhau.

  • Tiếp theo bạn chọn view top-left và add các constraint còn lại (top: 20, left: 20, right: 20, bottom: 20).
  • Chọn view top-right và add các constraint còn lại (top: 20, left: 20, right: 20, bottom: 20)
  • Chọn cả 3 view và add constraint equal height. Mục đích đảm bảo cả 3 view trên có chiều cao bằng nhau.
  • Chọn bottom view và add constraint (top: 20, left: 20, right: 20, bottom: 20)

Vậy là bạn có kểt quả như hình vẽ (đảm bảo cả khi rotate và với các màn hình có kích thước khác nhau)

SwiftAutoLayout19-480x270.png

4. Auto layout hoạt động thế nào?

  • Với project chúng ta đã làm ở trên cho thấy auto layout hoạt động dựa trên các constraint (ràng buộc) giữa các view
  • Trước đây, mỗi view chúng ta đều sử dụng frame, bound, center để set frame cho chúng. Đó chính là việc chúng ta hard-code (không nên). Đây là một điểm yếu.

StrutsProblem-coordinates.png

  • Khi chúng ta sử dụng autosizing masks

Struts-coordinates-2-353x500.png

  • Và khi chúng ta sử dụng auto layout

Struts-coordinates-3-353x500.png

Rõ ràng trong trường hợp này việc sử dụng auto layout là hợp lý nhất. Đảm bảo được mong muốn về giao diện với các thiết bị có kích thước khác nhau.

5. Một số loại ràng buộc và mối quan hệ với phần tử cha

5.1 Một số loại ràng buộc

  • Ràng buộc về kích thước: ví dụ độ rộng một UIButton là 70px
  • Ràng buộc về căn chỉnh: ví dụ một UIImageView luôn ở giữa màn hình (theo chiều ngang và dọc)
  • Ràng buộc về khoảng cách: ví dụ khoảng cách giữa hai UILabel là 100px

5.2 Mối quan hệ với phần tử cha

  • Leading Space to Container (ràng buộc khoảng cách với lề trái)
  • Trailing Space to Contrainer (ràng buộc khoảng cách với lề phải)
  • Top Space to Container Margin (ràng buộc khoảng cách với lề trên)
  • Bottom Space to Container Margin (ràng buộc khoảng cách với lề dưới)

5.3 Chú ý khi sử dụng constraint

  • Khi bạn add các constraint thiếu cho một view hoặc các constraint trong cùng một view, giữa các view bị conflick với nhau thì tức là các constraint đó khi ứng dụng chạy sẽ không có hiệu lực. Cách nhận biết như hình sau:

Screen-Shot-2015-09-05-at-4.38.50-PM-480x186.png

  • Khi bạn add constraint cho một view nào đó không đúng với vị trí hiện thời thì xcode sẽ có cảnh báo tam giác màu vàng. Khi đó bạn nên cập nhật lại frame cho view cảnh báo:

Screen-Shot-2015-09-05-at-4.38.50-PM-480x186.png

6. Kết thúc

Vậy auto layout thực sự cũng rất thú vị, mặc dù ở mỗi trường hợp, mỗi thời điểm, mỗi dự án khác nhau chúng ta đều có thể có cách xử lý khác nhau nhưng auto layout luôn là một sự lựa chọn thật hoàn hảo để đảm bảo hiển thị giao diện theo đúng mong muốn của chúng ta.


All Rights Reserved