75% điện thoại trên thế giới chạy Android và 75% người dùng Internet chỉ truy cập qua điện thoại. Do đó, thị trường ứng dụng Android cực lớn.
Chúng tôi vừa phát hành khóa học phát triển ứng dụng Android trên kênh YouTube freeCodeCamp.org. Khóa học hoàn hảo cho người hoàn toàn mới bắt đầu.
Khóa học do Rahul Pandey giảng dạy – Android Lead tại Facebook và giảng viên tại Đại học Stanford.
Bạn sẽ học phát triển Android bằng cách xây dựng một ứng dụng tính tiền bo (tip calculator). Không yêu cầu kinh nghiệm Android trước đó, và cuối khóa bạn sẽ có một app có thể xuất bản.
Bạn sẽ học:
- Tạo giao diện người dùng (UI) bằng XML
- Viết logic xử lý bằng ngôn ngữ Kotlin
- Sử dụng ConstraintLayout cho bố cục
- Xử lý sự kiện với hai listener
- Thêm animation cho phần trăm bo và footer tùy chỉnh
Xem khóa học dưới đây hoặc trên YouTube freeCodeCamp.org (1 giờ).
Nội dung chính của khóa học
Demo ứng dụng
App cho phép nhập số tiền hóa đơn và phần trăm bo, tự động tính tiền bo và tổng cộng. Bàn phím chỉ cho nhập số và dấu thập phân. Thanh kéo (SeekBar) điều chỉnh % bo từ 0-30%, mô tả thay đổi động: "Poor" (đỏ), "Acceptable", "Good", "Great", "Amazing" (xanh lá). Footer cho phép cá nhân hóa tên tác giả.
Các khái niệm cốt lõi
- Tạo UI: Mọi app đều cần giao diện. ConstraintLayout chứa các widget (TextView, EditText, SeekBar) với cấu trúc phẳng (flat hierarchy) – không lồng view group – giúp hiệu năng tốt, tránh lag (jank).
- Phản hồi tương tác người dùng: Hai nguồn nhập liệu: số tiền (EditText) và % bo (SeekBar). App cập nhật UI realtime khi có thay đổi.
- Styling & Animation cơ bản: Thay đổi màu sắc động và animation cho mô tả % bo.
Điều KHÔNG được覆盖 trong khóa học (để đơn giản hóa)
- Nhiều màn hình (navigation, back stack)
- Mạng/API (lập trình bất đồng bộ, quản lý dữ liệu)
- Lưu trữ (database, file, cloud) – mọi thứ chỉ ở bộ nhớ cục bộ
Xây dựng giao diện với ConstraintLayout
Tạo project Android Studio
- Chọn "Empty Activity" template
- Tên app: "Tippie"
- Package name: đảo ngược domain/email
- Language: Kotlin
- Min SDK: API 21
Chạy thử project rỗng trước để đảm bảo môi trường ổn định.
Cấu trúc file chính
MainActivity.kt– logic nghiệp vụ màn hình chínhactivity_main.xml– layout UI
Method onCreate() gọi setContentView(R.layout.activity_main) để gán layout.
Thiết kế layout 8 thành phần
Bên trái: 4 TextView (label: Base, Tip %, Tip, Total). Bên phải: EditText (số tiền), SeekBar (% bo), 2 TextView (kết quả Tip, Total).
Ràng buộc dọc: Mỗi TextView trái cách nhau 32dp. Ràng buộc ngang: Căn lề phải theo TextView đầu tiên (Base).
Dùng tab Code để thêm constraint app:layout_constraintEnd_toEndOf cho các TextView trái. Xóa namespace tools sau khi ràng buộc xong. Format code (Double Shift → Reformat).
Thành phần bên phải:
- EditText:
inputType="numberDecimal", hint "Bill amount", ems=8, textSize=24sp - SeekBar: width=200dp, max=30
- 2 TextView kết quả: textSize large
Căn dọc: cặp EditText-TextView Base, SeekBar-Tip%, 2 TextView kết quả. Căn ngang: lề trái các thành phần phải cách 32dp từ TextView trái tương ứng, và căn lề trái nhau.
Dùng tools:text cho TextView kết quả để chỉ hiển thị preview, không hiển thị khi chạy thật.
Xử lý logic với Kotlin
Tham chiếu View
Khai báo 5 view quan trọng: etBaseAmount, seekBarTip, tvTipPercentLabel, tvTipAmount, tvTotalAmount. Dùng findViewById trong onCreate.
Listener cho SeekBar
seekBarTip.setOnSeekBarChangeListener với 3 method override. Chỉ quan tâm onProgressChanged:
- Log giá trị progress
- Cập nhật
tvTipPercentLabel:"${progress}%" - Gọi
computeTipAndTotal()
Khởi tạo mặc định: initialTipPercent = 15, set progress và label lúc đầu.
Listener cho EditText
etBaseAmount.addTextChangedListener implement TextWatcher. Chỉ dùng afterTextChanged:
- Log giá trị nhập
- Gọi
computeTipAndTotal()
Method tính toán
private fun computeTipAndTotal() {
val baseText = etBaseAmount.text.toString()
if (baseText.isEmpty()) {
tvTipAmount.text = ""
tvTotalAmount.text = ""
return
}
val baseAmount = baseText.toDouble()
val tipPercent = seekBarTip.progress.toDouble()
val tipAmount = baseAmount * tipPercent / 100
val totalAmount = baseAmount + tipAmount
tvTipAmount.text = "%.2f".format(tipAmount)
tvTotalAmount.text = "%.2f".format(totalAmount)
}
Xử lý lỗi: Kiểm tra chuỗi rỗng trước khi parse Double để tránh crash khi xóa trắng ô nhập.
Định dạng tiền tệ: Dùng "%.2f".format() để luôn hiển thị 2 chữ số thập phân.
Tính năng nâng cao: Footer, Theme & Animation
Footer cá nhân hóa
Thêm TextView tvFooter ở dưới cùng: "Made with ❤️ by Rahul". Căn giữa ngang, cách dưới 32dp. Style: all caps, font sans-serif-condensed, medium.
Tùy chỉnh màu sắc (Light/Dark Theme)
File quan trọng: AndroidManifest.xml → android:theme="@style/Theme.Tippie".
Theme định nghĩa trong res/values/themes/themes.xml, màu trong colors.xml.
Dùng công cụ Adobe Color chọn bảng màu. Ví dụ: Primary Blue, Darker Blue, Background Blue. Cập nhật colorPrimary, colorPrimaryVariant (status bar), thêm android:colorBackground.
Animation màu cho mô tả % bo
Thêm TextView tvTipDescription dưới SeekBar (margin 8dp, căn giữa ngang, bold).
Logic trong updateTipDescription(tipPercent: Int) dùng when:
val tipDescription = when {
tipPercent in 0..9 -> "Poor"
tipPercent in 10..14 -> "Acceptable"
tipPercent in 15..19 -> "Good"
tipPercent in 20..24 -> "Great"
else -> "Amazing"
}
tvTipDescription.text = tipDescription
Gọi trong onCreate với initialTipPercent và trong onProgressChanged.
Interpolation màu (RGB Evaluator): Màu chuyển dần từ đỏ (xấu) → xanh lá (tốt) theo % bo.
val fraction = tipPercent / seekBarTip.max.toFloat()
val color = ArgbEvaluator().evaluate(
fraction,
ContextCompat.getColor(this, R.color.colorWorstTip),
ContextCompat.getColor(this, R.color.colorBestTip)
) as Int
tvTipDescription.setTextColor(color)
Kết quả: Text mô tả đổi màu mượt mà từ đỏ → vàng → xanh khi kéo SeekBar.
Kết luận & Mở rộng
App đã hoàn chỉnh: tính toán realtime, không crash khi xóa input, định dạng tiền tệ chuẩn, footer, theme tùy chỉnh, animation màu sắc.
Ý tưởng mở rộng:
- Chia bill cho N người
- Nút làm tròn số tiền
- Cải tiến UI/UX, màu sắc
Bạn có thể xuất bản app này lên Play Store. Chúc bạn thành công trên con đường phát triển Android!