Giới thiệu
UX (User Experience) là trải nghiệm người dùng, nó quyết định đến sự thuận tiện của người dùng ứng dụng, để tạo ra 1 UX tốt nó cần tổ hợp bởi nhiều yếu tố:
- UI (User Interface) đẹp hoặc chấp nhận được.
- Định hướng trang tốt, người dùng dễ dàng chuyển hướng hoặc định vị được vị trí của người dùng trong ứng dụng.
- Sự phản hồi ngay khi kích hoạt 1 tính năng hoặc có sự phản hồi khi ứng dụng đang tải dữ liệu (hiển thị phần trăm tải).
Để hỗ trợ việc làm ra giao diện với trải nghiệm tốt, Android có một số ViewGroup
giúp thiết kế giao diện từ đơn giản đến phức tạp như FrameLayout
, LinearLayout
, TableLayout
, ...
Hệ thống View trong Android
![Hệ thống 1 số View trên Android](https://resources.stdio.vn/content/article/5fa8e5c55f20adb62674cd33/resources/res-1605441956-1605441956878.png)
Trên đây là hệ thống một số View trong Android, các View trong Android đều được kế thừa từ lớp View
, có rất nhiều View cơ bản trong Android.
Lớp ViewGroup
có các lớp con là FrameLayout
, RelativeLayout
, LinearLayout
.
Khái niệm ViewGroup
ViewGroup
là 1 View, chứa các View
con trong nó và có nhiệm vụ bố trí các phần tử con theo thuật toán của ViewGroup
đó, và chuyển giao event xuống cho các con trong nó.
Các phương thức quan trọng trong ViewGroup
onMeasure()
onMeasure()
là phương thức tính toán chiều rộng, chiều cao cho View
.
onLayout()
onLayout()
là phương thức có nhiệm vụ bố trí các phần tử con trong nó. Ví dụ có 4 View
con, muốn bố trí mỗi View
con nằm 4 góc thì sử dụng phương thức này.
2 phương thức onMeasure()
và onLayout()
chỉ sử dụng nếu muốn tạo ViewGroup
bố trí các phần tử con theo ý muốn.
getChildAt()
getChildAt()
là phương thức lấy View
tại vị trí index của ViewGroup
, bản chất của ViewGroup
là lưu các con của nó trong 1 mảng.
addView()
addView()
là phương thức thêm View
con vào ViewGroup
.
removeView()
removeView()
là phương thức xóa View
con khỏi ViewGroup
.
Tạo ViewGroup
Có thể tạo ViewGroup
để bố trí các View
con theo ý muốn bằng cách kế thừa ViewGroup
và implement lại phương thức onLayout()
của ViewGroup
.
Trong Android các ViewGroup
được sử dụng nhiều nhất đó là:
FrameLayout
RelativeLayout
LinearLayout
ViewGroup sử dụng nhiều trong Android
FrameLayout
FrameLayout
là ViewGroup
đơn giản nhất trong Android vì thời gian tính toán trong onLayout()
cho việc sắp xếp các View con khá nhanh. Mặc định thêm 1 View
vào FrameLayout
thì các View
sẽ nằm đè lên nhau.
Ví dụ 1: TextView
nằm đè lên ImageView
như sau:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.nguyennghia.demo.MainActivity"> <FrameLayout android:layout_gravity="center" android:layout_width="200dp" android:layout_height="200dp"> <ImageView android:scaleType="fitCenter" android:src="@drawable/avatar" android:layout_width="match_parent" android:layout_height="match_parent" /> <TextView android:layout_marginLeft="3dp" android:layout_marginRight="3dp" android:textSize="18sp" android:textStyle="bold" android:layout_marginBottom="6dp" android:gravity="center_horizontal" android:layout_gravity="bottom|center_horizontal" android:background="#a9b4af" android:text="Founder Eitguide.com" android:layout_width="match_parent" android:layout_height="wrap_content" /> </FrameLayout> </FrameLayout>
![Sử dụng FrameLayout trong Android](https://resources.stdio.vn/content/article/5fa8e5c55f20adb62674cd33/resources/res-1605442535-1605442535451.png)
Ngoài ra để định vị các View
con trong FrameLayout
sử dung thuộc tính layout_gravity
với các giá trị sau:
Giá trị | Ý nghĩa |
---|---|
left | Định vị View con nằm mép trái View cha. |
top | Định vị View con nằm mép trên View cha. |
right | Định vị View con nằm mép phải View cha. |
bottom | Định vi View con nằm mép dưới View cha. |
center | Định vị View con nằm giữa View cha. |
center_vetical | Định vị View con nằm giữa View cha theo thiều dọc. |
center_horizontal | Định vị View con nằm giữa view cha theo chiều ngang. |
Ngoài ra cũng có thể or
2 giá trị lại với nhau. Ví dụ định vị View con nằm ở góc bottom-right sẽ là:
layout_gravity="bottom|right" // hoặc layout_gravity="right|bottom"
Thuộc tính layout_gravity
có thể sử dụng được với LinearLayout
.
Ưu điểm
FrameLayout
là nhẹ nhất trong 3 ViewGroup
(FrameLayout
, RelativeLayout
, LinearLayout
), được sử dụng phổ biến.
Nhược điểm
FrameLayout
không thể thiết kế được những giao diện phức tạp.
RelativeLayout
RelativeLayout
sở hữu đầy đủ các tính năng của FrameLayout
và có thêm tính năng hỗ trợ các View
con có thể định vị vị trí tương đối với nhau.
Ví dụ màn hình đăng nhập như dưới đây:
![RelativeLayout trong Android](https://resources.stdio.vn/content/article/5fa8e5c55f20adb62674cd33/resources/res-1605442789-1605442789584.png)
TextView
username nằm trên.EditText
username nằm dướiTextView
username.TextView
password nằm ngay dướiEditText
usenameEditText
password nằm ngay dướiTextView
password.
RelativeLayout
hỗ trợ tính tương đối đó, có thể định vị 1 View
tương đối với View
khác bằng cách chỉ ra id của View
mà nó dùng để xét vị trí tương đối.
Và dưới đây là mã XML thiết kế cho UI trên sử dụng RelativeLayout
.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_centerInParent="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin"> <TextView android:id="@+id/tv_username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Username" android:textSize="18sp" /> <EditText android:id="@+id/edt_username" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/tv_username" /> <TextView android:id="@+id/tv_password" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/edt_username" android:text="Password" android:textSize="18sp" /> <EditText android:id="@+id/edt_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/tv_password" android:inputType="textPassword"/> </RelativeLayout> </RelativeLayout>
Ví dụ trên sử dụng thuộc tính layout_below
và chỉ ra id
.
Dưới đây là một số thuộc tính thường dùng với RelativeLayout
.
Thuộc tính | Ý nghĩa |
---|---|
layout_below | Chỉ ra rằng View hiện tại sẽ nằm dưới View có id được chỉ ra. |
layout_above | Chỉ ra rằng View hiện tại sẽ nằm trên View có id được chỉ ra. |
layout_toLeftOf | View hiện tại sẽ nằm bên trái View có id được chỉ ra. |
layout_toRightOf | View hiện tại sẽ nằm bên phải View có id được chỉ ra. |
layout_alignTop | Định vị View hiện tại theo cạnh trên của View có id được chỉ ra. |
layout_alignRight | Định vị View hiện tại theo cạnh phải của View có id được chỉ ra. |
layout_alignLeft | Định vị View hiện tại theo cạnh trái của View có id được chỉ ra. |
layout_alignBottom | Định vị View hiện tại theo cạnh dưới của View có id được chỉ ra. |
RelativeLayout
không có thuộc tính layout_gravity
để định vị các con theo View cha. Đối với RelativeLayout
sử dụng những thuộc tính khác như sau:
Thuộc tính | Ý nghĩa |
---|---|
layout_centerInParent | Định vị View hiện tại ở giữa View cha |
layout_centerVertical | Định vị View hiện tại ở giữa View cha theo chiều dọc. |
layout_centerHorizontal | Định vị View hiện tại ở giữa View cha theo chiều ngang. |
layout_alignParentTop | Định vị View hiện tại ở theo cạnh trên của View cha. |
layout_alignParentBottom | Định vị View hiện tại ở theo cạnh dưới của View cha. |
layout_alignParentRight | Định vị View hiện tại ở theo cạnh phải của View cha. |
layout_alignParentLeft | Định vị View hiện tại ở theo cạnh trái của View cha. |
Ưu điểm
Ưu điểm của RelativeLayout
là có thể thiết kế UI 1 cách linh hoạt hơn so với FrameLayout
.
Nhược điểm
- Thời gian tính toán để bố trí các phần tử con chậm hơn
FrameLayout
. - Khi
View
cóVisibility = GONE
hoặc xóa ra khỏiRelativeLayout
thì cácView
có tính tương đối vớiView
này sẽ bị hỗn loạn.
LinearLayout
LinearLayout
là 1 ViewGroup
mạnh mẽ trong Android và được sử dụng rất nhiều. Điểm đặc biệt của LinearLayout
là các View
con bên trong không nằm đè lên nhau, 1 View
con chiếm 1 vị trí riêng.
Để thay đổi chiều bố trí của LinearLayout
sử dụng thuộc tính orientation
:
orientation="vertical"
: layout theo chiều dọc.orientation="horizontal"
: layout theo chiều ngang.
Code sử dụng LinearLayout trong XML
Ví dụ bố trí theo chiều dọc:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vetical"> <View android:background="#b95b5b" android:layout_width="match_parent" android:layout_height="50dp"/> <View android:background="#1b5827" android:layout_width="match_parent" android:layout_height="100dp"/> <View android:background="#0e203e" android:layout_width="match_parent" android:layout_height="50dp"/> <View android:background="#86051b" android:layout_width="match_parent" android:layout_height="50dp"/> </LinearLayout>
![LinearLayout trong Android.](https://resources.stdio.vn/content/article/5fa8e5c55f20adb62674cd33/resources/res-1605443661-1605443661183.png)
Ví dụ bố trí theo chiều ngang:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <View android:background="#b95b5b" android:layout_width="50dp" android:layout_height="match_parent"/> <View android:background="#1b5827" android:layout_width="100dp" android:layout_height="match_parent"/> <View android:background="#0e203e" android:layout_width="50dp" android:layout_height="match_parent"/> <View android:background="#86051b" android:layout_width="50dp" android:layout_height="match_parent"/> </LinearLayout>
![LinearLayout trong Android.](https://resources.stdio.vn/content/article/5fa8e5c55f20adb62674cd33/resources/res-1605443747-1605443747794.png)
LinearLayout sử dụng layout_weight
Sử dụng thuộc tính layout_weight
để xác định View đó muốn chiếm bao nhiêu phần trong View
cha?
Ví dụ chia kích thước màn hình thành 2 phần:
- Phần 1 chiếm 1/4 và tiếp tục chia phần này theo chiều ngang thành 4 phần bằng nhau.
- Phần 2 chiếm 3/4 và tiếp tục chia phần này theo chiều dọc thành 4 phần bằng nhau.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" android:orientation="horizontal"> <View android:background="#61afdf" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <View android:background="#338350" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <View android:background="#ba2f9b29" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <View android:background="#5a3676" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout> <LinearLayout android:layout_weight="3" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="0dp"> <View android:background="#533838" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" /> <View android:background="#a11e1e" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" /> <View android:background="#188b12" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" /> <View android:background="#89147b" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" /> </LinearLayout> </LinearLayout>
![LinearLayout và layout_weight trong Android](https://resources.stdio.vn/content/article/5fa8e5c55f20adb62674cd33/resources/res-1605443922-1605443922203.png)
Vẫn ví dụ trên nhưng đặt visibility = GONE
:
![LinearLayout trong Android](https://resources.stdio.vn/content/article/5fa8e5c55f20adb62674cd33/resources/res-1605443976-1605443976181.png)
Lúc này phần thứ 2 không chiếm 3/4 mà chiếm toàn bộ màn hình. Vì mặc định, không xác định giá trị cho weightSum
thì weightSum
sẽ được tính bằng tổng layout_weight
của các View
con.
Ví dụ trên phần thứ 2 có layout_weight
= "3"
nên weightSum= "3"
. Vì vậy, nó sẽ chiếm toàn bộ màn hình.
Để chắc chắn nên xác định weightSum
cho LinearLayout
.
Ví dụ trên được điều chỉnh lại như sau:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:weightSum="4"> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="horizontal" android:visibility="gone" android:weightSum="4"> <View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#61afdf" /> <View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#338350" /> <View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#ba2f9b29" /> <View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#5a3676" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="3" android:orientation="vertical" android:weightSum="4"> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#533838" /> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#a11e1e" /> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#188b12" /> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#89147b" /> </LinearLayout> </LinearLayout>
LinearLayout
có thuộc tính layout_gravity
giúp căn chỉnh các View
con theo View
cha giống như FrameLayout
.
Ưu điểm
So với FrameLayout
và RelativeLayout
thì LinearLayout
mạnh mẽ và có thể chia được các phần khác nhau, phù hợp thiết kế cho các loại màn hình khác nhau.
Nhược điểm
LinearLayout
là ViewGroup
, được xem là phức tạp vì thời gian tính toán để bố trí các phần tử con bên trong nó khá lâu. Vì vậy, khi thiết kế UI nên cân nhắc và xét độ ưu tiên sử dụng ViewGroup
theo trình tự sau: FrameLayout
> RelativeLayout
> Linearlayout
.