1. Giới thiệu
Khi dùng được trên điện thoại tiêu chuẩn, ứng dụng của bạn sẽ dùng được trên các thiết bị có màn hình lớn, chẳng hạn như máy tính bảng, thiết bị có thể gập lại và thiết bị ChromeOS.
Khi dùng ứng dụng trên màn hình lớn, người dùng mong đợi sẽ có trải nghiệm tương đương hoặc tốt hơn so với khi dùng trên màn hình nhỏ.
Người dùng cũng có nhiều khả năng sẽ dùng ứng dụng của bạn với một thiết bị trỏ (chẳng hạn như chuột hoặc bàn di chuột) và bàn phím thực trên thiết bị có màn hình lớn. Một số thiết bị có màn hình lớn (ví dụ: Chromebook) có thiết bị trỏ và bàn phím thực. Những thiết bị khác kết nối với bàn phím và thiết bị trỏ qua cổng USB hoặc Bluetooth. Khi dùng ứng dụng với thiết bị trỏ và bàn phím thực, người dùng mong đợi có thể hoàn thành cùng các tác vụ như khi dùng màn hình cảm ứng.
Điều kiện tiên quyết
- Có kinh nghiệm dùng Compose để tạo ứng dụng
- Có kiến thức cơ bản về Kotlin, bao gồm cả lambda và coroutine
Sản phẩm bạn sẽ tạo ra
Bạn sẽ thêm tính năng hỗ trợ cho chuột và bàn phím thực vào ứng dụng được tạo bằng Jetpack Compose. Các bước thực hiện như sau:
- Kiểm tra ứng dụng theo các tiêu chí nêu trong nguyên tắc về chất lượng ứng dụng cho màn hình lớn
- Xem xét kết quả kiểm tra và tìm ra các vấn đề liên quan đến tính năng hỗ trợ chuột và bàn phím thực
- Khắc phục vấn đề
Cụ thể hơn, bạn sẽ cập nhật các tính năng sau đây cho ứng dụng mẫu:
- Điều hướng bằng bàn phím
- Phím tắt để cuộn xuống và cuộn lên
- Trình trợ giúp phím tắt
Kiến thức bạn sẽ học được
- Cách kiểm tra ứng dụng để hỗ trợ thiết bị ảo
- Cách dùng Compose để quản lý tính năng điều hướng bằng bàn phím
- Cách dùng Compose để thêm phím tắt
Bạn cần có
- Android Studio Hedgehog trở lên
- Bất cứ thiết bị nào sau đây để chạy ứng dụng mẫu:
- Một thiết bị có màn hình lớn cùng với chuột và bàn phím thực
- Một thiết bị Android ảo có cấu hình thuộc danh mục định nghĩa Thiết bị máy tính
2. Thiết lập
- Nhân bản kho lưu trữ large-screen-codelabs trên GitHub:
git clone https://github.com/android/large-screen-codelabs
Ngoài ra, bạn có thể tải xuống và giải nén tệp zip trong kho lưu trữ large-screen-codelabs. Cách làm như sau:
- Chuyển đến thư mục
add-keyboard-and-mouse-support-with-compose
. - Trong Android Studio, hãy mở dự án. Thư mục
add-keyboard-and-cursor-support-with-compose
chứa một dự án. - Nếu bạn không dùng thiết bị có thể gập lại hay máy tính bảng Android hoặc thiết bị ChromeOS có chuột và bàn phím thực, hãy mở Device Manager (Trình quản lý thiết bị) trong Android Studio rồi tạo thiết bị ảo bất kỳ trong danh mục Desktop (Máy tính).
3. Khám phá ứng dụng
Ứng dụng mẫu hiển thị một danh sách các bài viết. Người dùng có thể đọc một bài viết đã chọn trong danh sách này.
Ứng dụng cập nhật bố cục theo cách thích ứng với chiều rộng cửa sổ của ứng dụng. Có 3 lớp cửa sổ để phân loại chiều rộng cửa sổ của ứng dụng, đó là: thu gọn, trung bình và mở rộng.
Bố cục cho lớp kích thước cửa sổ thu gọn và trung bình
Ứng dụng dùng bố cục một ngăn. Trên màn hình chính, ứng dụng hiển thị một danh sách các bài viết. Khi người dùng chọn một bài viết trong danh sách này thì sẽ có hiệu ứng chuyển màn hình và bài viết đó sẽ hiển thị.
Ứng dụng dùng ngăn điều hướng để điều hướng chung.
Bố cục cho lớp kích thước cửa sổ mở rộng
Ứng dụng dùng bố cục danh sách-chi tiết. Ngăn danh sách hiện danh sách bài viết. Ngăn chi tiết hiện bài viết đã chọn.
Ứng dụng dùng thanh điều hướng để điều hướng chung.
4. Thông tin khái quát
Compose cung cấp nhiều API để giúp ứng dụng của bạn xử lý các sự kiện từ chuột và bàn phím thực. Một số API cho phép xử lý sự kiện chuột và bàn phím tương tự như xử lý sự kiện chạm. Do đó, trong nhiều trường hợp sử dụng, ứng dụng sẽ hỗ trợ chuột và bàn phím thực mà bạn không cần phải làm gì thêm.
Ví dụ điển hình là đối tượng sửa đổi clickable
giúp phát hiện lượt nhấp. Thao tác nhấn ngón tay được phát hiện là một lượt nhấp. Thao tác nhấp chuột và nhấn phím Enter
cũng được phát hiện là lượt nhấp. Ứng dụng cho phép người dùng tương tác với các thành phần bất kể thiết bị đầu vào nếu phát hiện thấy lượt nhấp thông qua đối tượng sửa đổi clickable
.
Tuy nhiên, mặc dù có sự hỗ trợ của API ở mức cao như vậy, bạn vẫn cần bỏ ra chút công sức để phát triển tính năng hỗ trợ chuột và bàn phím thực. Lý do là bạn cần kiểm thử ứng dụng để tìm ra các trường hợp không như dự kiến. Bạn cũng cần nỗ lực để giảm bớt trở ngại cho người dùng do các đặc điểm của thiết bị, chẳng hạn như:
- Người dùng không biết mình có thể nhấp vào thành phần nào
- Người dùng không thể di chuyển tiêu điểm bàn phím như mong đợi
- Người dùng không thể cuộn lên hoặc xuống khi dùng bàn phím thực
Tiêu điểm bàn phím
Tiêu điểm bàn phím là điểm khác biệt chính giữa hoạt động tương tác với bàn phím thực và các thao tác chạm vào màn hình. Người dùng có thể nhấn vào thành phần bất kỳ trên màn hình, bất kể vị trí của thành phần mà họ đã chạm vào trước đó. Ngược lại, khi dùng bàn phím, người dùng cần chọn thành phần để tương tác trước khi bắt đầu tương tác thực tế. Lựa chọn này có tên là tiêu điểm bàn phím.
Người dùng có thể di chuyển tiêu điểm bàn phím bằng phím Tab
và các phím định hướng (hoặc mũi tên). Theo mặc định, tiêu điểm bàn phím chỉ di chuyển đến các thành phần lân cận.
Hầu hết trở ngại đối với bàn phím thực đều liên quan đến tiêu điểm bàn phím. Sau đây là danh sách các vấn đề thường gặp:
- Người dùng không thể di chuyển tiêu điểm bàn phím đến thành phần mà họ muốn tương tác
- Thành phần không phát hiện thấy lượt nhấp khi người dùng nhấn phím
Enter
- Tiêu điểm bàn phím di chuyển khác với mong muốn của người dùng.
- Người dùng cần nhấn nhiều phím để di chuyển tiêu điểm bàn phím đến thành phần mà họ muốn tương tác sau khi chuyển đổi màn hình.
- Người dùng không thể xác định thành phần nào có tiêu điểm bàn phím vì không có dấu hiệu trực quan chỉ ra tiêu điểm bàn phím
- Người dùng không thể xác định thành phần mặc định có tiêu điểm khi điều hướng đến một màn hình mới
Chỉ báo trực quan cho tiêu điểm bàn phím đóng vai trò rất quan trọng. Nếu không, người dùng có thể bị lạc trong ứng dụng và không hiểu được điều gì xảy ra khi nhấn phím Enter
. Cách làm nổi bật thành phần là một dấu hiệu trực quan điển hình để chỉ ra tiêu điểm bàn phím. Người dùng có thể thấy nút ở thẻ bên phải có tiêu điểm bàn phím vì nút này được làm nổi bật.
Phím tắt
Người dùng mong muốn có thể sử dụng các phím tắt thông dụng khi dùng ứng dụng của bạn với bàn phím thực. Theo mặc định, một số thành phần hỗ trợ các phím tắt tiêu chuẩn. BasicTextField
là một ví dụ điển hình. Thành phần này cho phép người dùng sử dụng các phím tắt tiêu chuẩn để chỉnh sửa văn bản, bao gồm:
Phím tắt | Tính năng |
| Sao chép |
| Cắt |
| Dán |
| Huỷ |
| Làm lại |
Ứng dụng có thể xử lý các sự kiện chính để thêm phím tắt. Bạn có thể giám sát các sự kiện chính thông qua đối tượng sửa đổi onKeyEvent
và onPreviewKeyEvent
.
Thiết bị trỏ: Chuột, bàn di chuột và bút cảm ứng
Ứng dụng của bạn có thể xử lý chuột, bàn di chuột và bút cảm ứng theo cùng một cách. Thao tác nhấn vào bàn di chuột được phát hiện là một lượt nhấp thông qua đối tượng sửa đổi clickable
. Thao tác nhấn bằng bút cảm ứng cũng được phát hiện là một lượt nhấp.
Giao diện ứng dụng phải cho người dùng biết liệu họ có thể nhấp vào một thành phần hay không. Đó là lý do trạng thái di chuột được đề cập đến trong nguyên tắc về chất lượng ứng dụng cho màn hình lớn.
Theo mặc định, các thành phần Material 3 hỗ trợ trạng thái di chuột. Material 3 cung cấp hiệu ứng trực quan cho trạng thái di chuột. Bạn có thể áp dụng hiệu ứng này cho thành phần tương tác thông qua đối tượng sửa đổi indication
.
Thao tác cuộn
Theo mặc định, các vùng chứa có thể cuộn hỗ trợ thao tác cuộn con lăn chuột, cử chỉ cuộn trên bàn di chuột, cũng như thao tác cuộn bằng các phím Page up
và Page down
.
Đối với thao tác cuộn ngang, sẽ rất dễ cho người dùng nếu ứng dụng của bạn hiện các nút mũi tên trái và phải ở trạng thái di chuột, nhờ vậy, người dùng có thể cuộn nội dung bằng cách nhấp vào các nút đó.
Cấu hình thay đổi do việc tháo lắp thiết bị
Người dùng có thể lắp hoặc tháo chuột và bàn phím trong khi ứng dụng của bạn đang chạy. Người dùng có thể kết nối bàn phím thực khi thấy một trường văn bản cần nhập lượng lớn nội dung. Chuột kết nối qua Bluetooth sẽ ngắt kết nối khi chuột chuyển sang chế độ ngủ. Bàn phím kết nối qua USB có thể bị tháo rời do vô tình.
Hoạt động lắp hoặc tháo phần cứng ngoại vi sẽ dẫn đến các thay đổi về cấu hình. Ứng dụng nên giữ nguyên trạng thái trong suốt quá trình thay đổi cấu hình. Để biết thêm thông tin, hãy xem bài viết Lưu trạng thái giao diện người dùng.
5. Kiểm tra ứng dụng mẫu dùng bàn phím và chuột
Để bắt đầu phát triển tính năng hỗ trợ chuột và bàn phím thực, hãy khởi động ứng dụng mẫu và xác nhận những thông tin sau đây:
- Người dùng phải có thể di chuyển tiêu điểm bàn phím đến mọi thành phần tương tác
- Người dùng phải có thể "nhấp" vào thành phần được lấy làm tâm điểm bằng phím
Enter
- Các thành phần tương tác phải hiện chỉ báo khi lấy tiêu điểm bàn phím
- Tâm điểm bàn phím di chuyển theo mong đợi của người dùng (tức là theo quy ước đã thiết lập) khi dùng phím
Tab
,Shift+Tab
và các phím định hướng (mũi tên) - Các thành phần tương tác phải có một trạng thái di chuột
- Người dùng phải có thể nhấp vào các thành phần tương tác
- Trình đơn theo bối cảnh xuất hiện khi có lượt nhấp chuột phải (nhấp vào nút điều khiển phụ) vào các thành phần thích hợp, chẳng hạn như những thành phần mà trình đơn theo bối cảnh sẽ xuất hiện khi nhấn giữ hoặc chọn văn bản
Bạn nên xem hết tất cả các mục trong lớp học lập trình này 2 lần, trong đó: 1 lần cho bố cục một ngăn và 1 lần cho bố cục danh sách-chi tiết.
Vấn đề cần khắc phục trong lớp học lập trình này
Bạn sẽ phát hiện thấy các vấn đề. Trong lớp học lập trình này, bạn sẽ khắc phục những vấn đề sau đây:
- Người dùng không thể đọc toàn bộ bài viết nếu chỉ dùng bàn phím thực vì không thể cuộn bài viết xuống
- Người dùng không thể xác định liệu ngăn chi tiết có tiêu điểm bàn phím hay không
6. Cho phép người dùng đọc toàn bộ bài viết trong ngăn chi tiết
Ngăn chi tiết hiện bài viết đã chọn. Một số bài viết quá dài nên không đọc được toàn bộ bài viết mà không cần cuộn. Tuy nhiên, người dùng không thể cuộn bài viết lên và xuống chỉ bằng bàn phím thực.
Vùng chứa có thể cuộn (chẳng hạn như LazyColumn
) cho phép người dùng cuộn xuống bằng phím Page down
. Căn nguyên của vấn đề này là do người dùng không thể di chuyển tiêu điểm bàn phím đến ngăn chi tiết.
Thành phần phải có khả năng lấy tâm điểm bàn phím thì mới nhận được sự kiện từ bàn phím. Đối tượng sửa đổi focusable
cho phép thành phần đã sửa đổi lấy tâm điểm bàn phím.
Để khắc phục vấn đề nêu trên, hãy làm theo các bước sau đây:
- Truy cập vào hàm có khả năng kết hợp
PostContent
trong tệpui/article/PostContent.kt
- Dùng đối tượng sửa đổi
focusable
để sửa đổi hàm có khả năng kết hợpLazyColumn
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PostContent(
post: Post,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
state: LazyListState = rememberLazyListState(),
coroutineScope: CoroutineScope = rememberCoroutineScope(),
focusRequester: FocusRequester = remember { FocusRequester() },
header: (@Composable () -> Unit)? = null
) {
LazyColumn(
contentPadding = contentPadding,
modifier = modifier
.padding(horizontal = defaultSpacerSize)
.focusable(),
state = state,
) {
// Code to layout the selected article.
}
}
Chỉ ra bài viết có tâm điểm bàn phím
Giờ đây, người dùng có thể đọc toàn bộ bài viết khi dùng phím Page down
để cuộn xuống dưới bài viết. Tuy nhiên, rất khó để biết được liệu thành phần PostContent
có tiêu điểm bàn phím hay không vì chẳng có hiệu ứng trực quan nào chỉ ra điều đó.
Ứng dụng của bạn có thể liên kết Indication
với các thành phần để chỉ ra tiêu điểm bàn phím một cách trực quan. Chỉ báo sẽ tạo một đối tượng để hiển thị các hiệu ứng trực quan theo hoạt động tương tác. Ví dụ: Chỉ báo mặc định cho Material 3 là làm nổi bật thành phần khi thành phần đó có tiêu điểm bàn phím.
Ứng dụng mẫu có một Indication
tên là BorderIndication
. Chỉ báo này cho thấy một đường bên cạnh thành phần có tiêu điểm bàn phím (như trong ảnh chụp màn hình sau đây). Mã được lưu trữ trong tệp ui/components/BorderIndication.kt
.
Để thành phần kết hợp PostConent
cho thấy BorderIndication
khi có tiêu điểm bàn phím, hãy làm theo các bước sau đây:
- Truy cập vào hàm có khả năng kết hợp
PostContent
trong tệpui/article/PostContent.kt
- Khai báo giá trị
interactionSource
được liên kết với giá trị trả về của hàmremember()
- Gọi hàm
MutableInteractionSource()
trong hàmremember()
để đối tượngMutableInteractionSource
đã tạo được liên kết với giá trịinteractionSource
- Truyền giá trị
interactionSource
vào đối tượng sửa đổifocusable
thông qua tham số InteractionSource - Thay đổi đối tượng sửa đổi của thành phần kết hợp
PostContent
để gọi đối tượng sửa đổifocusable
sau khi gọi đối tượng sửa đổiindication
- Truyền giá trị
interactionSource
và giá trị mà hàmBorderIndication
trả về vào đối tượng sửa đổi chỉ báo
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PostContent(
post: Post,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
state: LazyListState = rememberLazyListState(),
coroutineScope: CoroutineScope = rememberCoroutineScope(),
focusRequester: FocusRequester = remember { FocusRequester() },
header: (@Composable () -> Unit)? = null
) {
val interactionSource = remember { MutableInteractionSource() }
LazyColumn(
contentPadding = contentPadding,
modifier = modifier
.padding(horizontal = defaultSpacerSize)
.indication(interactionSource, BorderIndication())
.focusable(interactionSource = interactionSource),
state = state,
) {
// Code to layout the selected article.
}
}
Thêm phím tắt để cuộn lên và xuống
Đây là một tính năng phổ biến cho phép người dùng cuộn lên và xuống bằng Spacebar
. Ứng dụng của bạn có thể triển khai tính năng này bằng cách thêm phím tắt như bảng sau đây:
Phím tắt | Tính năng |
| Cuộn bài viết xuống |
| Cuộn bài viết lên |
Đối tượng sửa đổi onKeyEvent
cho phép ứng dụng xử lý các sự kiện chính xảy ra trên một thành phần đã sửa đổi. Đối tượng sửa đổi này lấy một hàm lambda do đối tượng KeyEvent
gọi để mô tả sự kiện chính. Hàm lambda đó sẽ trả về một giá trị Boolean
cho biết liệu sự kiện chính có được sử dụng hay không.
Vị trí cuộn của LazyColumn
và LazyRow
được ghi lại trong đối tượng LazyListState
. Ứng dụng có thể kích hoạt tính năng cuộn bằng cách gọi phương thức tạm ngưng animateScrollBy()
qua đối tượng LazyListState
. Phương thức này sẽ cuộn LazyColumn
xuống theo số lượng pixel được chỉ định. Khi hàm tạm ngưng được gọi cùng với một giá trị âm có độ chính xác đơn, hàm này sẽ cuộn LazyColumn
lên.
Để triển khai những phím tắt này, hãy làm theo các bước sau đây:
- Truy cập vào hàm có khả năng kết hợp
PostContent
trong tệpui/article/PostContent.kt
- Dùng đối tượng sửa đổi
onKeyEvent
để sửa đổi hàm có khả năng kết hợpLazyColumn
- Thêm một biểu thức
if
vào hàm lambda được truyền vào đối tượng sửa đổionKeyEvent
như sau:
- Trả về
true
nếu thoả mãn các điều kiện sau đây: - Phím
Spacebar
được nhấn. Bạn có thể phát hiện phím này bằng cách kiểm tra xem thuộc tínhtype
có phải làKeyType.KeyDown
và thuộc tínhkey
có phải làKey.Spacebar
hay không - Thuộc tính
isCtrlPressed
là false để đảm bảo phímCtrl
không được nhấn - Thuộc tính
isAltPressed
là false để đảm bảo phímAlt
không được nhấn - Thuộc tính
isMetaPressed
là false để đảm bảo phímMeta
không được nhấn (xem ghi chú) - Nếu không, hãy trả về
false
- Xác định mức cuộn khi nhấn phím
Spacebar
như sau:
-0.4f
khi nhấn phímShift
(được mô tả bằng thuộc tínhisShiftPressed
của đối tượngKeyEvent
cụ thể)- Nếu không thì là
0.4f
- Gọi phương thức
launch()
quacoroutineScope
(tham số của hàm có khả năng kết hợpPostContent
) - Tính mức cuộn thực tế bằng cách nhân mức cuộn tương đối đã tính ở bước trước với thuộc tính
state.layoutInfo.viewportSize.height
trong tham số lambda của phương thứclaunch
. Thuộc tính này biểu thị chiều cao củaLazyColumn
được gọi trong hàm có khả năng kết hợpPostContent
. - Gọi phương thức
state.animateScrollBy()
trong hàm lambda cho phương thứclaunch()
để kích hoạt thao tác cuộn dọc
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PostContent(
post: Post,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
state: LazyListState = rememberLazyListState(),
coroutineScope: CoroutineScope = rememberCoroutineScope(),
focusRequester: FocusRequester = remember { FocusRequester() },
header: (@Composable () -> Unit)? = null
) {
val interactionSource = remember { MutableInteractionSource() }
LazyColumn(
contentPadding = contentPadding,
modifier = modifier
.padding(horizontal = defaultSpacerSize)
.onKeyEvent {
if (
it.type == KeyEventType.KeyDown &&
it.key == Key.Spacebar &&
!it.isCtrlPressed &&
!it.isAltPressed &&
!it.isMetaPressed
) {
val relativeAmount = if (it.isShiftPressed) {
-0.4f
} else {
0.4f
}
coroutineScope.launch {
state.animateScrollBy(relativeAmount * state.layoutInfo.viewportSize.height)
}
true
} else {
false
}
}
.indication(interactionSource, BorderIndication())
.focusable(interactionSource = interactionSource),
state = state,
) {
// Code to layout the selected article.
}
}
Thông báo cho người dùng về phím tắt
Người dùng sẽ không thể khai thác tối đa bàn phím đã thêm nếu không biết các phím tắt. Ứng dụng của bạn có thể thông báo cho người dùng về các phím tắt hiện có thông qua trình trợ giúp phím tắt trên giao diện người dùng hệ thống của Android. Người dùng có thể sử dụng tổ hợp phím Meta+/
để mở trình trợ giúp phím tắt này.
Ứng dụng sẽ ghi đè phương thức onProvideKeyboardShortcuts()
trong hoạt động chính của ứng dụng để cung cấp danh sách phím tắt cho trình trợ giúp phím tắt.
Cụ thể hơn, ứng dụng sẽ cung cấp một số đối tượng KeyboardShortcutGroup
bằng cách thêm các đối tượng đó vào danh sách có thể thay đổi được truyền vào onProvideKeyboardShortcuts()
. Mỗi KeyboardShortcutGroup
biểu thị một danh mục phím tắt được đặt tên, cho phép ứng dụng nhóm các phím tắt có sẵn theo mục đích hoặc bối cảnh.
Ứng dụng mẫu có 2 phím tắt là Spacebar
và Shift+Spacebar
.
Để 2 phím tắt này hiện trong trình trợ giúp phím tắt, hãy làm theo các bước sau đây:
- Mở tệp
MainActivity.kt
- Ghi đè phương thức
onProvideKeyboardShortcuts()
trongMainActivity
- Đảm bảo phiên bản SDK Android là Android 7.0 (API cấp 24) trở lên để có thể sử dụng trình trợ giúp phím tắt.
- Xác nhận rằng tham số đầu tiên của phương thức không phải là
null
- Tạo một đối tượng
KeyboardShortcutInfo
cho phímSpacebar
bằng các tham số sau đây:
- Nội dung mô tả
android.view.KeyEvent.KEYCODE_SPACE
0
(cho biết không có đối tượng sửa đổi nào)
- Tạo một
KeyboardShortcutInfo
khác choShift+Spacebar
bằng các tham số sau đây:
- Nội dung mô tả
android.view.KeyEvent.KEYCODE_SPACE
android.view.KeyEvent.META_SHIFT_ON
- Tạo một danh sách không thể thay đổi chứa 2 đối tượng
KeyboardShortcutInfo
- Tạo một đối tượng
KeyboardShortcutGroup
bằng các tham số sau đây:
- Tên nhóm ở dạng văn bản
- Danh sách không thể thay đổi ở bước trước
- Thêm đối tượng
KeyboardShortcutGroup
vào danh sách có thể thay đổi được truyền dưới dạng tham số đầu tiên của phương thứconProvideKeyboardShortcuts()
Phương thức bị ghi đè sẽ có dạng như sau:
override fun onProvideKeyboardShortcuts(
data: MutableList<KeyboardShortcutGroup>?,
menu: Menu?,
deviceId: Int
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && data != null) {
val shortcutGroup = KeyboardShortcutGroup(
"To read articles",
listOf(
KeyboardShortcutInfo("Scroll down", KeyEvent.KEYCODE_SPACE, 0), // 0 means no modifier key is pressed
KeyboardShortcutInfo("Scroll up", KeyEvent.KEYCODE_SPACE, KeyEvent.META_SHIFT_ON),
)
)
data.add(shortcutGroup)
}
}
Chạy ứng dụng
Giờ đây, người dùng có thể đọc toàn bộ bài viết ngay cả khi sử dụng phím Spacebar
để cuộn bài viết. Bạn có thể thử bằng cách dùng phím Tab
hoặc các phím định hướng để di chuyển tiêu điểm bàn phím đến bài viết. Bạn có thể thấy thông báo khuyến khích mình nhấn phím Spacebar
.
Trình trợ giúp phím tắt cho thấy 2 phím tắt mà bạn đã thêm (nhấn tổ hợp phím Meta+/
). Các phím tắt đã thêm được liệt kê ở thẻ Current app (Ứng dụng hiện tại).
7. Tăng tốc độ điều hướng bằng bàn phím trong ngăn chi tiết
Khi ứng dụng đang chạy trong lớp kích thước cửa sổ mở rộng, người dùng cần nhấn phím Tab
nhiều lần để di chuyển tiêu điểm bàn phím đến ngăn chi tiết. Với phím định hướng bên phải, người dùng có thể di chuyển tiêu điểm bàn phím từ danh sách bài viết sang bài viết chỉ bằng một thao tác. Tuy nhiên, họ vẫn cần di chuyển tiêu điểm bàn phím. Tiêu điểm ban đầu không hỗ trợ mục tiêu chính của người dùng là đọc các bài viết.
Ứng dụng của bạn có thể yêu cầu di chuyển tiêu điểm bàn phím đến thành phần cụ thể thông qua đối tượng FocusRequester
. Đối tượng sửa đổi focusRequester
liên kết một đối tượng FocusRequester
với thành phần đã sửa đổi. Ứng dụng có thể gọi phương thức requestFocus()
của đối tượng FocusRequester
để gửi yêu cầu thực tế về việc di chuyển tiêu điểm.
Gửi yêu cầu di chuyển tiêu điểm bàn phím là một hệ quả phụ của thành phần này. Ứng dụng phải gọi phương thức theo cách phù hợp thông qua hàm LaunchedEffect
.
Để đặt thành phần kết hợp PostContent
sẽ lấy tiêu điểm bàn phím khi người dùng chọn một bài viết trong danh sách bài viết, hãy làm theo các bước sau đây:
- Truy cập vào hàm có khả năng kết hợp
PostContent
trong tệpui/article/
PostContent.kt
. - Liên kết giá trị
focusRequester
với hàm có khả năng kết hợpLazyColumn
thông qua đối tượng sửa đổifocusRequester
. Giá trị focusRequester được chỉ định làm tham số không bắt buộc của hàm có khả năng kết hợpPostContent
. - Gọi
LaunchedEffect
bằngpost
(tham số đầu tiên của hàm có khả năng kết hợpPostContent
) để hàm lambda đã truyền được gọi khi người dùng chọn một bài viết. - Gọi phương thức
focusRequester.requestFocus()
trong hàm lambda được truyền vào hàmLaunchedEffect
.
Thành phần kết hợp PostContent
sau khi cập nhật sẽ có dạng như sau:
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PostContent(
post: Post,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
state: LazyListState = rememberLazyListState(),
coroutineScope: CoroutineScope = rememberCoroutineScope(),
focusRequester: FocusRequester = remember { FocusRequester() },
header: (@Composable () -> Unit)? = null
) {
val interactionSource = remember { MutableInteractionSource() }
LaunchedEffect(post) {
focusRequester.requestFocus()
}
LazyColumn(
contentPadding = contentPadding,
modifier = modifier
.padding(horizontal = defaultSpacerSize)
.onKeyEvent {
if (it.type == KeyEventType.KeyDown && it.key == Key.Spacebar) {
val relativeAmount = if (it.isShiftPressed) {
-0.4f
} else {
0.4f
}
coroutineScope.launch {
state.animateScrollBy(relativeAmount * state.layoutInfo.viewportSize.height)
}
true
} else {
false
}
}
.focusRequester(focusRequester),
.indication(interactionSource, BorderIndication())
.focusable(interactionSource = interactionSource),
state = state,
) {
// Code to layout the selected article.
}
}
Chạy ứng dụng
Giờ đây, tiêu điểm bàn phím sẽ di chuyển đến bài viết khi người dùng chọn một bài viết trong danh sách bài viết. Bạn có thể thấy thông báo khuyến khích mình dùng phím Spacebar
để cuộn bài viết xuống khi chọn một bài viết.
8. Xin chúc mừng
Rất tốt! Bạn đã thêm tính năng hỗ trợ chuột và bàn phím thực vào ứng dụng mẫu. Do đó, người dùng có thể chọn một bài viết trong danh sách bài viết và chỉ cần dùng chuột hoặc bàn phím thực để đọc bài viết đã chọn.
Bạn đã tìm hiểu những kiến thức cần thiết sau đây để thêm tính năng hỗ trợ chuột và bàn phím thực:
- Cách kiểm tra xem ứng dụng có hỗ trợ chuột và bàn phím thực hay không, kể cả khi dùng trình mô phỏng
- Cách dùng Compose để quản lý tính năng điều hướng bằng bàn phím
- Cách dùng Compose để thêm phím tắt
Bạn cũng đã sửa đổi mã một chút để thêm tính năng hỗ trợ chuột và bàn phím thực.
Bạn đã sẵn sàng dùng Compose để thêm tính năng hỗ trợ chuột và bàn phím thực vào ứng dụng chính thức rồi đó.
Nếu học hỏi thêm chút nữa, bạn sẽ có thể thêm phím tắt cho các chức năng sau đây:
- Đánh dấu bài viết đã chọn là đã thích.
- Đánh dấu trang bài viết đã chọn.
- Chia sẻ bài viết đã chọn với các ứng dụng khác.