Android Bài 10: Đi Sâu Vào Layout

Posted by

Được chỉnh sửa ngày 29/03/2019.

Chào mừng các bạn đã đến với bài học Android thứ 10, bài học về các layout trong Android. Đây là bài học trong chuỗi bài viết về lập trình ứng dụng Android bằng Java của Yellow Code Books.

Mình nhắc lại một chút về kiến thức ở bài học cũ. Bài 7, chúng ta đã nói đến khái niệm ViewGroup, hiển nhiên như tên gọi của nó, ViewGroup dùng để chứa đựng các View hay các ViewGroup khác. Hôm nay chúng ta cùng nhau nói về các thể hiện cụ thể của ViewGroup, đó chính là các Layout.

Mình cũng xin nhắc lại một tí, đó là:

– Từ View chúng ta xây dựng nên các Widget.
– Từ ViewGroup chúng ta xây dựng nên các Layout.

Có thể nói layout mạnh mẽ nhất, thông dụng và hiệu quả nhất bây giờ chỉ có thể là ConstraintLayout. Nhưng bài này mình sẽ không nói về ConstraintLayout. Vì kiến thức của nó khá nhiều và mình đã dành hẳn 2 bài để nói về nó, bạn có thể bắt đầu tìm hiểu ở link này. Bạn nên đọc qua ConstraintLayout sau khi đọc bài viết hôm nay. Ngoài ConstraintLayout ra thì mình cũng dành hẳn một bài viết khác để nói về các layout phổ biến còn lại như FrameLayout, TableLayout,… các bạn có thể xem tại đây.

Nhắc lại rằng, bài học này chúng ta cùng nhau tìm hiểu hai layout cơ bản, đó là LinearLayoutRelativeLayout. Tuy độ hot của 2 layout này không thể sánh với ConstraintLayout được. Nhưng LinearLayoutRelativeLayout được mình đánh giá là 2 layout cơ bản, chúng tạo nền tảng cho sự ra đời của ConstraintLayout. Bạn có thể xây dựng một giao diện khởi đầu với ConstraintLayout, nhưng rồi đâu đó, bạn cũng sẽ cần đến LinearLayout hoặc RelativeLayout hoặc sự kết hợp của cả hai, chúng lồng vào bên trong ConstraintLayout của bạn. Việc kết hợp này giúp bạn giải quyết các giao diện hóc búa. Hoặc nó đơn giản chỉ là bạn đang tận dụng lại giao diện của một ai đó mà họ không đang sử dụng ConstraintLayout như bạn.

Chúng ta bắt đầu kiến thức về Layout với các khái niệm “mở màn” như sau.

Nói Đến Layout Phải Nói Đến RTL Hay LTR

Bạn biết không, hầu hết các ngôn ngữ trên trái đất này đều có cách viết từ trái sang phải, chúng ta cũng vậy vì tiếng Việt cũng theo cách viết này. Cách viết từ trái sang phải như vậy được gọi là LTR (left-to-right).

Một số ít ngôn ngữ còn lại, như mình biết có ngôn ngữ Ả Rập (Arabic) có cách viết từ phải sang trái, cách viết này được gọi là RTL (right-to-left). Nhớ lại ngày xưa khi còn làm game J2ME, mình đã phải xây dựng thuật toán để hiển thị text (bằng image) cho các game với ngôn ngữ Ả Rập, tuy khó nhưng thú vị lắm các bạn. Bây giờ thì chúng ta đã được Android hỗ trợ rồi nên các bạn yên tâm sẽ không cần phải biết ngôn ngữ Ả Rập là gì đâu nhé.

Tại sao mục này lại nói đến các ngôn ngữ LTR hay RTL? Bạn cũng biết Layout là các ViewGroup dùng để sắp xếp các View hay ViewGroup khác vào bên trong nó, và vì vậy các Layout này cũng sẽ chịu ảnh hưởng nhiều từ các hệ ngôn ngữ LTR hay RTL. Mình ví dụ với LinearLayout bạn sắp làm quen, sẽ có cách sắp xếp các thành phần con của nó bắt đầu từ bên trái hay bên phải là tùy vào hệ ngôn ngữ này. Hoặc hầu hết các Layout đều có điểm neo mặc định ban đầu cho thành phần con là trên-trái (top-left) hay trên-phải (top-right) cũng là tùy vào hệ ngôn ngữ này.

Thêm một ý nữa, nếu như các bài trước bạn có làm quen với các thuộc tính android:paddingLeft hay android:paddingRight hay bất kỳ các thuộc tính nào có các từ LeftRight thì bạn có thể thay thế chúng bằng StartEnd nếu bạn muốn hỗ trợ cho các ngôn ngữ LTRRTL. Chẳng hạn android:paddingStart hay android:paddingEnd. Bạn có thể hiểu nếu LeftRight dùng để chỉ định cứng bên phía nào, thì StartEnd sẽ động hơn. Cụ thể, với ngôn ngữ LTR, Start sẽ chỉ định phía bắt đầu, tức là phía trái. Còn với ngôn ngữ RTL, Start sẽ chỉ định là bên phải.

Nói Về Các Thuộc Tính Của Layout

Nếu như bạn đã đọc qua Bài 9 và đã biết về Khái Niệm Thuộc Tính là dùng để khai báo các biểu hiện của một widget. Và bạn cũng biết Một Số Thuộc Tính Quan Trọng bao gồm ID, layout_width, layout_height. Thì với bài hôm nay khi làm quen với layout, các khái niệm và các thuộc tính quan trọng này vẫn được áp dụng một cách trọn vẹn, không có khác biệt gì cả.

Các mục phía dưới đây sẽ hướng dẫn bạn cách sử dụng thêm các thuộc tính chuyên biệt cho từng loại layout cụ thể. Chúng ta sẽ bắt đầu với LinearLayout.

LinearLayout – Sắp Xếp Các View Nằm Cạnh Nhau

LinearLayout thường được mình mô tả cho dễ hiểu là “xếp cá mòi vào hộp”, bạn sẽ không được phép xếp con này chồng lên con kia, mà chỉ được xếp con này cạnh con kia mà thôi. Bạn có thể chỉ định việc xếp các con cá nằm cạnh nhau theo một chiều ngang, hoặc một chiều dọc.

Các Thuộc Tính Thường Dùng Của LinearLayout

Ngoài các thuộc tính dùng như widget được liệt kê ở mục trên đây, thì LinearLayout còn có các thuộc tính riêng để chỉ định việc sắp xếp “cá mòi” vào trong nó như thế nào.

Vậy mình tổng hợp lại bạn cần quan tâm đến các thuộc tính sau:

– Hướng “xếp cá” (orientation).
– Trọng số (weight).
– Một thuộc tính dịch ra tiếng Việt hơi chuối đó là lực hấp dẫn (gravity).
– Ngoài ra còn có một điều không phải là thuộc tính nhưng cũng được liệt kê trong đây, đó là việc phân bổ không gian cho view con (fill).

Chúng ta cùng làm quen với từng thuộc tính quan trọng này sau đây.

Thuộc Tính Hướng (Orientation)

Như mình đã nói, LinearLayout chỉ xếp các thành phần con nằm cạnh nhau theo một trong hai hướng là ngang hay dọc. Thuộc tính XML android:orientation sẽ giúp bạn định nghĩa được điều đó, tham số của thuộc tính này sẽ là một trong hai giá trị.

android:orientation=”horizontal” – Giúp xếp các thành phần con nằm cạnh nhau theo phương ngang.
android:orientation=”vertical” – Giúp xếp vác thành phần con nằm cạnh nhau theo phương dọc.

Tương tự, nếu muốn dùng thuộc tính hướng cho Java code bạn có thể dùng hàm setOrientation() với tham số truyền vào là một hằng số LinearLayout.HORIZONTAL hoặc LinearLayout.VERTICAL.

Phân Bổ Không Gian Cho View Con (Fill)

Như được nói trước, đây không phải một thuộc tính, nó là một nguyên tắc của LinearLayout. Bạn hãy thử tưởng tượng như vầy, bạn có một LinearLayout mà bên trong nó có 3 view con (view ở đây nói chung là View hoặc ViewGroup) được xếp theo nguyên tắc horizontal, tức xếp lớp theo chiều ngang. Giả sử có một view con có thuộc tính android:layout_width=”match_parent”, tức là view con này có chiều rộng hết LinearLayout cha luôn rồi, thì các view còn lại sẽ hiển thị như thế nào?

Câu trả lời là LinearLayout sẽ dành không gian cho con kiểu “ưu tiên con cả trước”, tức là anh nào được đưa vào trước sẽ được ưu tiên không gian trước, anh nào vào sau sẽ… ra khỏi màn hình mà nằm nếu không đủ chỗ, tức là người dùng sẽ không thấy anh này đâu cả.

Bạn thấy như hình ví dụ sau, mình cố tình thiết lập cho cả 3 view con đều dành không gian rộng 200dp, như vậy ắt sẽ có view phải ra khỏi màn hình, đó là view có background màu xanh dương.

Layout - Phân bổ không gian trong LinearLayout

Thuộc Tính Trọng Số (Weight)

Sau khi xem ví dụ trên đây về việc phân bổ không gian cho view con, ắt hẳn bạn hơi bị thắc mắc, câu hỏi bạn đặt ra bấy giờ là liệu có cách nào đó, với một sự phân chia hợp lý hơn, sao cho tất cả các view con đều có thể hiển thị được trên màn hình?

Chà khó quá… nhưng thật dễ dàng đối với LinearLayout, Google đã tính trước câu hỏi của bạn nên mới ra khái niệm weight.

Nói một cách đầy đủ, weight sẽ giúp bạn thiết lập trọng số cho các view con để sử dụng phần không gian trống còn lại của một LinearLayout, với mỗi trọng số khác 0, phần không gian trống còn lại của LinearLayout sẽ được chia ra cho các view con theo trọng số đó. Để sử dụng trọng số weight, bạn không cần dùng đến layout_width hay layout_height cho view con tương ứng nữa, chúng ta xem qua cách sử dụng weight như sau trước khi xem ví dụ bên dưới.

– Với LinearLayoutorientationhorizontal, bạn nên set android:layout_width của view con về 0dp. Với LinearLayoutorientation là vertical, bạn set android:layout_height của view con về 0dp.
– Khai báo android:layout_weight cho view con đó và cho nó một con số (số nguyên hay số thực đều được, và không kèm theo dp hay dip vào giá trị này).

Bạn có thể xem ví dụ ở hình dưới, mình đã sửa lại bằng cách khai báo weight cho các view con lần lượt là 2-1-1. Khi đó view đầu tiên sẽ có chiều rộng sao cho bằng 2 lần các view còn lại.

Layout - Trọng số weight

Để bạn dễ hiểu hơn, mình tiếp tục thử nghiệm bằng cách đổi lại weight cho chúng lần lượt là 2-3-1. Bạn sẽ thấy view màu đỏ với weight2 sẽ chiếm không gian rộng gấp 2 lần so với view xanh dương với weight1. Tương tự, view màu xanh lá với weight3 sẽ rộng gấp 3 lần so với view xanh dương với weight1. Bạn hiểu độ tương quan của các trọng số weight chưa nào?

Layout - Trọng số weight

Với cách set trọng số weight như trên thì dù cho LinearLayout có không gian như thế nào thì view con cũng sẽ tìm cách lấp đầy không gian trống đó. Nhưng nếu bạn muốn chừa không gian trống cho mục đích nào đó, bạn có thể thiết lập một giá trị android:weightSum cho LinearLayout rồi set weight cho các view con của nó sao cho tổng giá trị weight nhỏ hơn weightSum như hình bên dưới đây.

Như hình thì bạn thấy mình set giá trị weightSum cho LinearLayout8, mà tổng weight của các view con chỉ là 6 thôi, như vậy sẽ còn dư 2 weight không có con nào được fill vào, nên nó mới trống như vậy.

Layout - Giá trị weightSum

Thuộc Tính Lực Hấp Dẫn (Gravity)

Chắc bạn còn nhớ ở bài trước, bài về widget, cũng có dùng đến thuộc tính android:gravity này. LinearLayout của bài hôm nay cũng sử dụng thuộc tính này giống như vậy để canh chỉnh cho các thành phần con của mình.

Mặc định thì các thành phần con bên trong LinearLayout sẽ được “hút” về start-top theo “lực hấp dẫn” mặc định (như đã nói ở trên, start sẽ là left hay right là tùy vào ngôn ngữ LTR hay RTL).

Ví dụ sau mình set android:gravity=”bottom” sẽ làm các view con bị hút (neo) hết xuống dưới so với layout cha.

Layout - Thuộc tính gravity

Bạn cứ từ từ làm quen hết tất cả các giá trị gravity này. Bạn cũng có thể kết hợp nhiều giá trị gravity vào cùng một khai báo thuộc tính bằng cách thêm vào ký tự “|” như này android:gravity=”right|bottom”.

Các Thuộc Tính Thêm Vào Cho View Con

Một điều thú vị là khi các View (hay ViewGroup) khác nằm bên trong một LinearLayout, chúng sẽ có thêm một vài thuộc tính, chủ yếu là canh chỉnh vị trí của bản thân nó so với không gian của layout cha.

Với LinearLayout thì chúng ta chỉ cần quan tâm đến 2 thuộc tính được thêm vào thành phần con, trong đó có thuộc tính weight đã được nói trước ở trên, thuộc tính còn lại như sau.

android:layout_gravity – Không cần giải thích dài dòng, thuộc tính này dùng chính xác như android:gravity của LinearLayout được nói ngay trên đây. Nếu như android:gravityLinearLayout sẽ áp dụng lực hút (hay còn gọi là điểm neo) cho tất cả các con của nó, thì android:layout_gravity dùng cho mỗi thành phần con sẽ có tác dụng neo cho chính thành phần con này mà thôi. Bạn nhớ là tên thuộc tính hơi khác nhau chút, layout_gravitygravity nhé.

Thực Hành Xây Dựng Màn Hình Empty Của TourNote Bằng LinearLayout

Sau khi thực hành qua các bài trước, giao diện đầu tiên khi mở TourNote ra sẽ trông như thế này.

Layout - Giao diện TourNote bài trước

Giờ thì bạn hãy quên đi layout nào đang chứa TextViewImageView mà bạn đã thêm vào trước đó. Nhiệm vụ của bài thực hành này là sử dụng LinearLayout để bao lấy 2 widget này, sao cho chúng vẫn hiển thị đúng như thiết kế ban đầu.

Lưu ý là bài thực hành này chỉ là vọc chơi cho biết LinearLayout thôi nhé. Mong muốn của bài thực hành này là làm sao có thể sử dụng một layout khác, cụ thể là LinearLayout mà vẫn xây dựng được một giao diện như với ConstraintLayout. Kết thúc bài học hôm nay bạn nên trả lại giao diện của TourNote về lại ConstraintLayout như những gì bài học trước đạt được. Và cũng vì lý do vọc chơi thôi nên mình cũng không đẩy source code của bài hôm nay lên Github đâu nhé. Mặc dù chúng ta không công nhận những chỉnh sửa về mặt UI của bài hôm nay, nhưng mình vẫn mong muốn các bạn hãy cứ mở TourNote lên và thực hành đầy đủ. Các layout của bài hôm nay khá quan trọng. Trừ khi các bạn đã biết đến LinearLayout và RelativeLayout là gì rồi thì có thể bỏ qua.

Để bắt đầu, bạn hãy mở file activity_main.xml ra. Trước tiên chúng ta hãy chuyển đổi từ ConstraintLayout sang LinearLayout. Nhớ là chuyển đổi chứ không phải là thêm một LinearLayout vào dưới ConstraintLayout có sẵn đâu nhé. Nhiều bạn không lưu ý chỗ này khi báo cả 2 layout ngang cấp như vậy dẫn đến trình biên dịch báo lỗi đấy.

Để chuyển đổi các layout như thế này thì bạn có 2 cách. Nếu bạn đang ở tab Text của màn hình thiết kế, thì bạn chỉ việc thay đổi khai báo tên thẻ android.support.constraint.ConstraintLayout thành LinearLayout thôi. Đại loại như sau.

Layout - Chỉnh giao diện sang LinearLayout

Tất nhiên bước chuyển đổi tạm như vậy sẽ phát sinh lỗi. Bởi vì bạn nên biết rằng, mỗi một layout sẽ có một cách sắp xếp các thành phần con khác nhau. Và mỗi một view con nằm trong một layout cũng có cách tự canh chỉnh nó khác với khi nằm ở layout khác nữa. Nên việc bạn chuyển một layout này sang layout khác đã làm xáo trộn đi sự canh chỉnh này. Nhưng hãy tạm bỏ qua lỗi đi nhé, chúng ta sẽ canh chỉnh thuộc tính của chúng sau. Giờ chúng ta hãy xem cách chuyển đổi khác từ ConstraintLayout sang LinearLayout nào.

Cách chuyển đổi thứ hai là nếu bạn ở tab Design của màn hình thiết kế, thì bạn hãy tìm đến cửa sổ nhỏ có tên Component Tree. Như hình dưới đây.

Nơi đây chính là nơi hiển thị cách tổ chức layout của bạn. Nó sẽ liệt kê theo dạng cây (tree) các widget hay layout của ứng dụng, theo đúng như những gì mà mình có mô tả về cây này ở mục này đấy nhé. Với cây này thì bạn có thể thấy layout gốc chính là ConstraintLayout. Để chuyển đổi layout gốc này về LinearLayout, bạn hãy click chuột phải vào nó và chọn chức năng Convert view… (như hình).

Sau bước chọn lựa trên bạn sẽ thấy một popup xuất hiện kế tiếp. Bạn sẽ dễ dàng nhìn thấy LinearLayout trong danh sách các layout bạn muốn chuyển đổi. Dĩ nhiên chúng ta chọn LinearLayout rồi, xong thì hãy nhấn Apply.

Sau thao tác chuyển đổi (bằng một trong hai cách trên), thì bạn thấy rằng các widget mà bạn đã sắp xếp từ bài hôm trước chúng bị thay đổi vị trí đến mức không còn có thể nhìn thấy gì cả. Bởi vì chúng khác layout như mình có giải thích ở trên.

Đặc thù của LinearLayout chính là một layout theo kiểu cũ. Tức layout này sinh ra từ khi các lập trình viên Android còn đang code giao diện bằng XML cơ, chứ không phải kéo thả như ConstraintLayout đâu. Nên để làm quen với layout này, bạn nên tập code một tí. Bạn hãy mở tab Text của cửa sổ thiết kế giao diện activity_main.xml lên. Đảm bảo cửa sổ Preview đang được chọn để bạn có thể xem được sự thay đổi đến tức thì khi bạn sửa code XML bên trái.

Mình sẽ liệt kê các chỉnh sửa sau, bạn có thể nhìn qua một lượt rồi tự code lại để so sánh kết quả nhé.

Với LinearLayout gốc.

Mình sẽ thêm thuộc tính orientation và chỉ định giá trị của nó là vertical. Vì hai widget con của nó cần được sắp xếp theo chiều dọc mà.

– Thêm thuộc tính gravity và set giá trị là center. Vì mong muốn các phần tử con canh chỉnh vào giữa màn hình.

Với TextView.

layout_width của TextView sẽ là match_parent. Nó không còn giá trị 0dp nữa, vì chỉ có với ContraintLayout thì giá trị này mới là là match_constraint (tức 0dp) thôi, bài trước mình có nói tới giá trị này rồi.

– Bỏ các thuộc tính layout_constraintBottom_toBottomOf, layout_constraintLeft_toLeftOf, layout_constraintRight_toRightOf, layout_constraintTop_toTopOf. Vì với LinearLayout, các thuộc tính này vô nghĩa.

Với ImageView.

– Bỏ các thuộc tính layout_constraintEnd_toEndOf, layout_constraintStart_toStartOf, layout_constraintTop_toBottomOf. Cũng với ý nghĩa tương tự như TextView trên kia.

Code giao diện sẽ trông như sau.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/activity_main_tv_empty"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:gravity="center"
        android:text="@string/empty_note"
        android:textSize="15sp" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:scaleType="fitCenter"
        app:srcCompat="@drawable/empty_note" />

</LinearLayout>
[/code]

Kết quả khi run ứng dụng sẽ như chúng ta mong muốn. Bạn có thấy giao diện giống với bài học trước không nào.

Layout - Giao diện TourNote bài trước

RelativeLayout – Sắp Xếp Các View Theo Mối Quan Hệ

Nghe đến mối quan hệ chắc bạn sẽ nghĩ đến họ hàng hay quen biết gì đó. Thực chất RelativeLayout sẽ sắp xếp các con của nó theo một trật tự… tự do, mỗi thành phần con sẽ tự quyết định cho mình một chỗ đứng. Cách thức chọn chỗ đứng của các thành phần con là nói cho RelativeLayout biết nó đứng như thế nào so với chính layout cha hay so với các thành phần kế cận mà thôi, đó cũng chính là khái niệm mối quan hệ trong RelativeLayout.

Các Thuộc Tính Thêm Vào Cho View Con

Về cơ bản thì RelativeLayout có tính “dân chủ” hơn LinearLayout, mọi quyết định về vị trí đều ưu tiên cho các thành phần con tự chọn. Chính vì vậy mà với RelativeLayout bạn sẽ hầu như không cần quan tâm đến thuộc tính của chính nó, mà quan tâm đến các thuộc tính thêm vào cho các thành phần con của nó. Và bởi vì có rất nhiều thuộc tính được thêm vào thành phần con, nên mình sẽ tách các thuộc tính này làm nhiều nhóm như sau.

Quyết Định Vị Trí So Với RelativeLayout Cha

Tất cả các thuộc tính dưới đây chỉ cần truyền vào true hay false thể hiện rằng bạn có đồng ý với việc canh chỉnh này hay không mà thôi.

android:layout_alignParentTop – Chỉ định đỉnh của thành phần này sẽ được canh theo đỉnh của layout cha.
android:layout_alignParentBottom – Ngược lại, chỉ định đáy của thành phần này sẽ được canh theo đáy của layout cha.
android:layout_alignParentStart – Chỉ định cạnh start của thành phần này sẽ được canh theo cạnh start của layout cha, dùng cho việc phân biệt RTL hay LTR được nói ở đầu bài hôm nay.
android:layout_alignParentEnd – Chỉ định cạnh end của thành phần này sẽ được canh theo cạnh end của layout cha, dùng cho việc phân biệt RTL hay LTR được nói ở đầu bài hôm nay.
android:layout_alignParentLeft – Chỉ định cạnh trái của thành phần này sẽ được canh theo cạnh trái của layout cha, không phân biệt RTL hay LTR.
android:layout_alignParentRight – Chỉ định cạnh phải của thành phần này sẽ được canh theo cạnh phải của layout cha, không phân biệt RTL hay LTR.
android:layout_centerHorizontal – Chỉ định thành phần này được đặt ngay giữa theo chiều ngang so với layout cha.
android:layout_centerVertical – Chỉ định thành phần này được đặt ngay giữa theo chiều dọc so với layout cha.
android:layout_centerInParent – Chỉ định thành phần này được đặt ngay giữa theo cả hai chiều ngang và dọc so với layout cha.

Quyết Định Vị Trí So Với Các Widget Khác

Tất cả các thuộc tính dưới đây cần phải truyền vào một ID @id/ hay @+id/ (nếu không rõ phần sử dụng ID này, bạn có thể đọc ở mục này của Bài 9.

– android:layout_alignTop –  Chỉ định đỉnh của thành phần này sẽ được canh theo đỉnh của thành phần gọi đến bằng ID.
android:layout_alignBottom – Chỉ định đáy của thành phần này sẽ được canh theo đáy của thành phần gọi đến bằng ID.
android:layout_alignStart – Chỉ định cạnh start của thành phần này sẽ được canh theo cạnh start của thành phần gọi đến bằng ID.
android:layout_alignEnd – Chỉ định cạnh end của thành phần này sẽ được canh theo cạnh end của thành phần gọi đến bằng ID.
android:layout_alignBaseline – Chỉ định baseline của thành phần này sẽ được canh theo baseline của thành phần gọi đến bằng ID. Baseline này bạn không nhìn thấy được, dùng để canh chỉnh cho text hiển thị bên trong widget, do đó sẽ hữu dụng khi canh chỉnh các TextView với nhau).
android:layout_above – Chỉ định thành phần này sẽ nằm ở trên so với thành phần gọi đến bằng ID.
android:layout_below – Chỉ định thành phần này sẽ nằm dưới so với thành phần gọi đến bằng ID.
android:layout_toStartOf – Chỉ định thành phần này sẽ nằm bên phía start so với thành phần gọi đến bằng ID.
android:layout_toEndOf – Chỉ định thành phần này sẽ nằm bên phía end so với thành phần gọi đến bằng ID.
android:layout_toLeftOf – Chỉ định thành phần này sẽ nằm bên phía trái so với thành phần gọi đến bằng ID.
android:layout_toRightOf – Chỉ định thành phần này sẽ nằm bên phía phải so với thành phần gọi đến bằng ID.

Thực Hành Xây Dựng Màn Hình Empty Của TourNote Bằng RelativeLayout

Giờ chúng ta tiếp tục “đập” giao diện activity_main.xml một lần nữa, chúng ta hãy chuyển từ LinearLayout sang RelativeLayout.

Cách chuyển đổi thẻ XML thì bạn làm tương tự như khi chuyển từ ConstraintLayout sang LinearLayout trên kia nhé. Sau bước chuyển đổi từ LinearLayout sang RelativeLayout này, bạn lại chứng kiến các widget bên trong màn hình trực quan lại chạy loạn hết cả. Bạn đã hiểu mỗi layout có cách canh chỉnh của chúng như thế nào chưa nào. Mỗi lần bạn chuyển đổi layout, bạn phải canh chỉnh lại các thuộc tính của layout và của chính các widget bên trong layout đó nữa.

Cũng như cách trình bày ở bài thực hành trên. Mình sẽ liệt kê các chỉnh sửa sau cho layout mới, bạn có thể nhìn qua một lượt rồi tự code lại để so sánh kết quả.

Với RelativeLayout gốc.

– Bỏ các thuộc tính không cần thiết với RelativeLayout, như android:gravityandroid:orientation.

Với TextView.

– Thêm thuộc tính layout_centerInParent và set giá trị true cho nó. Như mình có diễn đạt trên kia, điều này giúp TextView tự canh vào giữa layout cha.

Với ImageView.

– Thêm thuộc tính layout_centerHorizontal và set giá trị true cho nó. Điều này giúp canh ImageView vào giữa layout cha theo chiều ngang.

– Thêm thuộc tính layout_below và set giá trị trỏ đến ID của TextView. Điều này như mình có giải thích ở mục này của bài trước, nó sẽ giúp ImageView canh chỉnh sao cho nằm dưới view có ID được chỉ định.

Code giao diện sẽ trông như sau.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/activity_main_tv_empty"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:gravity="center"
        android:text="@string/empty_note"
        android:textSize="15sp" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_below="@id/activity_main_tv_empty"
        android:layout_centerHorizontal="true"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:scaleType="fitCenter"
        app:srcCompat="@drawable/empty_note" />

</RelativeLayout>

Kết quả run lên như thế nào tự bạn kiểm chứng nhé.

Bạn vừa xem qua cách sử dụng 2 layout phổ biến nhất hiện nay là LinearLayoutRelativeLayout. Tuy như mình có nói, chúng ta chưa vội sử dụng 2 layout này vào trong TourNote vội, nhưng bạn hãy cứ biết đến nó nhé. Và nếu có thời gian, mình có một bài viết riêng để nói đầy đủ tất cả các layout trong Android, các bạn có thể vào tham khảo bài Tìm hiểu các layout trong Android.

Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy ủng hộ blog bằng cách:

Đánh giá 5 sao bên dưới mỗi bài nếu thấy thích.
Comment bên dưới mỗi bài nếu có thắc mắc.
Để lại địa chỉ email của bạn ở thanh bên phải để nhận được thông báo sớm nhất khi có bài viết mới.
Chia sẻ các bài viết của Yellow Code Books đến nhiều người khác.

Bài Kế Tiếp

Bạn sẽ được biết cách khai báo và sử dụng build.gradle, dựa trên kiến thức này, bạn sẽ biết cách tìm kiếm và sử dụng các thư viện được viết sẵn cho Android (mà không để sẵn trong Android Platform) hoặc các thư viện của bên thứ ba (Third Party), làm cho ứng dụng của bạn thêm dễ dàng để xây dựng, và trông chuyên nghiệp hơn.

Advertisements
Rating: 5.0/5. From 15 votes.
Please wait...

7 comments

    1. Chào Bạn :
      Lâu nay Mình quay lại đọc từ đầu để nắm sâu hơn bài học và củng cố kiến thức vững hơn để đọc các bài sau được dễ hơn.
      Đọc và thực hành lại đến bài 10 thì có các dòng lệnh sau báo lỗi nhờ Bạn giải thích ý nghĩa của các dòng lệnh này cho Mình với và cho biết các khắc phục :
      android:paddingBottom=”@dimen/activity_vertical_margin”
      android:paddingLeft=”@dimen/activity_horizontal_margin”
      android:paddingRight=”@dimen/activity_horizontal_margin”
      android:paddingTop=”@dimen/activity_vertical_margin”
      Cám ơn Bạn nhiều

      1. Chào bạn Thuận. Yeah cảm ơn bạn đã nhắc, do Android có một sự thay đổi lớn khi các bạn tạo mới một project bây giờ, nó không còn “khớp” với những gì mình viết trước đây nữa, mình sẽ điều chỉnh các bài blog sớm hơn.
        Với lỗi này của bạn là do hiện tại khi tạo mới project Android sẽ không tạo sẵn các thông số này ở resource dimen nữa. Bạn có thể đọc trước Bài 18, ở đó mình có nói về cách sử dụng dimen, cách khai báo bổ sung các thông số mà bạn đang bị báo lỗi do thiếu. Mình tin chắc thông qua lỗi này của bạn, bạn sẽ nắm vững project Android hơn nữa đấy.
        Nếu còn vấn đề gì bạn hãy tiếp tục để lại comment cho mình nhé.

Leave a Reply