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

Na urządzeniach z dużymi ekranami użytkownicy częściej korzystają z aplikacji za pomocą klawiatury, myszy, trackpada, rysika lub pada do gier. Aby umożliwić aplikacji akceptowanie danych wejściowych z urządzeń zewnętrznych:

  • Testowanie podstawowej obsługi klawiatury, np. nawigacji przy użyciu klawiszy Tab i strzałek, Wpisz potwierdzenie wpisywania tekstu oraz spacja i odtwarzanie/wstrzymywanie w aplikacjach do multimediów
  • W razie potrzeby dodaj standardowe skróty klawiszowe, na przykład Ctrl + Z, aby cofnąć czynność, i Ctrl + S, aby zapisać.
  • Przetestuj podstawowe interakcje myszą w taki sposób, aby uzyskać dostęp do menu kontekstowego, kliknięcia prawym przyciskiem myszy, zmiany ikony po najechaniu kursorem oraz zdarzeń przewijania kółkiem myszy lub trackpada w widokach niestandardowych.
  • Testowanie urządzeń wejściowych przeznaczonych do określonych aplikacji, takich jak rysik do aplikacji do rysowania, kontrolery do gier czy kontrolery MIDI do aplikacji muzycznych
  • Zastanów się nad zaawansowaną obsługą wprowadzania danych, która może wyróżnić aplikację na komputerach. Może to być na przykład touchpad jako przełącznik w przypadku aplikacji dla DJ-ów, przechwytywanie myszy w grach oraz rozbudowane skróty klawiszowe dla użytkowników korzystających z klawiatury.

Klawiatura

Sposób reagowania aplikacji na działanie klawiatury wpływa na wygodę korzystania z dużego ekranu. Są 3 rodzaje wprowadzania tekstu z klawiatury: nawigacja, naciśnięcia klawiszy i skróty.

W aplikacjach skoncentrowanych na dotyku użytkownicy rzadko implementują nawigację za pomocą klawiatury, ale użytkownicy mogą tego oczekiwać, gdy korzystają z aplikacji i mają ręce przyłożone do klawiatury. Może też być niezbędna w przypadku użytkowników z ułatwieniami dostępu na telefonach, tabletach, urządzeniach składanych i komputerach.

W przypadku wielu aplikacji wystarczą proste klawisze strzałek i nawigacja po kartach. W większości przypadków obsługa odbywa się automatycznie przez platformę Androida. 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órych domyślnie nie można zaznaczyć, 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 Skupienie się na obsłudze.

Kotlin

yourView.isFocusable = true

Java

yourView.setFocusable(true);

Atrybut focusable możesz też ustawić w pliku układu:

android:focusable="true"

Po włączeniu fokusu platforma Androida 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 trzeba nic więcej robić. Jeśli domyślne mapowanie nie odpowiada potrzebom 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);

Zalecamy, aby przed każdą wersją aplikacji spróbować uzyskać dostęp do wszystkich funkcji aplikacji tylko za pomocą klawiatury. Najczęściej używane działania powinny być łatwo dostępne bez użycia myszy lub dotyku.

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

Kombinacje klawiszy

W przypadku wprowadzania tekstu, który byłby obsługiwany przez wirtualną klawiaturę ekranową (IME), np. EditText, aplikacje powinny działać na urządzeniach z dużymi ekranami zgodnie z oczekiwaniami. Nie wymaga to żadnych działań ze strony dewelopera. W przypadku naciśnięć klawiszy, których platforma nie może przewidzieć, aplikacje muszą same poradzić sobie z tym 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ą ruchami za pomocą klawiszy W, A, S i D.

Większość aplikacji zastępuje wywołanie zwrotne onKeyUp() i dodaje oczekiwane działanie dla każdego odebranego 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 ma miejsce w przypadku zwolnienia klucza. Używanie tego wywołania zwrotnego sprawia, że aplikacje nie muszą przetwarzać wielu zdarzeń onKeyDown, jeśli klucz jest przytrzymywany lub zwalniany powoli. Gry i aplikacje, które chcą wiedzieć, kiedy zostanie naciśnięty klawisz, lub które wymagają przytrzymania klawiszy na klawiaturze, mogą wyszukać zdarzenie onKeyDown() i samodzielnie obsługiwać powtarzające się zdarzenia onKeyDown.

Więcej informacji o obsłudze klawiatury znajdziesz w sekcji Obsługa skrótów klawiszowych.

Skróty

Podczas korzystania z klawiatury sprzętowej należy się spodziewać typowych skrótów klawiszowych Ctrl, Alt i Shift. Brak ich w aplikacji może być frustrujący dla użytkowników. Doświadczeni użytkownicy doceniają też skróty do często używanych zadań w aplikacjach. Skróty ułatwiają korzystanie z aplikacji i odróżniają ją od tych, które nie mają skrótów.

Niektóre typowe skróty to Ctrl + S (zapisz), Ctrl + Z (cofnij) oraz Ctrl + Shift + Z (Ponów). Przykłady bardziej zaawansowanych skrótów znajdziesz na liście klawiszy skrótów VLC Media Player.

Skróty można stosować za pomocą elementu dispatchKeyShortcutEvent(). Przechwytuje wszystkie kombinacje naciśnięć klawiszy (Alt, Ctrl i Shift) w przypadku danego kodu. Aby znaleźć konkretny metaklucz, użyj KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() lub KeyEvent.hasModifiers().

Oddzielenie kodu skrótu od innej funkcji obsługi kombinacji klawiszy (np. onKeyUp() i onKeyDown()) może ułatwić konserwację kodu i umożliwi domyślne akceptowanie metakluczy bez konieczności ręcznego wdrażania sprawdzania metatagów za każdym razem. Dopuszczenie wszystkich kombinacji meta-klawisza może być 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);
}

Skróty możesz też zaimplementować w usłudze onKeyUp(), sprawdzając w ten sposób KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() lub KeyEvent.isAltPressed() w taki sam sposób jak powyżej. Będzie to łatwiejsze w utrzymaniu, jeśli metazachowanie polega raczej na modyfikacji działania aplikacji, a nie na skrótach. Na przykład gdy W oznacza „Idź do przodu”, a Shift + W – „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 jest wyposażonych w rysik, a aplikacje na Androida obsługują go jako ekran dotykowy. Niektóre urządzenia mogą mieć też stół do rysowania – USB lub Bluetooth, np. Wacom Intuos. Aplikacje na Androida mogą odbierać wejścia Bluetooth, ale nie działają przez wejście USB.

Zdarzenie rysika jest raportowane jako zdarzenie na ekranie dotykowym przez View.onTouchEvent() lub View.onGenericMotionEvent() i zawiera element MotionEvent.getSource() typu SOURCE_STYLUS.

MotionEvent będzie też zawierać dodatkowe dane:

Punkty historyczne

Android grupuje zdarzenia wejściowe i dostarcza je raz na klatkę. Rysik może zgłaszać zdarzenia z znacznie większą częstotliwością niż wyświetlacz. Podczas tworzenia aplikacji rysunkowych ważne jest, aby przy użyciu interfejsów API getHistorical sprawdzać zdarzenia, które mogły wystąpić w niedawnych przeszłości.

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

Odrzucenie dłoni

Gdy użytkownicy rysują, piszą lub korzystają z aplikacji za pomocą rysika, czasami dotykają ekranu dłonią. Zdarzenie dotknięcia (ustawione jako ACTION_DOWN lub ACTION_POINTER_DOWN) może zostać zgłoszone do aplikacji, zanim system rozpozna i zignoruje niezamierzony dotknięcie dłoni.

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

Nie sprawdzaj tylko wartości FLAG_CANCELED. Od Androida 13 dla wygody system ustawia dla zdarzeń ACTION_CANCEL ustawienie FLAG_CANCELED, ale poprzednie wersje tego nie robią.

Android 12

Na Androidzie 12 (poziom interfejsu API 32) i starszych wykrywanie odrzucenia dłoni jest możliwe tylko w przypadku zdarzeń dotyku za pomocą 1 wskaźnika. Jeśli jedynym wskaźnikiem jest dotknięcie dłoni, system anuluje zdarzenie, ustawiając obiekt ACTION_CANCEL na obiekt zdarzenia ruchu. Jeśli inne wskaźniki nie działają, system ustawia ACTION_POINTER_UP, co jest niewystarczające do wykrycia odrzucenia dłoni.

Android 13

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

Gdy aplikacja odbiera zdarzenie ruchu za pomocą funkcji ACTION_POINTER_UP, sprawdź, czy zdarzenie to FLAG_CANCELED wskazuje na odrzucenie dłoni (lub anulowanie innego wydarzenia).

Notatki

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

<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ą do sporządzania notatek. Gdy zostanie wysłane żądanie nowej notatki, aplikacja powinna utworzyć pustą notatkę, którą można pisać rysikiem. Gdy użytkownik chce dodać adnotacje do obrazu (np. do zrzutu ekranu lub pobranego obrazu), aplikacja uruchamia się z elementem ClipData zawierającym co najmniej 1 element z identyfikatorem URI content://. Aplikacja powinna utworzyć notatkę, która wykorzystuje pierwszy załączony obraz jako obraz tła, i włączyć tryb, w którym użytkownik może rysować na ekranie rysikiem.

Testowanie intencji robienia notatek bez rysika

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

  1. Przełącz się w tryb deweloperski i nadaj urządzeniu możliwość zapisu
  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 w nowym wierszu na końcu pliku
  5. Zapisz: naciśnij Esc, a następnie wpisz :, W i Q oraz naciśnij 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ę teraz menu rysika:

  • Kliknij przycisk rysika na półce i wybierz Nowa notatka. Powinno to 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 być dostępna opcja „Dodaj adnotację do obrazu”. Powinno to spowodować uruchomienie aplikacji z obrazem gotowym do dodania adnotacji.

Obsługa myszy i touchpada

Większość aplikacji obsługuje zazwyczaj 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

Wszystkie działania, które powodują wyświetlenie menu kontekstowego w aplikacji, np. naciśnięcie i przytrzymanie elementu listy, powinny też być reagowane na zdarzenie kliknięcia prawym przyciskiem myszy. Aby obsługiwać zdarzenia kliknięcia prawym przyciskiem myszy, aplikacje powinny zarejestrować element 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ą zadbać o to, aby układy aplikacji były dopracowane i łatwiejsze w użyciu, przez obsługę zdarzeń najechania kursorem. Dotyczy to zwłaszcza widoków niestandardowych. Oto 2 najczęstsze przykłady:

  • wskazywanie użytkownikom, czy element jest interaktywny, np. 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 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ść

Użytkownicy korzystający z wielu okien oczekują możliwości przeciągania i upuszczania elementów między aplikacjami. Dotyczy to zarówno komputerów, jak i tabletów, telefonów i urządzeń składanych w trybie podzielonego ekranu.

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

Aby dodać obsługę przeciągania i upuszczania, zapoznaj się z dokumentacją przeciągania i upuszczania na Androidzie oraz przeczytaj tego posta na blogu na temat ChromeOS.

Specjalne uwagi dotyczące ChromeOS

  • Pamiętaj, aby poprosić o uprawnienia za pomocą requestDragAndDropPermissions w celu uzyskania dostępu do elementów przeciągniętych z aplikacji
  • Aby element mógł zostać przeciągnięty do innych aplikacji, musi mieć flagę View.DRAG_FLAG_GLOBAL

Zaawansowana obsługa wskaźników

Aplikacje, które obsługują zaawansowane funkcje wprowadzania danych za pomocą myszy i touchpada, powinny być zgodne z dokumentacją systemu View.onGenericMotionEvent() i używać MotionEvent.getSource() do rozróżniania między SOURCE_MOUSE a SOURCE_TOUCHSCREEN.

Sprawdź MotionEvent, aby wdrożyć wymagane zachowanie:

  • Ruch generuje wydarzenia (ACTION_HOVER_MOVE).
  • Przyciski generują zdarzenia ACTION_BUTTON_PRESS i ACTION_BUTTON_RELEASE. Możesz też sprawdzić bieżący stan wszystkich przycisków myszy/trackpada, używając 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. Deweloperzy powinni używać do obsługi standardowych interfejsów API kontrolerów do gier na Androida (patrz Obsługa kontrolerów do gier).

Przyciski są zmapowane na wspólne wartości. Niestety nie wszyscy producenci kontrolerów do gier stosują te same konwencje mapowania. Aby zapewnić użytkownikom znacznie lepsze wrażenia, zezwól użytkownikom na wybieranie różnych popularnych mapowań kontrolerów. Więcej informacji znajdziesz w artykule o przetwarzaniu naciśnięć przycisku na pada do gier.

Tryb tłumaczenia wejściowego

ChromeOS domyślnie włącza tryb tłumaczenia danych wejściowych. W przypadku większości aplikacji na Androida ten tryb ułatwia działanie aplikacji w środowisku komputerowym. Przykłady obejmują automatyczne włączanie przewijania 2 palcami po touchpadzie, przewijanie kółkiem myszy oraz mapowanie nieprzetworzonych współrzędnych wyświetlania na współrzędne okna. Ogólnie rzecz biorąc, deweloperzy aplikacji nie muszą sami wdrażać żadnego z tych działań.

Jeśli aplikacja obsługuje niestandardowe sposoby wprowadzania danych, na przykład definiuje niestandardowe działanie ściągnięcia palcami na touchpadzie 2 palcami, 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 do pliku manifestu Androida ten tag:

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

Dodatkowe materiały