Chào mừng bạn quay trở lại với series “Android Developer Roadmap“! Sau khi đã làm quen với môi trường phát triển, hiểu về ngôn ngữ Kotlin, OOP, cấu trúc dữ liệu, Git, và thậm chí là xây dựng ứng dụng “Hello World” đầu tiên (Android Developer Roadmap: Ứng dụng Android Đầu Tiên Của Bạn – Tạo “Hello World” Từ Con Số Không), cũng như khám phá vòng đời Activity (Hiểu Rõ Vòng Đời Activity trong Android (Kèm Sơ Đồ Thực Tế)) và các thành phần khác của ứng dụng (Android Developer Roadmap: Khám phá Services, Content Providers, và Broadcast Receivers), đã đến lúc chúng ta chạm vào thứ mà người dùng tương tác trực tiếp: Giao diện người dùng (UI).
Trong thế giới Android, UI được xây dựng chủ yếu từ các khối xếp hình gọi là Views và ViewGroups. Bài viết này sẽ tập trung vào những “khối xếp hình” cơ bản nhất – các View đơn lẻ mà bạn sẽ sử dụng hàng ngày để hiển thị thông tin, nhận dữ liệu từ người dùng, và xử lý tương tác.
Mục lục
View là gì? Nền tảng của Giao diện người dùng Android
Hãy tưởng tượng màn hình ứng dụng của bạn là một bức tranh. Mỗi phần tử trên bức tranh đó, dù là một đoạn văn bản, một hình ảnh, một nút bấm, hay một ô nhập liệu, đều là một View. Về cơ bản, một View
là một hình chữ nhật trên màn hình, có khả năng vẽ nội dung cho chính nó và xử lý các sự kiện tương tác của người dùng (như chạm, vuốt).
Lớp android.view.View
là lớp cha (superclass) của tất cả các thành phần UI mà bạn thấy trong Android. Từ những thứ đơn giản như TextView
đến những thứ phức tạp hơn như RecyclerView
(Android Developer Roadmap: Xây dựng Danh sách Động với RecyclerView trong Android), tất cả đều kế thừa từ lớp View
.
Các Views thường được tổ chức theo cấu trúc cây (View Hierarchy), trong đó các ViewGroup (kế thừa từ View nhưng có thể chứa các Views khác) đóng vai trò là các nút trung gian hoặc nút gốc, chứa các View con. Chúng ta sẽ nói sâu hơn về ViewGroups (Layouts) trong bài viết sau, nhưng tạm thời, hãy hiểu rằng View là những thành phần đơn lẻ, và ViewGroup là những container dùng để sắp xếp chúng.
Bạn định nghĩa giao diện người dùng chủ yếu bằng cách sử dụng file XML trong thư mục res/layout
của module ứng dụng. Mỗi tag XML trong file layout thường tương ứng với một lớp View hoặc ViewGroup.
<?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:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<!-- Đây là một TextView -->
<TextView
android:id="@+id/textViewGreeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Xin chào!"
android:textSize="24sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"/>
<!-- Đây là một EditText -->
<EditText
android:id="@+id/editTextName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nhập tên của bạn"
android:inputType="textPersonName"
android:layout_marginTop="8dp"/>
<!-- Đây là một Button -->
<Button
android:id="@+id/buttonSubmit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gửi đi"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"/>
<!-- Đây là một ImageView -->
<ImageView
android:id="@+id/imageViewIcon"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_launcher_foreground"
android:scaleType="centerCrop"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"/>
</LinearLayout>
Trong đoạn mã XML trên, bạn có thể thấy các thẻ như <TextView>
, <EditText>
, <Button>
, và <ImageView>
. Mỗi thẻ này đại diện cho một loại View cụ thể và có các thuộc tính (attributes) riêng để cấu hình giao diện và hành vi của nó.
Các thuộc tính cơ bản của View
Trước khi đi sâu vào từng loại View, hãy nắm vững một số thuộc tính chung mà hầu hết các View đều có:
android:id
: Mã định danh duy nhất cho View trong file layout. Rất quan trọng để bạn có thể tham chiếu và thao tác với View đó từ code Kotlin/Java của mình.android:layout_width
vàandroid:layout_height
: Xác định kích thước của View. Các giá trị phổ biến là:match_parent
: Chiếm toàn bộ không gian có sẵn của View cha.wrap_content
: Kích thước vừa đủ để bao bọc nội dung của View.- Một kích thước cụ thể theo đơn vị
dp
(density-independent pixels) hoặcsp
(scale-independent pixels) cho văn bản.
android:visibility
: Kiểm soát View có hiển thị hay không. Các giá trị là:visible
(mặc định): Hiển thị bình thường.invisible
: Không hiển thị, nhưng vẫn chiếm không gian trong layout.gone
: Không hiển thị và không chiếm không gian trong layout.
android:padding
: Khoảng cách giữa nội dung của View và đường viền của chính nó (khoảng đệm bên trong). Có thể đặt cho cả 4 cạnh (android:padding
) hoặc từng cạnh (android:paddingLeft
,android:paddingRight
,android:paddingTop
,android:paddingBottom
,android:paddingStart
,android:paddingEnd
).android:layout_margin
: Khoảng cách giữa View và các View khác hoặc đường viền của View cha (lề ngoài). Tương tự như padding, có thể đặt cho cả 4 cạnh hoặc từng cạnh.
Còn rất nhiều thuộc tính khác liên quan đến màu nền, căn chỉnh, trọng lực, v.v., nhưng đây là những thuộc tính cơ bản nhất bạn cần biết.
Các View cơ bản bạn sẽ sử dụng hàng ngày
Bây giờ, chúng ta hãy cùng tìm hiểu chi tiết về các View phổ biến nhất:
1. TextView
TextView
là View dùng để hiển thị văn bản không thể chỉnh sửa. Nó là một trong những View đơn giản và được sử dụng nhiều nhất.
Thuộc tính chính:
android:text
: Văn bản sẽ hiển thị. Nên dùng tài nguyên chuỗi (string resource) để hỗ trợ đa ngôn ngữ.android:textColor
: Màu của văn bản.android:textSize
: Kích thước của văn bản (sử dụng đơn vịsp
).android:textStyle
: Kiểu chữ (normal
,bold
,italic
).android:gravity
: Căn chỉnh văn bản bên trong TextView (ví dụ:center
,left
,right
).android:textAppearance
: Áp dụng một kiểu (style) định sẵn cho văn bản (ví dụ:@style/TextAppearance.AppCompat.Large
).
<TextView
android:id="@+id/myTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/welcome_message"
android:textColor="#333333"
android:textSize="18sp"
android:textStyle="italic"
android:gravity="center"/>
Trong code Kotlin, bạn có thể truy cập và thay đổi văn bản của TextView:
// Giả sử bạn đã thiết lập View Binding
binding.myTextView.text = "Chào mừng bạn, Developer!"
2. EditText
EditText
là View cho phép người dùng nhập và chỉnh sửa văn bản. Nó kế thừa từ TextView
và thêm vào khả năng nhập liệu.
Thuộc tính chính:
android:hint
: Văn bản gợi ý hiển thị khi ô nhập liệu trống (ví dụ: “Nhập tên của bạn”).android:inputType
: Xác định loại dữ liệu mà người dùng có thể nhập (ví dụ:text
,number
,textPassword
,textEmailAddress
,phone
). Điều này giúp hệ thống hiển thị bàn phím phù hợp.android:maxLines
: Số dòng tối đa cho phép.android:singleLine
: Nếu làtrue
, chỉ cho phép nhập trên một dòng (đã bị deprecated, nên dùngandroid:maxLines="1"
).
<EditText
android:id="@+id/myEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nhập email của bạn"
android:inputType="textEmailAddress"/>
Trong code Kotlin, bạn có thể lấy nội dung người dùng nhập hoặc đặt nội dung cho EditText:
// Lấy nội dung
val email = binding.myEditText.text.toString()
// Đặt nội dung
binding.myEditText.setText("[email protected]")
Lưu ý: Khi lấy nội dung, luôn gọi .toString()
vì thuộc tính text
của EditText trả về một đối tượng thuộc kiểu Editable
.
3. Button
Button
là View cho phép người dùng thực hiện một hành động khi chạm vào. Nó là thành phần chính để xử lý tương tác của người dùng.
Thuộc tính chính:
android:text
: Văn bản hiển thị trên nút.android:onClick
: Tên của phương thức sẽ được gọi trong Activity khi nút được click (cách khai báo trong XML). Phương thức này phải nhận một tham số làView
và trả vềUnit
(void
trong Java). Tuy nhiên, cách hiện đại và linh hoạt hơn là thiết lập listener trong code.
<Button
android:id="@+id/myButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me"/>
Trong code Kotlin, bạn thiết lập sự kiện click bằng cách sử dụng setOnClickListener
:
binding.myButton.setOnClickListener {
// Logic xử lý khi nút được click
binding.textViewGreeting.text = "Nút đã được nhấn!"
}
Việc sử dụng setOnClickListener
trong code Kotlin (thường là trong phương thức onCreate
của Activity, sau khi setup View Binding) là cách được khuyến khích hơn so với android:onClick
trong XML, vì nó giúp tập trung logic xử lý vào code và dễ dàng quản lý hơn.
4. ImageView
ImageView
là View dùng để hiển thị hình ảnh. Hình ảnh có thể là từ tài nguyên drawable của ứng dụng, từ internet (khi sử dụng thư viện tải ảnh), hoặc từ bộ nhớ thiết bị.
Thuộc tính chính:
android:src
: Nguồn của hình ảnh. Thường là tham chiếu đến một tài nguyên drawable (ví dụ:@drawable/my_image
).android:scaleType
: Cách hình ảnh được điều chỉnh kích thước để vừa với View. Các giá trị phổ biến:center
: Căn giữa hình ảnh, giữ nguyên kích thước ban đầu.centerCrop
: Phóng to hình ảnh để lấp đầy View, cắt bớt phần thừa.centerInside
: Thu nhỏ hình ảnh để vừa với View, giữ nguyên tỷ lệ.fitCenter
: Căn giữa hình ảnh và điều chỉnh kích thước để vừa với View, giữ nguyên tỷ lệ.fitXY
: Kéo dãn hình ảnh để lấp đầy View mà không giữ tỷ lệ (có thể làm méo ảnh).
android:tint
: Áp dụng một lớp màu (color overlay) lên hình ảnh.
<ImageView
android:id="@+id/myImageView"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@drawable/android_logo"
android:scaleType="fitCenter"
android:contentDescription="@string/android_logo_description"/> <!-- Luôn cung cấp contentDescription cho khả năng truy cập -->
Trong code Kotlin, bạn có thể thay đổi hình ảnh:
// Từ tài nguyên drawable
binding.myImageView.setImageResource(R.drawable.new_image)
// Từ Bitmap (ví dụ sau khi tải về hoặc xử lý)
// binding.myImageView.setImageBitmap(myBitmap)
5. Các View cơ bản khác
Ngoài 4 View chính trên, còn có nhiều View cơ bản khác bạn sẽ thường xuyên bắt gặp:
CheckBox
: Cho phép người dùng chọn hoặc bỏ chọn một tùy chọn.RadioButton
: Thường dùng trong nhómRadioGroup
, cho phép người dùng chọn một tùy chọn duy nhất từ một tập hợp.Switch
: Một công tắc bật/tắt (on/off).ProgressBar
: Hiển thị tiến độ của một tác vụ.SeekBar
: Thanh trượt cho phép người dùng chọn một giá trị trong khoảng.RatingBar
: Cho phép người dùng xếp hạng bằng sao.
Mỗi loại View này đều có các thuộc tính và phương thức riêng để cấu hình và xử lý tương tác tương ứng.
Kết nối View từ XML sang Code (View Binding)
Như bạn thấy trong các ví dụ code Kotlin ở trên, tôi đang sử dụng cú pháp binding.viewId
. Đây là cách hiện đại và được khuyến khích để truy cập các View được định nghĩa trong file XML từ code Activity hoặc Fragment của bạn.
Trước đây, phương pháp phổ biến là sử dụng findViewById(R.id.view_id)
. Tuy nhiên, cách này có nhược điểm là dễ gây lỗi (Runtime Exception) nếu ID không tồn tại hoặc kiểu View không khớp, và tốn hiệu năng hơn một chút.
View Binding tạo ra một lớp binding cho mỗi file layout XML của bạn. Lớp binding này chứa các tham chiếu đến tất cả các View có ID trong layout tương ứng, được typed-safe (kiểu dữ liệu chính xác) và null-safe. Điều này giúp loại bỏ hầu hết các lỗi liên quan đến findViewById
.
Để sử dụng View Binding, bạn cần bật nó trong file build.gradle (Module: app)
:
android {
...
buildFeatures {
viewBinding true
}
...
}
Sau khi sync project, Android Studio sẽ tự động tạo các lớp binding. Ví dụ, nếu layout của bạn là activity_main.xml
, lớp binding tương ứng sẽ là ActivityMainBinding
.
Trong Activity, bạn sẽ sử dụng nó như sau:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.your_app_name.databinding.ActivityMainBinding // Thay bằng tên package và tên binding của bạn
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root // Lấy View gốc của layout
setContentView(view)
// Bây giờ bạn có thể truy cập các View bằng binding object
binding.textViewGreeting.text = "Chào mừng bạn!"
binding.buttonSubmit.setOnClickListener {
val name = binding.editTextName.text.toString()
binding.textViewGreeting.text = "Xin chào, $name!"
}
}
}
Cách tiếp cận này làm cho code của bạn sạch sẽ, an toàn và dễ đọc hơn rất nhiều.
Xử lý Tương tác Người dùng
Hầu hết các View đều có thể xử lý các sự kiện tương tác, phổ biến nhất là sự kiện click. Như đã trình bày ở ví dụ Button
, bạn sử dụng setOnClickListener
để lắng nghe sự kiện này. Tương tự, các View khác cũng có các listener riêng:
EditText
: Có các listener cho sự kiện thay đổi văn bản (addTextChangedListener
), sự kiện bàn phím (setOnEditorActionListener
).CheckBox
/RadioButton
/Switch
: CósetOnCheckedChangeListener
để lắng nghe sự kiện trạng thái checked thay đổi.- Bất kỳ View nào: Có thể có
setOnLongClickListener
cho sự kiện giữ lâu, hoặc lắng nghe các sự kiện chạm phức tạp hơn.
Hiểu và sử dụng các listener này là chìa khóa để tạo ra giao diện tương tác với người dùng.
Bảng tóm tắt các View cơ bản
Đây là bảng tóm tắt nhanh về các View cơ bản chúng ta đã thảo luận:
Loại View | Mục đích | Thuộc tính XML chính | Tương tác người dùng phổ biến | Truy cập/Thao tác từ Code |
---|---|---|---|---|
TextView |
Hiển thị văn bản không chỉnh sửa | android:text , android:textColor , android:textSize , android:gravity |
Click (thường chỉ để phản hồi, không phải hành động chính) | text (đặt/lấy nội dung) |
EditText |
Nhập và chỉnh sửa văn bản | android:hint , android:inputType , android:maxLines |
Nhập liệu bàn phím, sự kiện thay đổi text | text (đặt/lấy nội dung, cần .toString() khi lấy) |
Button |
Kích hoạt một hành động khi chạm | android:text , android:onClick (không khuyến khích) |
Click | setOnClickListener |
ImageView |
Hiển thị hình ảnh | android:src , android:scaleType , android:tint |
Click (tùy mục đích) | setImageResource() , setImageBitmap() , setImageDrawable() |
CheckBox |
Chọn/bỏ chọn một tùy chọn | android:text , android:checked |
Thay đổi trạng thái (checked/unchecked) | isChecked (lấy trạng thái), setChecked() (đặt trạng thái), setOnCheckedChangeListener |
RadioButton |
Chọn một từ nhiều tùy chọn (trong RadioGroup ) |
android:text , android:checked |
Chọn (khi ở trong RadioGroup) | isChecked , setChecked() (thường quản lý qua RadioGroup ) |
Switch |
Bật/tắt | android:text , android:checked |
Thay đổi trạng thái (on/off) | isChecked , setChecked() , setOnCheckedChangeListener |
Lời khuyên cho người mới bắt đầu
- Sử dụng Layout Editor: Android Studio cung cấp một trình soạn thảo layout đồ họa mạnh mẽ. Hãy sử dụng nó để kéo thả các View và xem trước giao diện. Nó cũng giúp bạn làm quen với các thuộc tính XML một cách trực quan.
- Luôn đặt ID: Đảm bảo rằng các View mà bạn cần tham chiếu từ code đều có thuộc tính
android:id
duy nhất. - Sử dụng tài nguyên: Đối với văn bản (text), kích thước (dimensions), màu sắc (colors), hình ảnh (drawables), hãy định nghĩa chúng trong các file tài nguyên tương ứng (
res/values/strings.xml
,res/values/dimens.xml
,res/values/colors.xml
,res/drawable/
). Điều này giúp quản lý, tái sử dụng và hỗ trợ đa ngôn ngữ/đa thiết bị dễ dàng hơn. - Tìm hiểu về Units đo lường: Nắm vững sự khác biệt giữa
dp
(density-independent pixels) vàsp
(scale-independent pixels).dp
dùng cho kích thước và lề,sp
dùng cho kích thước văn bản để nó có thể thay đổi theo cài đặt font của người dùng. - Đọc tài liệu chính thức: Tài liệu của Android Developer là nguồn thông tin tuyệt vời nhất. Khi gặp một View mới hoặc thuộc tính lạ, hãy tìm hiểu trong đó.
Kết luận
Các View cơ bản như TextView, EditText, Button, và ImageView là những viên gạch đầu tiên và quan trọng nhất để xây dựng giao diện người dùng trong ứng dụng Android truyền thống (View-based UI). Nắm vững cách sử dụng chúng, các thuộc tính phổ biến, và cách kết nối chúng với code Kotlin bằng View Binding là nền tảng vững chắc cho hành trình trở thành một nhà phát triển Android giỏi.
Trong bài viết tiếp theo, chúng ta sẽ đi sâu hơn vào cách sắp xếp các View này trên màn hình bằng cách tìm hiểu về ViewGroups hay còn gọi là các Layouts. Đây là bước tiếp theo để bạn có thể tạo ra những giao diện phức tạp và bố cục linh hoạt trên nhiều kích thước màn hình khác nhau.
Chúc bạn học tốt và hẹn gặp lại trong bài viết tiếp theo của series Android Developer Roadmap!