Khả năng tương thích đầu vào trên màn hình lớn

Trên các thiết bị màn hình lớn, người dùng thường tương tác với các ứng dụng bằng cách sử dụng bàn phím, chuột, bàn di chuột, bút cảm ứng hoặc tay điều khiển trò chơi. Để cho phép ứng dụng chấp nhận dữ liệu đầu vào từ các thiết bị ngoại vi, hãy làm như sau:

  • Kiểm thử tính năng hỗ trợ bàn phím cơ bản, chẳng hạn như Ctrl+Z để huỷ, Ctrl+C để sao chép và Ctrl+S để lưu. Hãy xem phần Xử lý thao tác trên bàn phím để biết danh sách phím tắt mặc định.
  • Kiểm thử khả năng hỗ trợ bàn phím nâng cao, ví dụ: điều hướng bằng phím Tab và phím mũi tên, xác nhận mục nhập văn bản bằng phím Enter và phát/tạm dừng bằng phím Dấu cách trong các ứng dụng đa phương tiện.
  • Kiểm thử các hoạt động tương tác cơ bản với chuột, bao gồm cả thao tác nhấp chuột phải để mở trình đơn theo bối cảnh, thay đổi biểu tượng khi di chuột và con lăn chuột hoặc sự kiện cuộn trên bàn di chuột trên các thành phần tuỳ chỉnh.
  • Kiểm thử các thiết bị đầu vào dành riêng cho ứng dụng, chẳng hạn như bút cảm ứng, tay điều khiển trò chơi và bộ điều khiển MIDI của ứng dụng nhạc.
  • Cân nhắc việc hỗ trợ phương thức nhập nâng cao để có thể giúp ứng dụng trở nên nổi bật trong môi trường máy tính; ví dụ: bàn di chuột khi thích hợp cho các ứng dụng DJ, ẩn con trỏ chuột trong các trò chơi và các phím tắt mở rộng cho người dùng thành thạo.

Bàn phím

Cách ứng dụng phản hồi dữ liệu nhập bằng bàn phím góp phần mang lại trải nghiệm người dùng trên màn hình lớn. Có 3 cách nhập bằng bàn phím: di chuyển,tổ hợp phímphím tắt.

Tính năng di chuyển trên bàn phím hiếm khi được triển khai trong các ứng dụng tập trung vào thao tác chạm, nhưng người dùng mong đợi điều này khi họ sử dụng ứng dụng và bàn phím. Điều hướng bằng bàn phím có thể rất cần thiết trên điện thoại, máy tính bảng, thiết bị có thể gập lại và máy tính cho những người dùng có nhu cầu hỗ trợ tiếp cận.

Đối với nhiều ứng dụng, thao tác điều hướng bằng phím mũi tên và phím Tab được khung Android xử lý tự động. Ví dụ: một số thành phần kết hợp có thể lấy tiêu điểm theo mặc định, chẳng hạn như Button hoặc một thành phần kết hợp có đối tượng sửa đổi clickable; hoạt động điều hướng bằng bàn phím thường sẽ hoạt động mà không cần thêm mã nào. Để bật tính năng điều hướng bằng bàn phím cho các thành phần kết hợp tuỳ chỉnh không thể lấy tiêu điểm theo mặc định, hãy thêm đối tượng sửa đổi focusable:

var color by remember { mutableStateOf(Green) }
Box(
    Modifier
        .background(color)
        .onFocusChanged { color = if (it.isFocused) Blue else Green }
        .focusable()
) {
    Text("Focusable 1")
}

Để biết thêm thông tin, hãy xem phần Đặt tiêu điểm cho thành phần kết hợp.

Khi tiêu điểm được bật, khung Android sẽ tạo một mục ánh xạ điều hướng cho mọi thành phần có thể lấy tiêu điểm dựa vào vị trí của chúng. Phương thức này thường hoạt động như dự kiến và bạn không cần phát triển thêm.

Tuy nhiên, Compose không phải lúc nào cũng xác định chính xác mục tiếp theo cho thao tác điều hướng theo thẻ cho các thành phần kết hợp phức tạp như thẻ và danh sách, chẳng hạn như khi một trong các thành phần kết hợp là một thành phần có thể cuộn theo chiều ngang không hiển thị đầy đủ.

Để kiểm soát hành vi lấy tiêu điểm, hãy thêm đối tượng sửa đổi focusGroup vào thành phần kết hợp mẹ của một tập hợp các thành phần kết hợp. Tiêu điểm sẽ di chuyển đến nhóm, sau đó di chuyển qua nhóm trước khi chuyển sang thành phần có thể lấy tiêu điểm tiếp theo, ví dụ:

Row {
    Column(Modifier.focusGroup()) {
        Button({}) { Text("Row1 Col1") }
        Button({}) { Text("Row2 Col1") }
        Button({}) { Text("Row3 Col1") }
    }
    Column(Modifier.focusGroup()) {
        Button({}) { Text("Row1 Col2") }
        Button({}) { Text("Row2 Col2") }
        Button({}) { Text("Row3 Col2") }
    }
}

Để biết thêm thông tin, hãy xem bài viết Cung cấp tính năng điều hướng nhất quán bằng nhóm đối tượng mục tiêu.

Kiểm thử quyền truy cập vào mọi thành phần trên giao diện người dùng của ứng dụng chỉ bằng bàn phím. Người dùng phải truy cập được các thành phần thường dùng mà không cần phải sử dụng chuột hoặc thao tác chạm.

Lưu ý rằng hỗ trợ bàn phím có thể rất cần thiết cho những người dùng có nhu cầu hỗ trợ tiếp cận tính năng.

Thao tác phím

Đối với văn bản nhập bằng bàn phím ảo trên màn hình (IME), chẳng hạn như đối với, TextField,, ứng dụng sẽ hoạt động như dự tính trên các thiết bị màn hình lớn mà nhà phát triển không phải làm gì thêm. Đối với các tổ hợp phím khung không thể đoán trước được, ứng dụng cần phải tự xử lý hành vi. Điều này đặc biệt đúng với các ứng dụng có chế độ xem tuỳ chỉnh.

Một số ví dụ là ứng dụng trò chuyện sử dụng phím Enter để gửi tin nhắn, ứng dụng nghe nhìn bắt đầu và dừng phát bằng Phím cách và các trò chơi điều khiển di chuyển bằng các phím w, a, sd.

Bạn có thể xử lý từng thao tác nhấn phím bằng đối tượng sửa đổi onKeyEvent. Đối tượng này chấp nhận một hàm lambda được gọi khi thành phần đã sửa đổi nhận được một sự kiện nhấn phím. Thuộc tính KeyEvent#type cho phép bạn xác định xem sự kiện đó là một thao tác nhấn phím (KeyDown) hay thả phím (KeyUp):

Box(
    modifier = Modifier.focusable().onKeyEvent {
        if(
            it.type == KeyEventType.KeyUp &&
            it.key == Key.S
        ) {
            doSomething()
            true
        } else {
            false
        }
    }
)  {
    Text("Press S key")
}

Ngoài ra, bạn có thể ghi đè lệnh gọi lại onKeyUp() và thêm hành vi dự kiến cho mỗi mã phím nhận được:

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
    return when (keyCode) {
        KeyEvent.KEYCODE_ENTER -> {
            sendChatMessage()
            true
        }
        KeyEvent.KEYCODE_SPACE -> {
            playOrPauseMedia()
            true
        }
        else -> super.onKeyUp(keyCode, event)
    }
}

Sự kiện onKeyUp xảy ra khi một phím được nhả. Khi dùng lệnh gọi lại này, ứng dụng sẽ không cần phải xử lý nhiều sự kiện onKeyDown nếu một phím được nhấn giữ hoặc thả chậm. Các trò chơi và ứng dụng cần phát hiện thời điểm nhấn phím hoặc liệu người dùng có đang nhấn và giữ phím hay không có thể nghe sự kiện onKeyDown và tự xử lý các sự kiện onKeyDown lặp lại.

Để biết thêm thông tin, hãy xem phần Xử lý thao tác trên bàn phím.

Phím tắt

Bạn nên sử dụng các phím tắt thông thường như Ctrl, Alt, ShiftMeta khi sử dụng bàn phím phần cứng. Nếu một ứng dụng không triển khai phím tắt, người dùng có thể cảm thấy khó chịu với trải nghiệm đó. Người dùng nâng cao cũng đánh giá cao các phím tắt cho các tác vụ thường dùng trong ứng dụng. Phím tắt giúp ứng dụng dễ sử dụng hơn và đem lại sự khác biệt của nó đối với ứng dụng không có phím tắt.

Một số phím tắt phổ biến bao gồm Ctrl+S (lưu), Ctrl+Z (huỷ) và Ctrl+Shift+Z (làm lại). Để biết danh sách phím tắt mặc định, hãy xem phần Xử lý thao tác trên bàn phím.

Đối tượng KeyEvent có các thuộc tính sau cho biết liệu người dùng có nhấn phím sửa đổi hay không:

Ví dụ:

Box(
    Modifier.onKeyEvent {
        if (it.isAltPressed && it.key == Key.A) {
            println("Alt + A is pressed")
            true
        } else {
            false
        }
    }
    .focusable()
)

Để biết thêm thông tin, hãy xem phần dưới đây:

Bút cảm ứng

Nhiều thiết bị màn hình lớn có bút cảm ứng. Các ứng dụng Android xử lý bút cảm ứng dưới dạng thao tác trên màn hình cảm ứng. Một số thiết bị cũng có thể có USB hoặc bảng vẽ Bluetooth, như Wacom Intuos. Các ứng dụng Android có thể nhận đầu vào bằng Bluetooth nhưng không nhận được đầu vào qua USB.

Để truy cập vào các đối tượng MotionEvent của bút cảm ứng, hãy thêm đối tượng sửa đổi pointerInteropFilter vào một bề mặt vẽ. Triển khai một lớp ViewModel bằng một phương thức xử lý các sự kiện chuyển động; truyền phương thức dưới dạng hàm lambda onTouchEvent của đối tượng sửa đổi pointerInteropFilter:

@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
   Canvas(modifier = modifier
       .clipToBounds()
       .pointerInteropFilter {
           viewModel.processMotionEvent(it)
       }

   ) {
       // Drawing code here.
   }
}

Đối tượng MotionEvent chứa thông tin về sự kiện:

Điểm trước đó

Android phân chia hàng loạt sự kiện đầu vào và phân phối chúng cho mỗi khung. Bút cảm ứng có thể báo cáo các sự kiện có tần suất cao hơn nhiều so với màn hình. Khi tạo các ứng dụng vẽ, hãy kiểm tra các sự kiện có thể xảy ra trong quá khứ gần bằng cách sử dụng các API getHistorical:

Tính năng chống tì tay

Khi người dùng vẽ, viết hoặc tương tác với ứng dụng của bạn bằng bút cảm ứng, đôi khi người dùng chạm lòng bàn tay vào màn hình. Sự kiện chạm (được đặt thành ACTION_DOWN hoặc ACTION_POINTER_DOWN) có thể được báo cáo cho ứng dụng của bạn trước khi hệ thống nhận dạng và bỏ qua thao tác chạm vô tình.

Android huỷ các sự kiện chạm tay bằng cách gửi một MotionEvent. Nếu ứng dụng của bạn nhận được ACTION_CANCEL, hãy huỷ cử chỉ. Nếu ứng dụng của bạn nhận được ACTION_POINTER_UP, hãy kiểm tra xem FLAG_CANCELED đã được đặt hay chưa. Nếu có, hãy huỷ cử chỉ.

Đừng chỉ tìm kiếm FLAG_CANCELED. Trên Android 13 (API cấp 33) trở lên, hệ thống sẽ đặt FLAG_CANCELED cho các sự kiện ACTION_CANCEL, nhưng hệ thống không đặt cờ trên các phiên bản Android thấp hơn.

Android 12

Trên Android 12 (API cấp 32) trở xuống, bạn chỉ có thể phát hiện tính năng từ chối cảm ứng bằng lòng bàn tay đối với các sự kiện chạm con trỏ một lần. Nếu thao tác chạm lòng bàn tay là sự kiện con trỏ duy nhất, hệ thống sẽ huỷ sự kiện bằng cách đặt ACTION_CANCEL trên đối tượng sự kiện chuyển động. Nếu các con trỏ khác không hoạt động, hệ thống sẽ đặt ACTION_POINTER_UP, điều này không đủ để phát hiện tính năng từ chối cảm ứng bằng lòng bàn tay.

Android 13

Trên Android 13 (API cấp 33) trở lên, nếu thao tác chạm lòng bàn tay là sự kiện con trỏ duy nhất, hệ thống sẽ huỷ sự kiện bằng cách đặt ACTION_CANCELFLAG_CANCELED trên đối tượng sự kiện chuyển động. Nếu các con trỏ khác không hoạt động, hệ thống sẽ đặt ACTION_POINTER_UPFLAG_CANCELED.

Bất cứ khi nào ứng dụng của bạn nhận được một sự kiện chuyển động bằng ACTION_POINTER_UP, hãy kiểm tra FLAG_CANCELED để xác định xem sự kiện đó có cho thấy việc từ chối cảm ứng bằng lòng bàn tay (hoặc sự kiện nào đó bị huỷ) hay không.

Ứng dụng ghi chú

ChromeOS có ý định đặc biệt là hiển thị các ứng dụng ghi chú đã đăng ký cho người dùng. Để đăng ký một ứng dụng làm ứng dụng ghi chú, hãy thêm đoạn mã sau vào tệp kê khai ứng dụng:

<intent-filter>
    <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

Khi một ứng dụng được đăng ký với hệ thống, người dùng có thể chọn ứng dụng đó làm ứng dụng ghi chú mặc định. Khi có yêu cầu ghi chú mới, ứng dụng sẽ tạo một ghi chú trống để sẵn sàng nhập văn bản bằng bút cảm ứng. Khi người dùng muốn chú thích một hình ảnh (chẳng hạn như ảnh chụp màn hình hoặc hình đã tải xuống), ứng dụng sẽ chạy với ClipData chứa một hoặc nhiều mục content:// có nhiều URI. Ứng dụng sẽ tạo một ghi chú sử dụng hình ảnh đính kèm đầu tiên làm hình nền và chuyển sang chế độ người dùng có thể vẽ trên màn hình bằng bút cảm ứng.

Kiểm thử ý định ghi chú không cần bút cảm ứng

[TBD remove section.]

Để kiểm tra xem một ứng dụng có phản hồi chính xác các ý định ghi chú không cần dùng bút cảm ứng đang hoạt động hay không, hãy sử dụng phương thức sau để hiển thị các tuỳ chọn ghi chú trên ChromeOS:

  1. Chuyển sang chế độ nhà phát triển và đặt thiết bị ở chế độ có thể ghi
  2. Nhấn tổ hợp phím Ctrl+Alt+F2 để mở một thiết bị đầu cuối
  3. Chạy lệnh sudo vi /etc/chrome_dev.conf
  4. Nhấn i để chỉnh sửa và thêm --ash-enable-palette vào một dòng mới ở cuối tệp
  5. Lưu bằng cách nhấn phím Esc rồi nhập :, w, q rồi nhấn phím Enter
  6. Nhấn tổ hợp phím Ctrl+Alt+F1 để quay lại giao diện người dùng ChromeOS thông thường
  7. Đăng xuất rồi đăng nhập lại

Lúc này, bạn sẽ thấy một trình đơn bút cảm ứng trên kệ:

  • Nhấn vào nút bút cảm ứng trên kệ và chọn Ghi chú mới. Thao tác này sẽ mở một bản ghi chú trống.
  • Chụp ảnh màn hình. Từ kệ, hãy chọn nút bút cảm ứng > Chụp màn hình hoặc tải ảnh xuống. Bạn nên chọn Chú thích hình ảnh trong thông báo. Thao tác này sẽ mở ra ứng dụng có hình ảnh đã sẵn sàng chú thích.

Hỗ trợ chuột và bàn di chuột

Hầu hết các ứng dụng thường chỉ cần xử lý 3 sự kiện tập trung vào màn hình lớn: nhấp chuột phải, di chuộtkéo và thả.

Nhấp chuột phải

Mọi thao tác khiến ứng dụng hiển thị trình đơn theo bối cảnh, chẳng hạn như chạm và giữ một mục trong danh sách, cũng phải phản ứng với các sự kiện nhấp chuột phải.

Để xử lý các sự kiện nhấp chuột phải, ứng dụng cần đăng ký View.OnContextClickListener:

Box(modifier = Modifier.fillMaxSize()) {
    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { context ->
            val rootView = FrameLayout(context)
            val onContextClickListener =
                View.OnContextClickListener { view ->
                    showContextMenu()
                    true
                }
            rootView.setOnContextClickListener(onContextClickListener)
            rootView
        },
    )
}

Để biết thông tin chi tiết về cách tạo trình đơn theo bối cảnh, hãy xem phần Tạo trình đơn theo bối cảnh.

Khoảng cách di

Bạn có thể khiến bố cục ứng dụng của mình trông gọn gàng và dễ sử dụng hơn bằng cách xử lý các sự kiện di chuột. Điều này đặc biệt đúng đối với các thành phầntuỳ chỉnh:

Hai ví dụ phổ biến nhất về vấn đề này là:

  • Cho người dùng biết liệu một phần tử có hành vi tương tác hay không, chẳng hạn như có thể nhấp hoặc chỉnh sửa bằng cách thay đổi biểu tượng con trỏ chuột
  • Thêm phản hồi bằng hình ảnh vào các mục trong một danh sách lớn hoặc dạng lưới khi con trỏ đang di chuột qua các mục đó

Kéo và thả

Trong môi trường nhiều cửa sổ, người dùng muốn có thể kéo và thả các mục giữa các ứng dụng. Điều này đúng với các thiết bị máy tính bàn cũng như máy tính bảng, điện thoại và thiết bị gập ở chế độ chia đôi màn hình.

Cân nhắc xem liệu người dùng có khả năng kéo các mục vào ứng dụng của bạn hay không. Ví dụ: trình chỉnh sửa ảnh phải nhận được ảnh, trình phát âm thanh sẽ phải nhận được tệp âm thanh và chương trình vẽ sẽ phải nhận được ảnh.

Để thêm tính năng hỗ trợ kéo và thả, hãy xem bài viết Kéo và thả và bài đăng trên blog Android trên ChromeOS — Triển khai tính năng Kéo và thả.

Những điều cần đặc biệt lưu ý đối với ChromeOS

Hỗ trợ con trỏ nâng cao

Các ứng dụng xử lý đầu vào bằng chuột và bàn di chuột nâng cao phải triển khai đối tượng sửa đổi pointerInput để lấy PointerEvent:

@Composable
private fun LogPointerEvents(filter: PointerEventType? = null) {
    var log by remember { mutableStateOf("") }
    Column {
        Text(log)
        Box(
            Modifier
                .size(100.dp)
                .background(Color.Red)
                .pointerInput(filter) {
                    awaitPointerEventScope {
                        while (true) {
                            val event = awaitPointerEvent()
                            // handle pointer event
                            if (filter == null || event.type == filter) {
                                log = "${event.type}, ${event.changes.first().position}"
                            }
                        }
                    }
                }
        )
    }
}

Kiểm tra đối tượng PointerEvent để xác định những thông tin sau:

Tay điều khiển trò chơi

Một số thiết bị Android màn hình lớn hỗ trợ lên đến bốn tay điều khiển trò chơi. Sử dụng các API tay điều khiển trò chơi Android tiêu chuẩn để xử lý tay điều khiển trò chơi (xem phần Hỗ trợ tay điều khiển trò chơi).

Các nút trên tay điều khiển trò chơi được liên kết tới các giá trị chung theo một liên kết chung. Tuy nhiên, không phải nhà sản xuất tay điều khiển trò chơi nào cũng tuân theo cùng một quy ước liên kết. Bạn có thể cung cấp trải nghiệm tốt hơn nhiều nếu cho phép người dùng chọn cách sắp xếp tay điều khiển phổ biến khác nhau. Hãy xem bài viết Xử lý thao tác nhấn nút trên tay điều khiển trò chơi để biết thêm thông tin.

Chế độ dịch dữ liệu đầu vào

Theo mặc định, ChromeOS cho phép bật chế độ dịch. Đối với hầu hết ứng dụng Android, chế độ này giúp các ứng dụng hoạt động như mong muốn trong môi trường máy tính bàn. Một số ví dụ bao gồm việc tự động cho phép cuộn bằng hai ngón tay trên bàn di chuột, cuộn con lăn chuột và ánh xạ toạ độ màn hình thô đến toạ độ cửa sổ. Nhìn chung, các nhà phát triển ứng dụng không cần thiết phải tự triển khai bất kỳ hành vi nào trong số này.

Nếu một ứng dụng triển khai hành vi nhập dữ liệu tuỳ chỉnh, chẳng hạn như xác định một thao tác chụm bàn di chuột bằng hai ngón tay tuỳ chỉnh, hoặc các bản dịch đầu vào này không cung cấp các sự kiện nhập như ứng dụng mong đợi, bạn có thể tắt chế độ dịch đầu vào bằng cách thêm thẻ sau vào tệp kê khai Android:

<uses-feature
    android:name="android.hardware.type.pc"
    android:required="false" />

Tài nguyên khác