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 tra khả năng hỗ trợ bàn phím cơ bản, chẳng hạn như điều hướng bằng phím mũi tên và phím Tab, phím Nhập (Enter) để xác nhận mục nhập văn bản, và phím Cách (Space) để phát/tạm dừng trong các ứng dụng đa phương tiện
  • Thêm phím tắt tiêu chuẩn nếu có; ví dụ: Ctrl + Z để hoàn tác và Ctrl + S để lưu
  • Thử nghiệm các hoạt động tương tác cơ bản với chuột theo cách 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 chế độ xem tuỳ chỉnh
  • Thử nghiệm 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 cho ứng dụng vẽ, tay điều khiển trò chơi cho trò chơi và bộ điều khiển MIDI cho ứng dụng nhạc
  • Cân nhắc việc hỗ trợ thiết bị đầu vào nâng cao để 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 như một thiết bị thanh trượt cho các ứng dụng DJ, chụp chuột trong các trò chơi và các phím tắt mở rộng cho người dùng bàn phím 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 tốt 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. Đây cũng có thể là yếu tố cần thiết cho người dùng có nhu cầu hỗ trợ tiếp cận tính năng trên điện thoại, máy tính bảng, thiết bị gập và máy tính.

Đối với nhiều ứng dụng, phím mũi tên đơn giản và thao tác trên thẻ là tất cả những gì cần thiết và hầu hết được xử lý tự động bằng khung Android. Ví dụ: chế độ xem củaButton có thể lấy tiêu điểm theo mặc định và hoạt động điều hướng bằng bàn phím thường sẽ hoạt động không cần thêm mã nào. Để bật tính năng di chuyển trên bàn phím cho các chế độ xem không thể lấy tiêu điểm theo mặc định, nhà phát triển nên đánh dấu các chế độ xem đó là có thể lấy tiêu điểm. Chế độ xem này có thể thực hiện qua lập trình hoặc ở định dạng XML, như minh hoạ bên dưới. Hãy xemXử lý tiêu điểmđể biết thêm thông tin.

Kotlin

yourView.isFocusable = true

Java

yourView.setFocusable(true);

Ngoài ra, bạn có thể thiết lập thuộc tính focusable trong tệp bố cục:

android:focusable="true"

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 chế độ xem 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 làm gì thêm. Khi mối liên kết mặc định không chính xác đối với nhu cầu của ứng dụng, nó có thể được ghi đè như sau:

Kotlin

// Arrow keys
yourView.nextFocusLeftId = R.id.view_to_left
yourView.nextFocusRightId = R.id.view_to_right
yourView.nextFocusTopId = R.id.view_above
yourView.nextFocusBottomId = R.id.view_below

// Tab key
yourView.nextFocusForwardId = R.id.next_view

Java

// Arrow keys
yourView.setNextFocusLeftId(R.id.view_to_left);
yourView.setNextFocusRightId(R.id.view_to_left);
yourView.setNextFocusTopId(R.id.view_to_left);
yourView.setNextFocusBottomId(R.id.view_to_left);

// Tab key
yourView.setNextFocusForwardId(R.id.next_view);

Bạn nên thử truy cập chỉ bằng bàn phím vào mọi chức năng trong ứng dụng của mình trước mỗi bản phát hành. Ứng dụng phải dễ dàng truy cập các thao tác phổ biến nhất không cần phải sử dụng chuột hoặ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.

Tổ hợp 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ư EditText, ứ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 đối 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 dấu cách và các trò chơi điều khiển di chuyển bằng các phím w, a, s và d.

Hầu hết các ứng dụng đều 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, như hiển thị dưới đây:

Kotlin

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)
    }
}

Java

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_ENTER) {
        sendMessage();
        return true;
    } else if (KeyEvent.KEYCODE_SPACE){
        playOrPauseMedia();
        return true;
    } else {
        return 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 muốn biết thời điểm một phím được nhấn hoặc tính toán người dùng nhấn và giữ phím có thể tìm sự kiệnonKeyDown() và tự xử lý sự kiện onKeyDown lặp lại.

Để biết thêm thông tin hỗ trợ về bàn phím tích hợp, hãy xem phầnXử lý các thao tác bằng 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 và Shift khi sử dụng bàn phím cứng. Nếu một ứng dụng không triển khai đầy đủ, người dùng sẽ 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 (hoàn tác) và Ctrl + Shift + Z (làm lại). Để biết ví dụ về một số phím tắt nâng cao, hãy xem danh sách các phím tắt VLC Media Player.

Bạn có thể triển khai phím tắt bằng cách sử dụng dispatchKeyShortcutEvent(). Thao tác này sẽ chặn mọi tổ hợp phím meta (Alt, Ctrl và Shift) đối với một mã khoá cụ thể. Để kiểm tra một thẻ meta cụ thể, hãy sử dụng KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() hoặc KeyEvent.hasModifiers().

Việc tách mã phím tắt khỏi các thao tác tổ hợp phím khác (chẳng hạn như onKeyUp()onKeyDown()) có thể giúp việc duy trì mã dễ dàng hơn và cho phép chấp nhận mặc định các khoá meta khi không cần phải triển khai kiểm tra khoá meta theo cách thủ công trong tất cả trường hợp. Việc cho phép tất cả các tổ hợp phím meta cũng có thể thuận tiện hơn cho những người dùng quen với bố cục bàn phím và hệ điều hành khác.

Kotlin

override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean {
  return when (event.keyCode) {
    KeyEvent.KEYCODE_O -> {
      openFile() // Ctrl+O, Shift+O, Alt+O
      true
    }
    KeyEvent.KEYCODE_Z-> {
      if (event.isCtrlPressed) {
        if (event.isShiftPressed) {
          redoLastAction() // Ctrl+Shift+Z pressed
          true
        } else {
          undoLastAction() // Ctrl+Z pressed
          true
        }
      }
    }
    else -> {
      return super.dispatchKeyShortcutEvent(event)
    }
  }
}

Java

@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
  if (event.getKeyCode() == KeyEvent.KEYCODE_O) {
      openFile(); // Ctrl+O, Shift+O, Alt+O
      return true;
  } else if(event.getKeyCode() == KeyEvent.KEYCODE_Z) {
      if (event.isCtrlPressed()) {
          if (event.isShiftPressed()) {
              redoLastAction();
              return true;
          }
          else {
              undoLastAction();
              return true;
          }
      }
  }
  return super.dispatchKeyShortcutEvent(event);
}

Bạn cũng có thể triển khai phím tắt trong onKeyUp() bằng cách kiểm tra KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), hoặc KeyEvent.isAltPressed() theo cách tương tự như trên. Điều này có thể dễ dàng duy trì hơn nếu hành vi meta thay đổi nhiều hơn hành vi ứng dụng so với phím tắt. Ví dụ: khi W có nghĩa là "di chuyển về phía trước" và Shift + W có nghĩa là "chạy về phía trước".

Kotlin

override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
  return when(keyCode) {
    KeyEvent.KEYCODE_W-> {
      if (event.isShiftPressed) {
        if (event.isCtrlPressed) {
          flyForward() // Ctrl+Shift+W pressed
          true
        } else {
          runForward() // Shift+W pressed
          true
        }
      } else {
        walkForward() // W pressed
        true
      }
    }
    else -> super.onKeyUp(keyCode, event)
  }
}

Java

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_W) {
        if (event.isShiftPressed()) {
            if (event.isCtrlPressed()) {
                flyForward(); // Ctrl+Shift+W pressed
                return true;
            } else {
                runForward(); // Shift+W pressed
                return true;
            }
        } else {
            walkForward();
            return true;
        }
    }
    return super.onKeyUp(keyCode, event);
}

Bút cảm ứng

Nhiều thiết bị màn hình lớn có bút cảm ứng, và các ứng dụng Android xử lý việc đó 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 tương thích với đầu vào USB.

Sự kiện bút cảm ứng được báo cáo là sự kiện có màn hình cảm ứng quaView.onTouchEvent() hoặcView.onGenericMotionEvent(), và chứa mộtMotionEvent.getSource() của loạiSOURCE_STYLUS.

MotionEvent cũng sẽ chứa dữ liệu bổ sung:

Đ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ẽ, điều quan trọng là bạn cần kiểm tra các sự kiện xảy ra trong quá khứ gần bằng cách sử dụng các API getHistorical:

  • MotionEvent.getHistoricalX()
  • MotionEvent.getHistoricalY()
  • MotionEvent.getHistoricalPressure()
  • MotionEvent.getHistoricalAxisValue()

Từ chối cảm ứng bằng lòng bàn 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. Kể từ Android 13, để thuận tiện, hệ thống sẽ đặt FLAG_CANCELED cho các sự kiện ACTION_CANCEL, nhưng những phiên bản trước đó thì không.

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 Android:

<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ý, người dùng có thể chọn nó 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

Để 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 Ctrl + Alt + F2 để mở 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 Esc rồi nhấn :, w, q và nhấn Enter
  6. Nhấn 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. Để biết thông tin chi tiết về việc tạo một trình đơn theo bối cảnh, hãy xem phần Tạo trình đơn theo bối cảnh.

Kotlin

yourView.setOnContextClickListener {
  showContextMenu()
  true
}

Java

yourView.setOnContextClickListener(v -> {
    showContextMenu();
    return true;
});

Di chuột

Các nhà phát triển có thể khiến bố cục ứng dụng của họ 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 với chế độ xem tuỳ chỉnh. Hai ví dụ phổ biến nhất về vấn đề này là:

  • Cho người dùng biết nếu một phần tử có hành vi tương tác 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 đó

Kotlin

// Change the icon to a "hand" pointer on hover,
// Highlight the view by changing the background.
yourView.setOnHoverListener { view, _ ->
  addVisualHighlighting(true)
  view.pointerIcon =
    PointerIcon.getSystemIcon(view.context,
    PointerIcon.TYPE_HAND)
  false // listener did not consume the event.
}

Java

yourView.setOnHoverListener((view, event) -> {
    addVisualHighlighting(true);
    view.setPointerIcon(PointerIcon
            .getSystemIcon(view.getContext(), PointerIcon.TYPE_HAND));
    return true;
});

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 cho người dùng ở chế độ chia đôi màn hình.

Nhà phát triển nên 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 họ hay không. Một số ví dụ phổ biến bao gồm: 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 hỗ trợ kéo và thả, hãy làm theo tài liệuKéo và thả của Android, sau đó xembài đăng này trên blog ChromeOS.

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

  • Hãy nhớ yêu cầu quyền qua requestDragAndDropPermissions để truy cập vào các mục được kéo vào từ ngoài ứng dụng
  • Một mục phải gắn cờ View.DRAG_FLAG_GLOBAL để được kéo vào các ứng dụng khác

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 tuân theo tài liệu Android choView.onGenericMotionEvent() và sử dụng MotionEvent.getSource() để phân biệt giữa SOURCE_MOUSESOURCE_TOUCHSCREEN.

Hãy kiểm tra MotionEvent để triển khai hành vi bắt buộc:

  • Di chuyển tạo ra ACTION_HOVER_MOVE sự kiện.
  • Các nút tạo ra ACTION_BUTTON_PRESSACTION_BUTTON_RELEASE sự kiện. Bạn cũng có thể kiểm tra trạng thái hiện tại của tất cả các nút chuột/bàn di chuột bằng cách sử dụnggetButtonState().
  • Thao tác cuộn con lăn chuột sẽ tạo ra ACTION_SCROLL sự kiện.

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. Nhà phát triển phải sử dụng các API tay điều khiển trò chơi Android tiêu chuẩn để xử lý các API đó (xem phần Hỗ trợ tay điều khiển trò chơi).

Các nút được liên kết tới các giá trị chung sau một liên kết chung. Rất tiếc là không phải tất cả các nhà sản xuất tay điều khiển trò chơi đều 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ý 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 lăn chuột 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 thực thi 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