Zgodność urządzeń wejściowych na dużych ekranach

Na urządzeniach z dużym ekranem użytkownicy częściej korzystają z aplikacji za pomocą klawiatury, myszy, trackpada, rysika lub pada do gier. Aby umożliwić aplikacji akceptowanie danych z urządzeń zewnętrznych, wykonaj te czynności:

  • Przetestuj podstawową obsługę klawiatury, w tym nawigację przy użyciu klawiszy Tab i klawiszy strzałek, potwierdzanie wpisywania tekstu klawisza oraz odtwarzanie i wstrzymywanie spacji w aplikacjach do multimediów
  • Dodaj standardowe skróty klawiszowe, np. Ctrl + Z, aby cofnąć cofanie lub Ctrl + S, aby zapisać zmiany.
  • Testuj podstawowe interakcje z myszą – kliknij prawym przyciskiem myszy, by wyświetlić menu kontekstowe, zmiany ikon po najechaniu kursorem, kółkiem myszy lub trackpada w widokach niestandardowych.
  • Przetestuj urządzenia wejściowe specyficzne dla aplikacji, takie jak rysik do rysowania, kontrolery do gier do gier i kontrolery MIDI do aplikacji muzycznych
  • Rozważ zaawansowaną obsługę wprowadzania, dzięki której aplikacja będzie wyróżniać się na komputerach. Może to być np. touchpad pełniący funkcję cross-fadera w aplikacjach dla DJ-ów, przechwytywanie myszy w grach i zaawansowane skróty klawiszowe dla użytkowników korzystających z klawiatury.

Klawiatura

Sposób, w jaki aplikacja reaguje na wprowadzanie tekstu z klawiatury, zapewnia wygodę korzystania z dużego ekranu. Są 3 rodzaje wprowadzania danych za pomocą klawiatury: nawigacja, naciśnięcia klawiszy i skróty.

Nawigacja za pomocą klawiatury jest rzadko implementowana w aplikacjach dotykowych, ale użytkownicy mogą się tego spodziewać, gdy mają do dyspozycji klawiaturę i korzystają z aplikacji. Może być również bardzo ważna dla użytkowników z ułatwieniami dostępu na telefonach, tabletach, urządzeniach składanych i komputerach.

W wielu aplikacjach wystarczą proste klawisze strzałek i nawigacja po kartach. W większości przypadków platforma Androida obsługuje je automatycznie. Na przykład widok elementu Button można domyślnie zaznaczyć, a nawigacja za pomocą klawiatury powinna zwykle działać bez dodatkowego kodu. Aby umożliwić nawigację za pomocą klawiatury w widokach, które domyślnie nie mogą być zaznaczone, deweloperzy powinni oznaczyć je jako możliwe do zaznaczenia. Można to zrobić automatycznie lub w formacie XML, jak pokazano poniżej. Więcej informacji znajdziesz w sekcji Zarządzanie skupieniem.

Kotlin

yourView.isFocusable = true

Java

yourView.setFocusable(true);

Możesz też ustawić atrybut focusable w pliku układu:

android:focusable="true"

Po włączeniu fokusu platforma Androida tworzy mapowanie nawigacyjne na potrzeby wszystkich widoków, które można zaznaczyć, na podstawie ich pozycji. Zwykle działa to zgodnie z oczekiwaniami i nie musisz niczego więcej robić. Jeśli domyślne mapowanie nie spełnia wymagań aplikacji, można je zastąpić:

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

Przed każdą aktualizacją dobrze jest korzystać z każdego elementu aplikacji i korzystać tylko z klawiatury. Najczęstsze czynności wykonywane bez użycia myszy lub dotyku powinny być łatwe do wykonania.

Pamiętaj, że obsługa klawiatury może być niezbędna dla użytkowników z niepełnosprawnościami.

Naciśnięcia klawiszy

W przypadku wprowadzania tekstu obsługiwanego przez ekranową klawiaturę wirtualną (IME), np. EditText, aplikacje powinny działać zgodnie z oczekiwaniami na urządzeniach z dużym ekranem – deweloper nie musi nic robić. W przypadku naciśnięć klawiszy, których platforma nie przewiduje, aplikacje muszą same radzić sobie z ich działaniem. Dotyczy to zwłaszcza aplikacji z widokami niestandardowymi.

Są to na przykład aplikacje do obsługi czatu, które używają klawisza Enter do wysyłania wiadomości, aplikacje multimedialne, które uruchamiają i zatrzymują odtwarzanie klawiszem spacji, oraz gry, które sterują ruchem przy użyciu klawiszy w, a, s i d.

Większość aplikacji zastępuje wywołanie zwrotne onKeyUp() i dodaje oczekiwane działanie dla każdego otrzymanego kodu klucza, jak pokazano poniżej:

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

Zdarzenie onKeyUp występuje po zwolnieniu klucza. Używanie tego wywołania zwrotnego zapobiega przetwarzaniu wielu zdarzeń onKeyDown przez aplikacje, jeśli klucz jest przytrzymywany lub powoli zwalniany. Gry i aplikacje, które chcą wiedzieć, kiedy klawisz jest naciśnięty lub które wymagają przytrzymania przez użytkownika klawiszy na klawiaturze, mogą samodzielnie wyszukiwać zdarzenie onKeyDown() i obsługiwać powtarzające się zdarzenia onKeyDown.

Więcej informacji o obsłudze klawiatury znajdziesz w artykule Obsługa działań klawiatury.

Skróty

Podczas korzystania z klawiatury sprzętowej wymagane są typowe skróty Ctrl, Alt i Shift. Jeśli aplikacja ich nie obsługuje, może to być frustrujące dla użytkowników. Doświadczeni użytkownicy doceniają też skróty do często używanych zadań w konkretnych aplikacjach. Skróty ułatwiają korzystanie z aplikacji i odróżniają ją od aplikacji bez skrótów.

Typowe skróty to Ctrl + S (zapisanie), Ctrl + Z (cofnięcie) i Ctrl + Shift + Z (ponowienie). Bardziej zaawansowane skróty znajdziesz na liście klawiszy skrótów VLC Media Player.

Skróty można wdrożyć za pomocą polecenia dispatchKeyShortcutEvent(). Przechwytuje wszystkie kombinacje klawiszy meta (Alt, Ctrl i Shift) dla danego kodu klawisza. Aby sprawdzić konkretny metaklucz, użyj KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() lub KeyEvent.hasModifiers().

Oddzielenie kodu skrótu od innej obsługi naciśnięć klawiszy (takich jak onKeyUp() i onKeyDown()) może ułatwić obsługę kodu i umożliwia domyślne akceptowanie metakluczy bez konieczności za każdym razem ręcznego wdrażania metakluczy. Zezwolenie na wszystkie kombinacje metaklawiszy może być też wygodniejsze dla użytkowników przyzwyczajonych do różnych układów klawiatury i systemów operacyjnych.

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

Możesz też wdrożyć skróty w onKeyUp(), sprawdzając element KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() lub KeyEvent.isAltPressed() w taki sam sposób jak powyżej. Może to być łatwiejsze w utrzymaniu, gdy metazachowanie jest raczej modyfikacją działania aplikacji niż skrótem. Na przykład gdy W oznacza „idź do przodu”, a Shift + W oznacza „bieg do przodu”.

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

Rysik

Wiele urządzeń z dużym ekranem ma rysik, a aplikacje na Androida obsługują go jako dane wejściowe na ekranie dotykowym. Niektóre urządzenia mogą też mieć stół do rysowania przez USB lub Bluetooth, np. Wacom Intuos. Aplikacje na Androida mogą odbierać wejście Bluetooth, ale nie obsługują wejścia USB.

Zdarzenie rysika jest zgłaszane jako zdarzenie ekranu dotykowego przez View.onTouchEvent() lub View.onGenericMotionEvent() i zawiera zdarzenie MotionEvent.getSource() typu SOURCE_STYLUS.

Pole MotionEvent będzie też zawierać dodatkowe dane:

Punkty historyczne

Android grupuje zdarzenia wejściowe i dostarcza je raz na klatkę. Rysik może raportować zdarzenia z częstotliwością większą niż wyświetlacz. Podczas tworzenia aplikacji należy sprawdzić, czy nie wystąpiły zdarzenia z przeszłości, używając interfejsów API getHistorical:

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

Odrzucenie palm

Gdy użytkownik rysuje, pisze lub korzysta z aplikacji za pomocą rysika, czasami dotyka ekranu dłonią. Zdarzenie dotknięcia (ustawione na ACTION_DOWN lub ACTION_POINTER_DOWN) może być zgłoszone do aplikacji, zanim system rozpozna i zignoruje niezamierzony dotyk dłoni.

Android anuluje zdarzenia dotyku dłoni, wysyłając kod MotionEvent. Jeśli aplikacja otrzyma ACTION_CANCEL, anuluj gest. Jeśli aplikacja otrzymuje ACTION_POINTER_UP, sprawdź, czy jest ustawiona wartość FLAG_CANCELED. Jeśli tak, anuluj gest.

Nie sprawdzaj tylko FLAG_CANCELED. Od Androida 13 dla wygody system ustawia FLAG_CANCELED dla zdarzeń ACTION_CANCEL, ale poprzednie wersje go nie ustawiają.

Android 12

Na Androidzie 12 (poziom interfejsu API 32) i starszych wersjach wykrywanie odrzucenia dłoni jest możliwe tylko w przypadku zdarzeń dotknięcia jednym wskaźnikiem. Jeśli jedyny wskaźnik to dotknięcie dłoni, system anuluje zdarzenie, ustawiając ACTION_CANCEL na obiekcie zdarzenia ruchu. Jeśli inne wskaźniki nie działają, system ustawia wartość ACTION_POINTER_UP, która jest niewystarczająca do wykrycia odrzucenia dłoni.

Android 13

Na Androidzie 13 (poziom interfejsu API 33) i nowszych, jeśli jedynym wskaźnikiem jest dotyk dłoni, system anuluje zdarzenie, ustawiając ACTION_CANCEL i FLAG_CANCELED w obiekcie zdarzenia ruchu. Jeśli inne wskaźniki nie działają, system ustawia ACTION_POINTER_UP i FLAG_CANCELED.

Za każdym razem, gdy aplikacja otrzyma zdarzenie ruchu z użyciem funkcji ACTION_POINTER_UP, sprawdź FLAG_CANCELED, aby określić, czy oznacza to odrzucenie dłoni (lub anulowanie w inny sposób).

Notatki

ChromeOS ma specjalną intencję wyświetlającą użytkownikom zarejestrowane aplikacje do robienia notatek. Aby zarejestrować aplikację jako aplikację do robienia notatek, do pliku manifestu Androida dodaj te elementy:

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

Po zarejestrowaniu aplikacji użytkownik może ją wybrać jako domyślną aplikację do sporządzania notatek. Po wysłaniu prośby o dodanie nowej notatki aplikacja powinna utworzyć pustą notatkę, w której można wprowadzać notatki rysikiem. Gdy użytkownik chce dodać adnotację do obrazu (np. do zrzutu ekranu lub pobranego obrazu), uruchamia się aplikacja ClipData, która zawiera co najmniej 1 element z identyfikatorem URI content://. Aplikacja powinna utworzyć notatkę, w której pierwszy załączony obraz będzie używany jako obraz tła, i uruchomić tryb, w którym użytkownik może rysować po ekranie za pomocą rysika.

Testuj intencje robienia notatek bez rysika

Aby sprawdzić, czy aplikacja prawidłowo reaguje na intencje robienia notatek bez aktywnego stylu, skorzystaj z poniższej metody wyświetlania opcji robienia notatek w ChromeOS:

  1. Włączanie trybu programisty i umożliwianie zapisu na urządzeniu
  2. Naciśnij Ctrl + Alt + F2, aby otworzyć terminal
  3. Uruchom polecenie sudo vi /etc/chrome_dev.conf
  4. Naciśnij i, aby edytować i dodać --ash-enable-palette do nowego wiersza na końcu pliku
  5. Zapisz, naciskając Esc, a następnie wpisując :, w, q, a następnie naciskając Enter
  6. Naciśnij Ctrl + Alt + F1, aby wrócić do zwykłego interfejsu ChromeOS
  7. Wyloguj się i zaloguj ponownie

Na półce powinno znajdować się menu rysika:

  • Kliknij przycisk rysika na półce i wybierz Nowa notatka. Powinno się otworzyć pustą notatkę z rysunkiem.
  • Zrób zrzut ekranu. Na półce wybierz przycisk stylu > Zrób zrzut ekranu lub pobierz obraz. W powiadomieniu powinna znajdować się opcja „Dodaj adnotację do obrazu”. Powinno to uruchomić aplikację z obrazem gotowym do dodania adnotacji.

Obsługa myszy i touchpada

Większość aplikacji zwykle obsługuje tylko 3 zdarzenia związane z dużym ekranem: kliknięcie prawym przyciskiem myszy, najechanie oraz przeciągnięcie i upuszczenie.

Kliknij prawym przyciskiem myszy

Działania, które powodują wyświetlenie menu kontekstowego w aplikacji (np. naciśnięcie i przytrzymanie elementu na liście), powinny również reagować na zdarzenia kliknięcia prawym przyciskiem myszy. Aby obsługiwać zdarzenia kliknięcia prawym przyciskiem myszy, aplikacje powinny zarejestrować właściwość View.OnContextClickListener. Szczegółowe informacje o tworzeniu menu kontekstowego znajdziesz w artykule Tworzenie menu kontekstowych.

Kotlin

yourView.setOnContextClickListener {
  showContextMenu()
  true
}

Java

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

Najechanie

Deweloperzy mogą sprawić, że układy aplikacji będą dopracowane i łatwiejsze w obsłudze dzięki obsłudze zdarzeń po najechaniu kursorem. Dotyczy to zwłaszcza widoków niestandardowych. Oto 2 najpowszechniejsze przykłady:

  • Wskazywanie użytkownikom, czy element ma interaktywne działanie, np. można go kliknąć lub edytować, przez zmianę ikony wskaźnika myszy
  • dodawanie wizualnej opinii do elementów na dużej liście lub siatce po najechaniu na nie wskaźnikiem,

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

Przeciągnij i upuść

W środowisku obejmującym wiele okien użytkownicy oczekują możliwości przeciągania elementów między aplikacjami. Dotyczy to zarówno komputerów, jak i tabletów, telefonów i urządzeń składanych z trybem podzielonego ekranu.

Deweloperzy powinni zastanowić się, czy użytkownicy mogą przeciągać elementy do aplikacji. Oto kilka typowych przykładów: edytorzy zdjęć mogą spodziewać się zdjęć, odtwarzacze audio – pliki audio, a programy do rysowania – zdjęcia.

Aby dodać obsługę przeciągania i upuszczania, zapoznaj się z dokumentacją dotyczącą Androida metodą przeciągnij i upuść oraz przeczytaj tego posta na blogu na temat ChromeOS.

Specjalne uwagi dotyczące ChromeOS

  • Pamiętaj, aby poprosić o uprawnienia za pomocą requestDragAndDropPermissions, aby uzyskać dostęp do elementów przeciągniętych poza aplikację
  • Element musi mieć flagę View.DRAG_FLAG_GLOBAL, aby można go było przeciągnąć do innych aplikacji

Zaawansowana obsługa wskaźników

Aplikacje, które zaawansowane obsługują obsługę myszy i touchpada, powinny być zgodne z dokumentacją Androida dotyczącą View.onGenericMotionEvent() i używać narzędzia MotionEvent.getSource() do rozróżniania między SOURCE_MOUSE i SOURCE_TOUCHSCREEN.

Sprawdź MotionEvent, aby wdrożyć wymagane działanie:

  • Ruch generuje ACTION_HOVER_MOVE zdarzeń.
  • Przyciski generują zdarzenia ACTION_BUTTON_PRESS i ACTION_BUTTON_RELEASE. Możesz też sprawdzić bieżący stan wszystkich przycisków myszy lub trackpada za pomocą przycisku getButtonState().
  • Przewijanie kółkiem myszy generuje zdarzenia ACTION_SCROLL.

Kontrolery do gier

Niektóre urządzenia z Androidem o dużym ekranie obsługują do 4 kontrolerów do gier. Do obsługi kontrolerów do gier na Androida deweloperzy powinni używać standardowych interfejsów API kontrolerów do gier na Androida (patrz Obsługa kontrolerów do gier).

Przyciski są mapowane na wspólne wartości w ramach wspólnego mapowania. Niestety nie wszyscy producenci kontrolerów do gier przestrzegają tych samych konwencji mapowania. Możesz zapewnić znacznie lepsze wrażenia, jeśli zezwolisz użytkownikom na wybieranie różnych popularnych mapowań kontrolerów. Więcej informacji znajdziesz w artykule Proces naciskania przycisków na padzie do gier.

Tryb translacji danych wejściowych

W ChromeOS domyślnie włączony jest tryb translacji danych wejściowych. W przypadku większości aplikacji na Androida ten tryb umożliwia poprawne działanie aplikacji na komputerze. Do przykładów należą automatyczne włączanie przewijania 2 palcami na touchpadzie, przewijanie kółkiem myszy i mapowanie nieprzetworzonych współrzędnych wyświetlania na współrzędne okna. Zasadniczo deweloperzy aplikacji nie muszą sami implementować żadnych z tych funkcji.

Jeśli aplikacja obsługuje niestandardowe dane wejściowe, np. zdefiniuj niestandardowe działanie ściągnięcia palcami po touchpadzie, lub takie tłumaczenia danych wejściowych nie zapewniają oczekiwanych przez aplikację zdarzeń wejściowych, możesz wyłączyć tryb tłumaczenia danych wejściowych, dodając do pliku manifestu Androida ten tag:

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

Dodatkowe materiały