Giao diện tĩnh (static UI) và giao diện động (dynamic UI)
Trong bài trước, chúng ta đã tìm hiểu cách tạo giao diện người dùng với công cụ trực quan (Design) và mã XML (Text). Trong thực tế, chúng ta dành phần lớn thời gian thiết kế giao diện bằng một trong hai cách thức trên, tuy nhiên, sẽ như thế nào nếu một giao diện chỉ xuất hiện khi người dùng nhấn chuột vào một button nào đó?
Có hai hình thức giao diện: giao diện tĩnh (static UI) và giao diện động (dynamic UI). Giao diện tĩnh là giao diện mặc định của ứng dụng khi ứng dụng này được tải đến thiết bị. Với giao diện tĩnh, cách thức thiết kế hiệu quả nhất là dùng công cụ trực quan hay mã XML. Giao diện động, ở một khía cạnh khác, là giao diện xuất hiện khi có sự tương tác từ người dùng hay hệ thống trong quá trình ứng dụng thực thi và dùng mã Java để thiết kế giao diện này sẽ rất hiệu quả.
Thiết kế giao diện với Java
Tạo các views
Như chúng ta đã biết từ bài trước, một giao diện người dùng được tạo từ các views (khái niệm bao hàm cả viewgroups và layouts) như Button, TextView, ConstraintLayout, v.v.
View đầu tiên được thêm đến giao diện gọi là view gốc (root view) – thường là một layout chứa các views còn lại của giao diện.
Dưới gốc độ Java, mỗi view là một lớp con của lớp android.view.View. Việc tạo ra một view trên giao diện chính là tạo ra một thể hiện (instance) của lớp view tương ứng. view đầu tiên được hiển thị đến người dùng nhờ phương thức setContentView; các views khác được thêm đến view gốc nhờ phương thức addView() của đối tượng view gốc này.
Mỗi view có nhiều thuộc tính (properties) như ID, Text, TextSize, TextColor, BackgroundColor, v.v. và việc sử dụng hay cung cấp các giá trị của các thuộc tính của một view thông qua các phương thức dạng get hay set tương ứng. Ví dụ phương thức setBackgroundColor() dùng để thiết lập màu nền cho một view (như Button) và getBackgroundColor() dùng để lấy màu nền của view đó.
Và điều quan trọng cần nhớ rằng, các views trên cùng một giao diện luôn có mối quan hệ mật thiết với nhau như quan hệ anh-em, quan hệ cha-con,…Mối quan hệ giữa các views hay cách thức các views xuất hiện được kiểm soát thông quan các layouts. Đối tượng LayoutParams (ViewGroup.LayoutParams) có các lớp con tương ứng với các layout như RelativeLayout.LayoutParams, GridLayout.LayoutParams, v.v. có vai trò quan trọng trong việc kiểm soát các views trong các layouts tương ứng thông qua các quy định hay luật lệ (rules). LayoutParams được thêm đến các view như là các tham số hay sử dụng phương thức setLayoutParams(). Các luật lệ của một đối tượng LayoutParams được thiết lập nhờ phương thức addRule() với các layout như RelativeLayout. Với layout đặc biệt như ConstraintLayout chúng ta phải kết hợp với đối tượng ConstraintSet sẽ được minh họa qua ứng dụng dưới đây của chúng ta.
Thêm các views dùng Java
Chúng ta đã đề cập, một cách lý thuyết, cách thức tạo giao diện người dùng bằng Java và bây giờ chúng ta sẽ minh họa cách xây dựng một giao diện thông qua tạo một ứng dụng Android.
Với các bước tương tự khi tạo dự án LayoutSample trong bài trước, chúng ta tạo ra dự án mới tên JavaLayout, tên Activity là JavaLayoutActivity và tên layout tương ứng là activity_java_layout.
Mở tập tin JavaLayoutActivity.java trong thư mục app > java > com.ngocminhtran.javalayout. Mã Java của tập tin lúc này:
package com.ngocminhtran.javalayout; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class JavaLayoutActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_java_layout); } }
Vì chúng ta cần tạo một giao diện mới hoàn toàn bằng Java nên chúng ta sẽ không dùng giao diện trong tập tin activity_java_layout.xml bằng cách xóa dòng mã sau trong phương thức onCreate:
setContentView(R.layout.activity_java_layout);
Bây giờ chúng ta sẽ thêm view đầu tiên hay view gốc là một layout kiểu ConstraintLayout. Đoạn mã tạo thể hiện cho đối tượng ConstraintLayout trong phương thức onCreate:
ConstraintLayout myLayout = new ConstraintLayout(this);
Kế tiếp chúng ta sẽ thêm một Button (view con) đến ConstraintLayout nhờ phương thức addView của đối tượng myLayout. Tạo một thể hiện từ lớp Button:
Button myLayout = new Button(this);
Lưu ý, khi chúng ta dùng lớp Button có thể phát sinh lỗi như sau trong Android Studio:
Nguyên nhân là chúng ta chưa tham chiếu lớp Button đến dự án. Xử lý đơn giản bằng cách (theo gợi ý từ Android Studio) đặt con trỏ chuột trên từ Button và nhấn tổ hợp phím Alt + Enter. Lúc này sẽ xuất hiện thêm dòng mã khai báo phía trên:
import android.widget.Button;
Thêm thể hiện Button đến myLayout nhờ phương thức addView:
myLayout.addView(myButton);
Cuối cùng là thể hiện layout đến người dùng bằng phương thức setContentView:
setContentView(myLayout);
Phương thức onCreate lúc này:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_java_layout); ConstraintLayout myLayout = new ConstraintLayout(this); Button myButton = new Button(this); myLayout.addView(myButton); setContentView(myLayout); }
Chạy ứng dụng, kết quả trông như sau:
Thay đổi thuộc tính các views dùng Java
Nhìn giao diện trên không được ấn tượng. Bây giờ giả sử chúng ta muốn Button có dòng chữ Press Me và có màu nền là màu xanh lá cây (green), layout của chúng ta có màu nền là màu vàng (yellow). Các phương thức setText() và setBackgroundColor() của từng đối tượng tương ứng được sử dụng để thiết lập giá trị cho các thuộc tính Text hay BackgroundColor. Đoạn mã trong phương thức onCreate được cập nhật như sau:
ConstraintLayout myLayout = new ConstraintLayout(this); myLayout.setBackgroundColor(Color.YELLOW); Button myButton = new Button(this); myButton.setBackgroundColor(Color.GREEN); myButton.setText("Press Me"); myLayout.addView(myButton); setContentView(myLayout);
Thực thi lại ứng dụng:
Đối tượng LayoutParams
Mặc định, Button của chúng ta sẽ ở vị trí góc trái trên của layout. Chúng ta có thể thay đổi vị trí của Button trong layout, ví dụ đến vị trí giữa màn hình hiện thị, nhưng trước tiên chúng ta sẽ thiết lập quan hệ về kích cỡ (chiều cao và chiều rộng) giữa layout (view cha) và Button (view con) thông qua đối tượng LayoutParams.
Vì layout của chúng ta là ConstraintLayout nên đối tượng LayoutParams tương ứng là ConstraintLayout.LayoutParams được khởi tạo như sau:
ConstraintLayout.LayoutParams buttonParams = new ConstraintLayout.LayoutParams( ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
Hai tham số trong phương thức khởi tạo là chiều cao (height) và chiều rộng (width) của view, trong trường hợp này là Button. Giá trị của các tham số này có thể là:
- WRAP_CONTENT: điều chỉnh kích cỡ view cha vừa khớp với các view con.
- MATCH_PARENT: mở rộng kích cỡ các view con khớp với view cha.
Gán đối tượng LayoutParams đến Button qua phương thức setLayoutParams:
myButton.setLayoutParams(buttonParams);
Kết quả khi chạy ứng dụng:
Chúng ta không thấy sự khác biệt so với trước nhưng bây giờ thay đổi các giá trị từ WRAP_CONTENT thành MATCH_PARENT kết quả sẽ:
Lúc này, kích cỡ của Button sẽ mở rộng cho khớp với kích cỡ layout. Thay đổi các giá trị trở lại thành WRAP_CONTENT.
Thiết lập ID cho các views
Các đối tượng views như ConstraintLayout, Button, v.v. được xác định thông qua các giá trị ID của chúng (giống như mỗi người phải có một chứng minh nhân dân). Thiết lập ID cho views bằng phương thức setId và sử dụng ID bằng phương thức getId nhưng bước đầu tiên là phải khai báo các ID như là các tài nguyên giá trị của dự án Android. Chúng ta sẽ khai báo ID của ConstraintLayout là myLayoutId và của Button là myButtonId đến dự án như sau:
Chọn và nhấp chuột phải vào thư mục app > res > values trong cửa sổ Project. Chọn New > Values resource file
Trong hộp thoại New Resource file nhập id.xml trong mục File name:
Nhấp OK. Bây giờ trong thư mục values sẽ xuất hiện tập tin id.xml:
Nhấp đôi chuột để mở tập tin này và thêm các dòng mã như sau:
<?xml version="1.0" encoding="utf-8"?> <resources> <item name="myButtonId" type="id"/> <item name="myLayoutId" type="id"/> </resources>
Chúng ta đã khai báo ID của Button và ConstraintLayout nhờ phần tử <item> với thuộc tính name là giá trị của item và thuộc tính type là kiểu item và trong trường hợp này là id.
Khi đã khai báo thành công các ID đến dự án, chúng ta sẽ gán các ID này đến các đối tượng Button và ConstraintLayout như sau:
myLayout.setId(R.id.myLayoutId); myButton.setId(R.id.myButtonId);
Định vị các views trong ConstraintLayout với đối tượng ConstraintSet
Để định vị các views trong ConstraintLayout chúng ta dùng đối tượng ConstraintSet. Khai báo một thể hiện ConstraintSet:
ConstraintSet constraintSet = new ConstraintSet();
Kế tiếp, sao chép tất cả các tham số từ ConstraintLayout đến đối tượng ConstraintSet dùng phương thức clone:
constraintSet.clone(myLayout);
Thiết lập kết nối vị trí giữa view con (Button) đến view cha (ConstraintLayout) dùng phương thức connect. Ví dụ thiết lập khoảng cách từ Button đến mép trên layout là 60 pixels và khoảng cách đến mép trái layout là 60 pixels như sau:
constraintSet.connect(myButton.getId(), ConstraintSet.TOP, myLayout.getId(), ConstraintSet.TOP, 60); constraintSet.connect(myButton.getId(), ConstraintSet.LEFT, myLayout.getId(), ConstraintSet.LEFT, 60);
Cuối cùng là gán đối tượng ConstraintSet đến đối tượng ConstraintLayout dùng phương thức applyTo:
constraintSet.applyTo(myLayout);
Kết quả khi chạy ứng dụng:
Trong trường hợp muốn đưa Button đến giữa màn hình chúng ta có thể dùng các phương thức đặc biệt là centerHorizontally và centerVertically:
constraintSet.centerHorizontally(myButton.getId(), myLayout.getId()); constraintSet.centerVertically(myButton.getId(), myLayout.getId());
Kết quả:
Bây giờ, giả sử chúng ta muốn đưa thêm một view mới, ví dụ EditText, đến layout. Các bước được tiến hành tương tự với đối tượng Button và ConstraintLayout.
Source code Java cho bài viết có thể tham khảo tại GitHub.
Tổng kết
Trong bài này chúng ta đã làm quen với cách thiết giao diện người dùng Android sử dụng Java. Chúng ta cũng đã làm quen với ConstraintLayout – một layout được dùng mặc định kể từ Android Studio 3.0. Đây là một layout thú vị và chúng ta sẽ tìm hiểu kĩ hơn trong bài sau.
Ý kiến bài viết