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

Na urządzeniach z dużym ekranem użytkownicy często wchodzą w interakcje z aplikacjami za pomocą klawiatury, myszy, trackpada, rysika lub pada do gier. Aby umożliwić aplikacji przyjmowanie danych wejściowych z urządzeń zewnętrznych:

  • Przetestuj podstawową obsługę klawiatury, np. Ctrl+Z do cofania, Ctrl+C do kopiowania i Ctrl+S do zapisywania. Listę domyślnych skrótów klawiszowych znajdziesz w artykule Obsługa działań wykonywanych za pomocą klawiatury.
  • Przetestuj zaawansowaną obsługę klawiatury, np. nawigację za pomocą klawisza Tab i strzałek, potwierdzanie wprowadzania tekstu za pomocą klawisza Enter, oraz odtwarzanie i wstrzymywanie w aplikacjach multimedialnych za pomocą spacji.
  • Przetestuj podstawowe interakcje z myszą, w tym kliknięcie prawym przyciskiem myszy w celu otwarcia menu kontekstowego, zmiany ikon po najechaniu kursorem oraz zdarzenia przewijania za pomocą kółka myszy lub trackpada w komponentach niestandardowych.
  • Przetestuj urządzenia wejściowe specyficzne dla aplikacji, takie jak rysik, kontrolery do gier i kontrolery MIDI w aplikacjach muzycznych.
  • Rozważ obsługę zaawansowanych danych wejściowych, które mogą wyróżnić aplikację w środowiskach komputerowych, np. trackpad jako crossfader w aplikacjach dla DJ-ów, przechwytywanie myszy w grach i skróty klawiszowe dla użytkowników, którzy głównie korzystają z klawiatury.

Klawiatura

Sposób, w jaki aplikacja reaguje na dane wejściowe z klawiatury, wpływa na wygodę użytkowników korzystających z dużego ekranu. Istnieją 3 rodzaje danych wejściowych z klawiatury: nawigacja, naciśnięcia klawiszy, i skróty.

Nawigacja za pomocą klawiatury jest rzadko implementowana w aplikacjach, w których główną rolę odgrywa dotyk, ale użytkownicy oczekują jej, gdy korzystają z aplikacji i mają ręce na klawiaturze. Nawigacja za pomocą klawiatury może być niezbędna na telefonach, tabletach, urządzeniach składanych i komputerach stacjonarnych dla użytkowników z potrzebami w zakresie ułatwień dostępu.

W przypadku wielu aplikacji nawigacja za pomocą strzałek i klawisza Tab jest obsługiwana automatycznie przez platformę Android. Na przykład element Button jest domyślnie możliwy do zaznaczenia, a nawigacja za pomocą klawiatury powinna działać bez dodatkowego kodu. Aby włączyć nawigację za pomocą klawiatury w przypadku widoków, które nie są domyślnie możliwe do zaznaczenia, oznacz je jako możliwe do zaznaczenia. Można to zrobić programowo lub w kodzie XML:

Kotlin

yourView.isFocusable = true

Java

yourView.setFocusable(true);

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

android:focusable="true"

Więcej informacji znajdziesz w artykule Obsługa zaznaczenia.

Gdy zaznaczenie jest włączone, platforma Android tworzy mapowanie nawigacyjne dla wszystkich widoków, które można zaznaczyć, na podstawie ich pozycji. Zwykle działa to zgodnie z oczekiwaniami i nie wymaga dalszego rozwoju. Jeśli domyślne mapowanie nie jest odpowiednie dla potrzeb aplikacji, można je zastąpić w ten sposób:

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

Przetestuj dostęp do każdego elementu interfejsu aplikacji za pomocą samej klawiatury. Często używane elementy powinny być dostępne bez użycia myszy lub dotyku.

Pamiętaj, że obsługa klawiatury może być niezbędna dla użytkowników z potrzebami w zakresie ułatwień dostępu.

Naciśnięcia klawiszy

W przypadku wprowadzania tekstu, które byłoby obsługiwane przez ekranową klawiaturę wirtualną (IME), takich jak an EditText , aplikacje powinny działać zgodnie z oczekiwaniami na urządzeniach z dużym ekranem bez dodatkowych prac programistycznych. W przypadku naciśnięć klawiszy, których platforma nie może przewidzieć, aplikacje muszą samodzielnie obsługiwać zachowanie. Dotyczy to zwłaszcza aplikacji z widokami niestandardowymi.

Przykłady to aplikacje do czatowania, które używają klawisza Enter do wysyłania wiadomości, aplikacje multimedialne, które rozpoczynają i zatrzymują odtwarzanie za pomocą spacji, oraz gry które sterują ruchem za pomocą klawiszy w, a, s i d.

Większość aplikacji zastępuje wywołanie zwrotne onKeyUp() i dodaje oczekiwane zachowanie dla każdego otrzymanego kodu klawisza:

Kotlin

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, gdy klawisz zostanie zwolniony. Użycie wywołania zwrotnego zapobiega konieczności przetwarzania przez aplikacje wielu onKeyDown zdarzeń, jeśli klawisz jest przytrzymywany lub zwalniany powoli. Gry i aplikacje, które muszą wykrywać moment naciśnięcia klawisza lub to, czy użytkownik przytrzymuje klawisz, mogą nasłuchiwać zdarzenia onKeyDown i samodzielnie obsługiwać powtarzające się zdarzenia onKeyDown.

Więcej informacji znajdziesz w artykule Obsługa działań wykonywanych za pomocą klawiatury.

Skróty

Podczas korzystania z klawiatury sprzętowej oczekuje się typowych skrótów klawiszowych, które obejmują klawisze Ctrl, Alt, Shift i Meta. Jeśli aplikacja nie implementuje skrótów, użytkownicy mogą być sfrustrowani. Zaawansowani użytkownicy doceniają też skróty do często używanych zadań specyficznych dla aplikacji. Skróty ułatwiają korzystanie z aplikacji i odróżniają ją od aplikacji, które nie mają skrótów.

Do typowych skrótów należą Ctrl+S (zapisz), Ctrl+Z (cofnij) i Ctrl+Shift+Z (przywróć). Listę domyślnych skrótów znajdziesz w artykule Obsługa działań wykonywanych za pomocą klawiatury.

Skróty można włączyć, implementując dispatchKeyShortcutEvent() w celu przechwytywania wszystkich kombinacji klawiszy (Alt, Ctrl, Shift i Meta) dla danego kodu klawisza. Aby sprawdzić określony klawisz modyfikujący, użyj:

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

Oddzielenie kodu skrótu od innych funkcji obsługi naciśnięć klawiszy (np. onKeyUp() i onKeyDown()) domyślnie akceptuje klawisze modyfikujące bez konieczności ręcznego implementowania sprawdzania klawiszy modyfikujących w każdym przypadku. Umożliwienie wszystkich kombinacji klawiszy modyfikujących może być też wygodniejsze dla użytkowników, którzy są przyzwyczajeni do różnych układów klawiatury i systemów operacyjnych.

Możesz też implementować skróty w onKeyUp(), sprawdzając KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() lub KeyEvent.isAltPressed(). Może to być łatwiejsze w utrzymaniu, jeśli zmodyfikowane zachowanie klawisza jest bardziej zmianą zachowania aplikacji niż skrótem. Na przykład w grach, gdy W oznacza „idź do przodu”, a Shift+W oznacza „biegnij 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);
}

Zobacz też Pomocnik skrótów klawiszowych.

Rysik

Wiele urządzeń z dużym ekranem jest wyposażonych w rysik. Aplikacje na Androida obsługują rysiki jako dane wejściowe z ekranu dotykowego. Niektóre urządzenia mogą też mieć tablet graficzny USB lub Bluetooth, np. Wacom Intuos. Aplikacje na Androida mogą odbierać dane wejściowe przez Bluetooth, ale nie przez USB.

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

Obiekt MotionEvent zawiera informacje o zdarzeniu:

Punkty historyczne

Android grupuje zdarzenia wejściowe i dostarcza je raz na klatkę. Rysik może zgłaszać zdarzenia z dużo większą częstotliwością niż wyświetlacz. Podczas tworzenia aplikacji do rysowania sprawdzaj zdarzenia, które mogły wystąpić w niedalekiej przeszłości, za pomocą interfejsów API getHistorical:

Odrzucanie dotyku dłonią

Gdy użytkownicy rysują, piszą lub wchodzą w interakcje z Twoją aplikacją za pomocą rysika, czasami dotykają ekranu dłonią. Zdarzenie dotknięcia (ustawione na ACTION_DOWN lub ACTION_POINTER_DOWN) może zostać zgłoszone do Twojej aplikacji zanim system rozpozna i zignoruje przypadkowy dotyk dłonią.

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

Nie sprawdzaj tylko FLAG_CANCELED. W Androidzie 13 (API na poziomie 33) i nowszym system ustawia FLAG_CANCELED dla zdarzeń ACTION_CANCEL, ale w starszych wersjach Androida system nie ustawia tej flagi.

Android 12

W Androidzie 12 (API na poziomie 32) i starszym wykrywanie odrzucania dotyku dłonią jest możliwe tylko w przypadku zdarzeń dotyku jednym palcem. Jeśli dotyk dłonią jest jedynym wskaźnikiem, system anuluje zdarzenie, ustawiając ACTION_CANCEL w obiekcie zdarzenia ruchu. Jeśli inne wskaźniki są wciśnięte, system ustawia ACTION_POINTER_UP, co jest niewystarczające do wykrycia odrzucania dotyku dłonią.

Android 13

W Androidzie 13 (API na poziomie 33) i nowszym, jeśli dotyk dłonią jest jedynym wskaźnikiem, system anuluje zdarzenie, ustawiając ACTION_CANCEL i FLAG_CANCELED w obiekcie zdarzenia ruchu. Jeśli inne wskaźniki są wciśnięte, system ustawia ACTION_POINTER_UP i FLAG_CANCELED.

Za każdym razem, gdy Twoja aplikacja otrzyma zdarzenie ruchu z ACTION_POINTER_UP, sprawdź, czy ustawiona jest flaga FLAG_CANCELED, aby określić, czy zdarzenie wskazuje na odrzucenie dotyku dłonią (lub inne anulowanie zdarzenia).

Aplikacje do robienia notatek

ChromeOS ma specjalny intent, który wyświetla użytkownikom zarejestrowane aplikacje do robienia notatek. Aby zarejestrować aplikację jako aplikację do robienia notatek, dodaj do manifestu aplikacji te informacje:

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

Gdy aplikacja jest zarejestrowana w systemie, użytkownik może wybrać ją jako domyślną aplikację do robienia notatek. Gdy zostanie poproszony o utworzenie nowej notatki, aplikacja powinna utworzyć pustą notatkę gotową do wprowadzania danych za pomocą rysika. Gdy użytkownik chce dodać adnotacje do obrazu (np. zrzutu ekranu lub pobranego obrazu), aplikacja uruchamia się z ClipData zawierającym co najmniej 1 element z identyfikatorami URI content://. Aplikacja powinna utworzyć notatkę, która używa pierwszego załączonego obrazu jako obrazu tła, i przejść do trybu, w którym użytkownik może rysować na ekranie za pomocą rysika.

Testowanie intentów do robienia notatek bez rysika

Aby sprawdzić, czy aplikacja prawidłowo reaguje na intenty do robienia notatek bez aktywnego rysika, użyj tej metody, aby wyświetlić opcje robienia notatek w ChromeOS:

  1. Przejdź do trybu deweloperskiego i włącz zapisywanie 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 dodaj --ash-enable-palette do nowego wiersza na końcu pliku.
  5. Zapisz, naciskając Esc, a następnie wpisując :, w, q i naciskając Enter
  6. Naciśnij Ctrl+Alt+F1, aby wrócić do zwykłego interfejsu ChromeOS.
  7. Wyloguj się, a następnie zaloguj się ponownie.

Na półce powinna teraz znajdować się ikona rysika:

  • Kliknij przycisk rysika na półce i wybierz Nowa notatka. Powinna się otworzyć pusta notatka do rysowania.
  • Zrób zrzut ekranu. Na półce kliknij przycisk rysika > Zrzut ekranu lub pobierz obraz. W powiadomieniu powinna być opcja Dodaj adnotacje do obrazu. Powinno to spowodować uruchomienie aplikacji z obrazem gotowym do dodania adnotacji.

Obsługa myszy i touchpada

Większość aplikacji musi zwykle obsługiwać tylko 3 zdarzenia związane z dużym ekranem: kliknięcie prawym przyciskiem myszy, najechanie i przeciąganie i upuszczanie.

Kliknięcie prawym przyciskiem

Wszystkie działania, które powodują wyświetlenie przez aplikację menu kontekstowego, np. dotknięcie i przytrzymanie elementu listy, powinny też reagować na zdarzenia kliknięcia prawym przyciskiem myszy.

Aby obsługiwać zdarzenia kliknięcia prawym przyciskiem myszy, aplikacje powinny zarejestrować View.OnContextClickListener:

Kotlin

yourView.setOnContextClickListener {
    showContextMenu()
    true
}

Java

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

Szczegółowe informacje o tworzeniu menu kontekstowych znajdziesz w artykule Tworzenie menu kontekstowego.

Najechanie

Obsługując zdarzenia najechania, możesz sprawić, że układy aplikacji będą bardziej dopracowane i łatwiejsze w użyciu. Dotyczy to zwłaszcza komponentów niestandardowych widoków:

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)
    true // Listener consumes the event.
}

Java

// Change the icon to a "hand" pointer on hover.
// Highlight the view by changing the background.
yourView.setOnHoverListener((view, event) -> {
    addVisualHighlighting(true);
    view.setPointerIcon(
        PointerIcon.getSystemIcon(view.getContext(), PointerIcon.TYPE_HAND)
    );
    return true; // Listener consumes the event.
});

Oto 2 najczęstsze przykłady:

  • Wskazywanie użytkownikom, czy element ma zachowanie interaktywne, np. czy można go kliknąć lub edytować, przez zmianę ikony wskaźnika myszy.
  • Dodawanie wizualnych informacji zwrotnych do elementów na dużej liście lub w siatce, gdy wskaźnik znajduje się nad nimi.

Przeciągnij i upuść

W środowisku wielookienkowym użytkownicy oczekują, że będą mogli przeciągać elementy między aplikacjami. Dotyczy to zarówno komputerów stacjonarnych, jak i tabletów, telefonów i urządzeń składanych w trybie podzielonego ekranu.

Zastanów się, czy użytkownicy będą przeciągać elementy do Twojej aplikacji. Na przykład edytory zdjęć powinny oczekiwać otrzymywania zdjęć, odtwarzacze audio – plików audio, a programy do rysowania – zdjęć.

Aby dodać obsługę przeciągania, przeczytaj artykuł Włączanie przeciągania i upuszczania oraz post na blogu Android on ChromeOS – Implementing Drag & Drop.

Szczególne uwagi dotyczące ChromeOS

  • Pamiętaj, aby poprosić o uprawnienia za pomocą requestDragAndDropPermissions(), aby uzyskać dostęp do elementów przeciągniętych z zewnątrz aplikacji.
  • Aby można było przeciągnąć element do innych aplikacji, musi on mieć flagę View.DRAG_FLAG_GLOBAL.

Zaawansowana obsługa wskaźnika

Aplikacje, które zaawansowanie obsługują dane wejściowe z myszy i touchpada, powinny implementować modyfikator View#onGenericMotionEvent() i użyj [MotionEvent.getSource()][], aby odróżnić SOURCE_MOUSE od SOURCE_TOUCHSCREEN.

Sprawdź obiekt MotionEvent, aby zaimplementować wymagane zachowanie:

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

Kontrolery do gier

Niektóre urządzenia z Androidem i dużym ekranem obsługują do 4 kontrolerów do gier. Do obsługi kontrolerów do gier używaj standardowych interfejsów API kontrolerów do gier na Androida (patrz Obsługa kontrolerów do gier).

Przyciski kontrolera do gier są mapowane na typowe wartości zgodnie z typowym mapowaniem. Nie wszyscy producenci kontrolerów do gier stosują jednak te same konwencje mapowania. Możesz znacznie poprawić wygodę użytkowników, jeśli pozwolisz im wybierać różne popularne mapowania kontrolerów. Więcej informacji znajdziesz w artykule Przetwarzanie naciśnięć przycisków gamepada.

Tryb tłumaczenia danych wejściowych

ChromeOS domyślnie włącza tryb tłumaczenia danych wejściowych. W przypadku większości aplikacji na Androida ten tryb pomaga aplikacjom działać zgodnie z oczekiwaniami w środowisku komputerowym. Przykłady to automatyczne włączanie przewijania 2 palcami na touchpadzie, przewijania kółkiem myszy i mapowania surowych współrzędnych wyświetlacza na współrzędne okna. Zwykle deweloperzy aplikacji nie muszą samodzielnie implementować żadnego z tych zachowań.

Jeśli aplikacja implementuje niestandardowe zachowanie danych wejściowych, np. definiuje niestandardowe działanie uszczypnięcia 2 palcami na touchpadzie, lub te tłumaczenia danych wejściowych nie zapewniają zdarzeń wejściowych oczekiwanych przez aplikację, możesz wyłączyć tryb tłumaczenia danych wejściowych, dodając ten tag do manifestu Androida:

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

Dodatkowe materiały