iOS/Auto Layout – Phần 6: Những trường hợp đặc biệt trong Auto Layout

by DaoNMSE02016
956 views

Lời mở đầu

Trong bài viết này mình sẽ chia sẻ về cách tạo constraint cho một số view đặc biệt và những lưu ý khi chúng ta tạo các constraint cho các view.



1. UISrollView

UIScrollView là một view tạo constraint khá là phức tạp và khó hiểu với người mới. Thật không may là nó lại được sử dụng trong khá nhiều trong ứng dụng của bạn. Nhưng nó sẽ trở nên đơn giản hơn nếu bạn hiểu được bản chất của nó.

UIScrollView là một view mà nó cho phép cuộn và phóng to nội dung của nó.

Khi tạo constraint cho scroll view bạn cần tạo constraint cho 2 bước:
– Bước 1 là cần phải tạo các constraints cố định khung(kích thước và vị trí) của scroll view so với super view của nó.
– Bước 2 là cần phải tạo các constraint cho các view trong scrollview.

1.1 Tạo constraint cho UIScrollView không sử dụng Content Layout Guide

Sử dụng trong trường hợp bạn sử dụng bản XCode version < 11 hoặc bạn sử dụng XCode 11 nhưng không muốn dùng Content Layout Guide của UIScrollView.

Giờ chúng ta kéo 1 scrollView vào và tạo constraint nó với superview như hình dưới:

Vậy là ta đã hoàn thành bước 1: tạo constraint xác định vị trí, kích thước của Scroll View. Trong trường hợp này mình đang để scrollview có kích thước bằng kích thước của màn hình.

Tiếp theo chúng ta đến bước 2 tạo constraint cho các view trong scroll view.
Chúng ta cần kéo vào 1 UIView để chứa tất cả các View.
Lúc này chúng ta sẽ tạo constraint cho View này bằng cách kéo chuột phải từ view đó vào scrollview và giữ Shift để add nhiều constraint như hình dưới:

Việc Fix equal height, equal width với scroll view giúp các bạn xác định vị trí cũng như kích thước của nội dung scrollview.

Giờ chúng ta có thể kéo các View mình muốn vào trong view này và sắp xếp chúng theo ý muốn. Ở trường hợp này mình muốn kéo vào 1 label và 1 button. Nên mình sẽ constraint theo như hình phía dưới.

Tiếp theo, do trong trường hợp này mình làm scrollview cuộn theo chiều dọc nên mình sẽ bỏ constraint equal height của view với scrollview đi. Khi đó ta cần sửa lại chỉ số constraint bottom của button sao cho phù hợp với thiết kế, giả sử trường hợp này mình sẽ để là 40 points. Ta sẽ được kết quả như hình:

Tiếp đến các bạn cần tìm constraint bottom của View Content và sửa lại giá trị của nó về giá trị mình mong muốn( thường sẽ để là 0) Constraint này đại diện cho khoảng cách bottom giữa scrollview và contentview khi mà content view có size lớn hơn size của scroll view.

Vậy là xong.
Bước cuối cùng chúng ta test lại scroll view bằng cách set 1 đoạn text dài cho Label.
kết quả sẽ được như hình dưới:

1.2 Tạo constraint cho UIScrollView với Content Layout Guide

Từ XCode 11 trở đi Apple đã cho thêm 1 thuộc tính Content Layout Guide cho UIScrollView giúp mọi người tạo constraint cho nó 1 cách dễ dàng hơn. Khi bạn kéo vào 1 UIScrollView ở XCode 11 nó sẽ mặc định được bật tính năng này. Khi này bên trong scroll view sẽ có 2 layout guide là Content Layout guide và Frame Layout Guide

Nó khác với cách tạo 1.1 là thay vì nó constraint trực tiếp với ScrollView thì nó lại constraint với các Layout guide của scroll view.

Content Layout guide: Chọn ContentView sử dụng chuột phải kéo vào Content layout guide và tạo các constraint ContentView với content layout guide leading, top, trailing, bottom như sau:

Frame Layout guide: Chọn content View sử dụng chuột phải kéo vào Frame Layout guide và tạo các constraint equal width nếu muốn cuộn dọc hoặc equal height nếu muốn cuộn ngang.

Còn lại chúng ta vẫn làm giống ở mục 1.1.

2. UILabel

Thông thường 1 UILabel chỉ cần 2 constraint để xác định được vị trí cũng như kích thước của nó. Thế nên rất nhiều bạn khi tạo constraint cho UILabel thường bị thiếu constraint, dẫn đến trường hợp khi build app lên bị vỡ layout.

2.1 Nên tạo ít nhất 4 Constraint cho UILabel

UILabel là view có thể tự thay đổi kích thước của nó dựa trên content size (text, font ..) của nó. Vì vậy nếu bạn không tạo đủ constraint cần thiết cho UILabel trong một số trường hợp nội dung của UILabel sẽ không hiển thị đúng như mong đợi.

Nếu bạn chỉ sử dụng 2 constraint sẽ dẫn đến trường hợp khi nôi dung của label dài ra nó sẽ bị tràn ra ngoài màn hình.

2.2 Nên set thêm constraint height cho các UILabel nếu nó làm nhiệm vụ giữ trục phát triển View

Trong trường hợp UILabel làm nhiệm vụ giữ trục của view mà nó được gán giá trị empty sẽ dẫn đến trường hợp bị vỡ layout vì khi UILabel có text = “” (empty) height của nó sẽ = 0 vì thế ta cần tạo constraint cho nó và để giá trị là greater than or equal (>=). Khi đó các label giữ trục của view sẽ không làm vỡ layout nữa vì giá trị height nhỏ nhất của nó hiện tại không phải là 0 nữa.

Các bạn theo dõi sự khác nhau của 2 hình dưới đây.

Có set height >=
Không set height

3. UIButton

UIButton cũng là một View có thể tự thay đổi kích thước dựa trên nội dung của nó. Vì vậy chúng ta cũng cần lưu ý khi tạo constraint cho nó. Đối với buton chúng ta chỉ cần 2 constraint là có thể xác định vị trí cũng như kích thước của nó. Nhưng để nó có thể hiển thị đúng trong nhiều trường hợp thì chúng ta cần nhiều hơn 2 constraint.

Không nên set width cho button có chứa text

Vì UIButton nó sẽ tự thay đổi kích thước theo nội dung bên trong, nên khi text dài ra hoặc ngắn đi nó sẽ tự thay đổi kích thước của button cho phù hợp. Nếu chúng ta gán constraint width cho nó thì dễ dẫn đến trường hợp khi text dài ra button sẽ hiển thị mất chữ.
Vì vậy thay vì các bạn set constraint width cho UIButton để đạt được kết quả như file design thì chúng ta sẽ sửu dụng thuộc tính insets để căn chỉnh khoảng cách nội dung của UIButton.

Ở đây mình sử dụng content insets để căn khoảng cách của nội dung button với các cạnh của nó.

4. Priority: Độ ưu tiên khi các View

Với mỗi view đều có 2 loại Priority đó là:
– Content Hugging Priority (Vertical, horizontal)
– Content Compression Resistance Priority (Vertical, horizontal)

Content Hugging Priority

Là độ ưu tiên ôm nội dung của View. View nào có độ ưu tiên của nó lớn hơn thì nó sẽ ưu tiên nội dung của view đó hiển thị đúng với các chỉ số. Các view lân cận có độ ưu tiên nhỏ hơn sẽ phải tự dãn content để lấp dầy khoảng trống còn lại theo chiều ngang hoặc dọc.
Nó sẽ hoạt động nếu nội dung của các chiều đang không lấp đầy khoảng trống có sẵn trong super view.

Theo dõi hình ảnh dưới đây để hiểu rõ hơn:

Hình này Label có Hugging priority lớn hơn của Button.
Vì vậy nó sẽ ưu tiên ôm nội dung của Label và dãn button.
Trường hợp này thì Button có Hugging priority lớn hơn của Label.
Nên nó sẽ ưu tiên ôm nội dung của Button và dãn Label.

NOTE: Nếu Priority của 2 View bằng nhau nó sẽ sảy ra lỗi constraint. Vì vậy các bạn cần xác định được View nào cần độ ưu tiên cao hơn ở các trường hợp khác nhau.

Tuy nhiên nó chỉ đúng khi nội dung của các view không chiếm hết khoảng không còn lại ở super view theo chiều của priority.
Khi nội dung của các view vượt quá khoảng không có sẵn thì chúng ta cần sử dụng Content compression resistance priority để giải quyết.

Content compression resistance priority

Đây là thuộc tính thể hiện độ ưu tiên chống lại việc nén nội dung của View. Có nghĩa là View nào có priority lớn hơn sẽ được ưu tiên hiển thị nội dung của nó để lấp khoảng trống còn lại trong super view trước, sau đó nếu còn khoảng trống thì các view còn lại có priority nhỏ hơn sẽ được lấp vào, nếu hết khoảng trống nó có thể sẽ biến mất nếu không có constraint.priority lớn hơn(Priority của các constraint mặc định là 1000).
Priority này sẽ hoạt động khi nội dung của các view được lấp đầy hoặc vươti quá size của super view.

Theo dõi hình dưới đây để hiểu rõ hơn:

Độ ưu tiên chống nén của UILabel cao hơn Button nên nội dung của button sẽ không hiển thị đầy đủ
Trong trường hợp này độ ưu tiên chống nén nội dung của UILabel thấp hơn nên Nội dung của button được hiển thị đầy đủ, còn UILabel trong trường hợp này sẽ mất chữ nếu có line = 1. Vì vậy ở đây mình để line = 0 để label tự co dãn

Tổng kết

Mình hi vọng bài viết sẽ giúp cho các bạn có thêm 1 chút tự tin khi làm việc với Auto Layout 😀



Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.