Rysik umożliwia użytkownikom wygodę i precyzyjną interakcję z aplikacjami. Dzięki niemu można robić notatki, szkicować i pracować z aplikacjami zwiększającymi produktywność, a także odprężyć się i zrelaksować dzięki grom i aplikacjom rozrywkowym.
Android i ChromeOS oferują różne interfejsy API, dzięki którym możesz w pełni wykorzystać możliwości rysika. Zajęcia MotionEvent
zawierają informacje o interakcjach użytkownika z ekranem, w tym o wykrywaniu nacisku rysika, orientacji, przechylania, najeżdżania kursorem i wykrywaniu dłoni. Grafika i biblioteki przewidywania ruchu o krótkim czasie oczekiwania ulepszają renderowanie na ekranie rysikiem, zapewniając bardziej naturalne wrażenia jak pióro i papier.
MotionEvent
Klasa MotionEvent
reprezentuje interakcje użytkownika, takie jak pozycja i ruch wskaźników dotykowych na ekranie. W przypadku wpisywania rysika MotionEvent
ujawnia też dane dotyczące nacisku, orientacji, przechylenia i najechania kursorem.
Dane zdarzenia
Aby uzyskać dostęp do danych MotionEvent
w aplikacjach opartych na widoku danych, skonfiguruj onTouchListener:
Kotlin
val onTouchListener = View.OnTouchListener { view, event -> // Process motion event. }
Java
View.OnTouchListener listener = (view, event) -> { // Process motion event. };
Detektor odbiera obiekty MotionEvent
z systemu, aby aplikacja mogła je przetworzyć.
Obiekt MotionEvent
dostarcza dane związane z tymi aspektami zdarzenia interfejsu:
- Działania: fizyczna interakcja z urządzeniem – dotykanie ekranu, przesuwanie wskaźnika nad powierzchnią ekranu, najeżdżanie kursorem na powierzchnię ekranu.
- Wskaźniki – identyfikatory obiektów wchodzących w interakcję z ekranem – palcem, rysika, myszy
- Oś: typ danych – współrzędne X i Y, ciśnienie, przechylenie, orientacja i utrzymanie (odległość).
działania.
Aby wdrożyć obsługę rysika, musisz wiedzieć, jakie czynności wykonuje użytkownik.
MotionEvent
udostępnia szeroki zakres stałych ACTION
, które definiują zdarzenia ruchu. Najważniejsze działania związane z rysikiem to:
Działanie | Opis |
---|---|
ACTION_DOWN ACTION_POINTER_DOWN |
Wskaźnik dotknął ekranu. |
ACTION_MOVE | Wskaźnik porusza się po ekranie. |
ACTION_UP ACTION_POINTER_UP |
Wskaźnik nie styka się już z ekranem |
ACTION_CANCEL | Poprzedni lub obecny ruch ma zostać anulowany. |
Aplikacja może wykonywać zadania takie jak rozpoczęcie nowego kreski w momencie ACTION_DOWN
, rysowanie kreski w formacie ACTION_MOVE,
i kończenie kreski po uruchomieniu funkcji ACTION_UP
.
Zbiór działań MotionEvent
, od ACTION_DOWN
do ACTION_UP
dla danego wskaźnika, jest nazywany zestawem ruchu.
Wskaźniki
Większość ekranów jest dotykowych: system przypisuje wskaźnik do każdego palca, rysika, myszy lub innego obiektu wskazującego, które styka się z ekranem. Indeks wskaźnika pozwala uzyskać informacje o osi dla określonego wskaźnika, np. położenie pierwszego palca dotykającego ekranu lub drugiego palca.
Indeksy wskaźników mają zakres od 0 do liczby wskaźników zwracanych przez MotionEvent#pointerCount()
minus 1.
Dostęp do wartości osi wskaźników można uzyskać za pomocą metody getAxisValue(axis, pointerIndex)
. W przypadku pominięcia indeksu wskaźnika system zwraca wartość pierwszego wskaźnika – wskaźnika 0 (0).
Obiekty MotionEvent
zawierają informacje o typie używanego wskaźnika. Aby uzyskać typ wskaźnika, wykonaj iterację dla indeksów wskaźników i wywołaj metodę getToolType(pointerIndex)
.
Więcej informacji o wskaźnikach znajdziesz w artykule Obsługa gestów wielodotykowych.
Dane wejściowe rysika
Za pomocą TOOL_TYPE_STYLUS
możesz filtrować dane wejściowe rysika:
Kotlin
val isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex)
Java
boolean isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex);
Rysik może też zgłosić, że jest używany jako gumka w aplikacji TOOL_TYPE_ERASER
:
Kotlin
val isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex)
Java
boolean isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex);
Dane osi rysika
ACTION_DOWN
i ACTION_MOVE
podają dane na temat rysika, czyli współrzędne X i Y, nacisk, orientację, przechylenie i najechanie kursorem.
Aby umożliwić dostęp do tych danych, interfejs MotionEvent
API udostępnia parametr getAxisValue(int)
, gdzie parametr jest dowolnym z tych identyfikatorów osi:
Axis | Zwracana wartość getAxisValue() |
---|---|
AXIS_X |
Współrzędna X zdarzenia ruchu. |
AXIS_Y |
Współrzędna Y zdarzenia ruchu. |
AXIS_PRESSURE |
W przypadku ekranu dotykowego lub touchpada nacisk wywierany przez palec, rysik lub inny wskaźnik. W przypadku myszy lub kulki ma wartość 1, gdy naciśnięty zostanie przycisk główny, lub 0, jeśli nie jest to możliwe. |
AXIS_ORIENTATION |
W przypadku ekranu dotykowego lub touchpada jest to orientacja palca, rysika lub innego wskaźnika względem pionowej płaszczyzny urządzenia. |
AXIS_TILT |
Kąt nachylenia rysika w radianach. |
AXIS_DISTANCE |
Odległość rysika od ekranu. |
Na przykład MotionEvent.getAxisValue(AXIS_X)
zwraca współrzędną x dla pierwszego wskaźnika.
Zobacz też Obsługiwanie gestów wielodotykowych.
Pozycja
Współrzędne x i y można pobierać, używając następujących wywołań:
MotionEvent#getAxisValue(AXIS_X)
lubMotionEvent#getX()
MotionEvent#getAxisValue(AXIS_Y)
lubMotionEvent#getY()
Ciśnienie
Presję wskaźnika można pobierać za pomocą tych wywołań:
getAxisValue(AXIS_PRESSURE)
lub getPressure()
w przypadku pierwszego wskaźnika.
W przypadku ekranów dotykowych i touchpadów wartość ciśnienia jest wartością z zakresu od 0 (bez nacisku) do 1, ale w zależności od kalibracji ekranu mogą być zwracane wyższe wartości.
Orientacja
Orientacja wskazuje kierunek, w którym wskazuje rysik.
Orientację wskaźnika można pobrać za pomocą funkcji getAxisValue(AXIS_ORIENTATION)
lub getOrientation()
(w przypadku pierwszego wskaźnika).
W przypadku rysika orientacja jest zwracana jako wartość radiana z zakresu od 0 do pi (π) w prawo lub od 0 do pi w lewo.
Orientacja umożliwia zastosowanie prawdziwego pędzla. Jeśli na przykład rysik reprezentuje płaski pędzel, jego szerokość zależy od jego orientacji.
Przechylenie
Pochylenie określa nachylenie rysika względem ekranu.
Pochylenie zwraca dodatni kąt rysika w radianach, gdzie 0 jest prostopadłe do ekranu, a π/2 jest płaska na powierzchni.
Kąt nachylenia można pobrać za pomocą funkcji getAxisValue(AXIS_TILT)
(bez skrótu do pierwszego wskaźnika).
Pochylenie pozwala uzyskać model z jak największą liczbą rzeczywistych narzędzi, np. naśladować cieniowanie przechylonym ołówkiem.
Najechanie
Odległość rysika od ekranu mierzy się za pomocą getAxisValue(AXIS_DISTANCE)
. Zwraca wartość od 0, 0 (kontakt z ekranem) na wyższe wartości, gdy rysik przesuwa się od ekranu. Odległość między ekranem a końcówką (punktem) rysika zależy od producenta ekranu i rysika. Implementacje mogą się różnić, dlatego nie polegaj na precyzyjnych wartościach kluczowych funkcji aplikacji.
Najechanie rysikiem pozwala wyświetlić podgląd rozmiaru pędzla lub wskazać przycisk, który zostanie wybrany.
Uwaga: funkcja tworzenia udostępnia zestaw elementów modyfikujących, które zmieniają stan elementów interfejsu:
hoverable
: skonfiguruj komponent tak, aby można go najeżdżać kursorem, korzystając ze zdarzeń wejścia i wyjścia wskaźnika.indication
: rysuje efekty wizualne związane z tym komponentem w przypadku interakcji.
Odrzucenie dłoni, nawigacja i niechciane dane wejściowe
Czasami ekrany wielodotykowe mogą rejestrować niechciane dotknięcia, np. gdy użytkownik w naturalny sposób opiera rękę o ekranie, aby umożliwić czytanie pisma odręcznego. Odrzucenie urządzenia Palm to mechanizm, który wykrywa takie zachowanie i powiadamia Cię, że ostatni zestaw MotionEvent
powinien zostać anulowany.
Dlatego musisz przechowywać historię danych wejściowych użytkownika, aby możliwe było usuwanie niechcianych dotknięć z ekranu i ponowne wyrenderowanie prawidłowych danych wejściowych użytkownika.
ACTION_CANCEL i FLAG_CANCELED
ACTION_CANCEL
i FLAG_CANCELED
zostały zaprojektowane tak, aby informować, że poprzedni zestaw MotionEvent
powinien zostać anulowany od ostatniego ACTION_DOWN
. Dzięki temu możesz na przykład cofnąć ostatnią kreskę w aplikacji do rysowania dla danego wskaźnika.
ACTION_CANCEL
Dodano w Androidzie 1.0 (poziom API 1)
ACTION_CANCEL
oznacza, że poprzedni zestaw zdarzeń ruchu ma zostać anulowany.
ACTION_CANCEL
jest wyzwalany, gdy zostanie wykryty dowolny z tych elementów:
- Gesty do nawigacji
- Odrzucenie dłoni
Po wywołaniu funkcji ACTION_CANCEL
aktywny wskaźnik należy wskazać za pomocą getPointerId(getActionIndex())
. Następnie usuń kreskę utworzoną za pomocą tego wskaźnika z historii danych wejściowych i ponownie wyrenderuj scenę.
OZNACZONE_ANULOWANIE
Dodano w Androidzie 13 (poziom API 33)
FLAG_CANCELED
oznacza, że wskaźnik wznoszący się został przypadkowo dotknięty przez użytkownika. Flaga jest zwykle ustawiana, gdy użytkownik przypadkowo dotknie ekranu, na przykład chwytając urządzenie lub przykładając dłoń do ekranu.
Dostęp do wartości flagi możesz uzyskać w ten sposób:
Kotlin
val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED
Java
boolean cancel = (event.getFlags() & FLAG_CANCELED) == FLAG_CANCELED;
Jeśli flaga jest ustawiona, musisz cofnąć ostatnie ustawienie parametru MotionEvent
, od ostatniego ustawienia ACTION_DOWN
od tego wskaźnika.
Podobnie jak ACTION_CANCEL
, wskaźnik można znaleźć razem z elementem getPointerId(actionIndex)
.
Pełny ekran, od krawędzi do krawędzi i gesty nawigacyjne
Jeśli aplikacja jest wyświetlana na pełnym ekranie i przy jej krawędziach zawiera interaktywne elementy, takie jak obszar roboczy aplikacji do rysowania lub tworzenia notatek, przesunięcie palcem od dołu do dołu w celu wyświetlenia nawigacji lub przeniesienie aplikacji w tle może spowodować niechciane dotknięcie obszaru roboczego.
Aby zapobiegać niepożądanym kliknięciom w aplikacji za pomocą gestów, możesz stosować wstawki i ACTION_CANCEL
.
Zapoznaj się też z sekcją Odrzucenie palca, nawigacja i niechciane dane wejściowe powyżej.
Użyj metody setSystemBarsBehavior()
i BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
w WindowInsetsController
, aby zapobiec wywoływaniu niepożądanych zdarzeń dotknięcia za pomocą gestów nawigacyjnych:
Kotlin
// Configure the behavior of the hidden system bars. windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
Java
// Configure the behavior of the hidden system bars. windowInsetsController.setSystemBarsBehavior( WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE );
Więcej informacji o zarządzaniu wstawianiem elementów i gestami znajdziesz tutaj:
- Ukrywanie pasków systemowych w trybie pojemnym
- Zapewnianie zgodności z nawigacją przy użyciu gestów
- Wyświetlanie treści w aplikacji od krawędzi do krawędzi
Małe opóźnienie
Opóźnienie to czas potrzebny sprzętowi, systemowi i aplikacjom na przetworzenie i wyrenderowanie danych wejściowych użytkownika.
Czas oczekiwania = przetwarzanie danych wejściowych sprzętu i systemu operacyjnego + przetwarzanie aplikacji + komponowanie systemu + renderowanie sprzętowe
Źródło opóźnienia
- Rejestrowanie rysika na ekranie dotykowym (sprzęt): pierwsze połączenie bezprzewodowe, gdy rysik i system operacyjny komunikują się ze sobą w celu zarejestrowania i zsynchronizowania.
- Częstotliwość próbkowania dotykowego (sprzęt): liczba razy na sekundę ekranu dotykowego sprawdza, czy wskaźnik dotyka powierzchni. Wartość z zakresu od 60 do 1000 Hz.
- Przetwarzanie danych wejściowych (aplikacja): stosowanie kolorów, efektów graficznych i przekształcania według danych wejściowych użytkownika.
- Renderowanie graficzne (system operacyjny i sprzęt): zamiana buforów, przetwarzanie sprzętowe.
Grafika z krótkim czasem oczekiwania
Biblioteka grafiki Jetpack o krótkim czasie oczekiwania skraca czas przetwarzania między danymi wprowadzonymi przez użytkownika a renderowaniem na ekranie.
Biblioteka skraca czas przetwarzania dzięki unikaniu renderowania wielobuforowego i wykorzystywaniu techniki renderowania bufora przedniego, która oznacza zapisywanie danych bezpośrednio na ekranie.
Renderowanie przedniego bufora
Przedni bufor to pamięć używana przez ekran do renderowania. To najbliższy obszar, w którym aplikacje mogą rysować bezpośrednio na ekranie. Biblioteka o krótkim czasie oczekiwania umożliwia aplikacjom renderowanie bezpośrednio w przednim buforze. Poprawia to wydajność, ponieważ zapobiega zamianie bufora, która może wystąpić w przypadku zwykłego renderowania z wieloma buforami lub podwójnego buforowania (najczęstszy przypadek).
Renderowanie z buforem przednim to świetna technika renderowania małego obszaru ekranu, ale nie służy do odświeżania całego ekranu. W przypadku renderowania z buforem przednim aplikacja renderuje treść do bufora, z którego odczytuje wyświetlacz. W rezultacie może dojść do wyrenderowania artefaktów lub rozerania się(patrz poniżej).
Biblioteka o krótkim czasie oczekiwania jest dostępna na urządzeniach z Androidem 10 (poziom interfejsu API 29) i nowszym oraz na urządzeniach z ChromeOS z Androidem 10 (poziom API 29) lub nowszym.
Zależności
Biblioteka o krótkim czasie oczekiwania dostarcza komponenty do implementacji renderowania bufora przedniego. Biblioteka jest dodawana jako zależność w pliku build.gradle
modułu aplikacji:
dependencies {
implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}
Wywołania zwrotne GLFrontBufferRenderer
Biblioteka o krótkim czasie oczekiwania zawiera interfejs GLFrontBufferRenderer.Callback
, który definiuje te metody:
Biblioteka o krótkim czasie oczekiwania nie zależy od typu danych używanych w usłudze GLFrontBufferRenderer
.
Biblioteka przetwarza je jako strumień setek punktów danych, więc musisz tak zaprojektować dane, aby zoptymalizować wykorzystanie pamięci i jej przydzielanie.
Wywołania zwrotne
Aby włączyć wywołania zwrotne renderowania, zaimplementuj funkcję GLFrontBufferedRenderer.Callback
i zastąp onDrawFrontBufferedLayer()
i onDrawDoubleBufferedLayer()
. Funkcja GLFrontBufferedRenderer
używa wywołań zwrotnych do renderowania danych w najbardziej zoptymalizowany sposób.
Kotlin
val callback = object: GLFrontBufferedRenderer.Callback<DATA_TYPE> { override fun onDrawFrontBufferedLayer( eglManager: EGLManager, bufferInfo: BufferInfo, transform: FloatArray, param: DATA_TYPE ) { // OpenGL for front buffer, short, affecting small area of the screen. } override fun onDrawMultiDoubleBufferedLayer( eglManager: EGLManager, bufferInfo: BufferInfo, transform: FloatArray, params: Collection<DATA_TYPE> ) { // OpenGL full scene rendering. } }
Java
GLFrontBufferedRenderer.Callback<DATA_TYPE> callbacks = new GLFrontBufferedRenderer.Callback<DATA_TYPE>() { @Override public void onDrawFrontBufferedLayer(@NonNull EGLManager eglManager, @NonNull BufferInfo bufferInfo, @NonNull float[] transform, DATA_TYPE data_type) { // OpenGL for front buffer, short, affecting small area of the screen. } @Override public void onDrawDoubleBufferedLayer(@NonNull EGLManager eglManager, @NonNull BufferInfo bufferInfo, @NonNull float[] transform, @NonNull Collection<? extends DATA_TYPE> collection) { // OpenGL full scene rendering. } };
Deklarowanie instancji GLFrontBufferedRenderer
Przygotuj GLFrontBufferedRenderer
, podając utworzone wcześniej zdarzenia SurfaceView
i wywołania zwrotne. GLFrontBufferedRenderer
optymalizuje renderowanie na początku i podwójny bufor przy użyciu wywołań zwrotnych:
Kotlin
var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)
Java
GLFrontBufferedRenderer<DATA_TYPE> glFrontBufferRenderer = new GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks);
Renderowanie
Renderowanie bufora przedniego rozpoczyna się po wywołaniu metody renderFrontBufferedLayer()
, która wywołuje wywołanie zwrotne onDrawFrontBufferedLayer()
.
Renderowanie z podwójnym buforem jest wznawiane po wywołaniu funkcji commit()
, która aktywuje wywołanie zwrotne onDrawMultiDoubleBufferedLayer()
.
W poniższym przykładzie proces renderuje się w przednim buforze (szybkie renderowanie), gdy użytkownik zacznie rysować na ekranie (ACTION_DOWN
), a potem przesunie kursor (ACTION_MOVE
). Gdy wskaźnik opuści powierzchnię ekranu (ACTION_UP
), proces renderuje się w podwójnym buforze.
Możesz użyć funkcji requestUnbufferedDispatch()
, aby poprosić system wprowadzania, by nie grupował zdarzeń ruchu, a zamiast nich wysyłał je, gdy tylko są dostępne:
Kotlin
when (motionEvent.action) { MotionEvent.ACTION_DOWN -> { // Deliver input events as soon as they arrive. view.requestUnbufferedDispatch(motionEvent) // Pointer is in contact with the screen. glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE) } MotionEvent.ACTION_MOVE -> { // Pointer is moving. glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE) } MotionEvent.ACTION_UP -> { // Pointer is not in contact in the screen. glFrontBufferRenderer.commit() } MotionEvent.CANCEL -> { // Cancel front buffer; remove last motion set from the screen. glFrontBufferRenderer.cancel() } }
Java
switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: { // Deliver input events as soon as they arrive. surfaceView.requestUnbufferedDispatch(motionEvent); // Pointer is in contact with the screen. glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE); } break; case MotionEvent.ACTION_MOVE: { // Pointer is moving. glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE); } break; case MotionEvent.ACTION_UP: { // Pointer is not in contact in the screen. glFrontBufferRenderer.commit(); } break; case MotionEvent.ACTION_CANCEL: { // Cancel front buffer; remove last motion set from the screen. glFrontBufferRenderer.cancel(); } break; }
Co robić, a czego nie robić
Należy
Niewielkie fragmenty ekranu, pismo odręczne, rysowanie, szkicowanie.
Przeciwwskazania
Aktualizacja na pełnym ekranie, przesunięcie, powiększenie. Może to spowodować rozdarcie.
Łzawienie
Rozdarcie pojawia się, gdy ekran odświeża się, gdy jednocześnie modyfikowany jest bufor ekranu. W jednej części ekranu widoczne są nowe dane, a w innej – stare.
Przewidywanie ruchu
Biblioteka prognoz ruchu jetpacka zmniejsza postrzegane opóźnienie, szacując ścieżkę ruchu użytkownika i dostarczając tymczasowe, sztuczne punkty do mechanizmu renderowania.
Biblioteka prognoz ruchu pobiera dane wejściowe użytkownika jako obiekty MotionEvent
. Obiekty zawierają informacje o współrzędnych x i y, ciśnieniu i czasie. Funkcje te są wykorzystywane przez funkcję prognozowania ruchu do przewidywania przyszłych obiektów MotionEvent
.
Prognozowane obiekty (MotionEvent
) są tylko szacunkowe. Prognozowane zdarzenia mogą zmniejszyć postrzegane czasy oczekiwania, ale dane prognozowane muszą zostać zastąpione rzeczywistymi danymi MotionEvent
po ich otrzymaniu.
Biblioteka prognoz ruchu jest dostępna na urządzeniach z Androidem 4.4 (poziom interfejsu API 19) i nowszym oraz na urządzeniach z ChromeOS z Androidem 9 (poziom interfejsu API 28) lub nowszym.
Zależności
Biblioteka prognoz ruchu umożliwia ich implementację. Biblioteka jest dodawana jako zależność w pliku build.gradle
modułu aplikacji:
dependencies {
implementation "androidx.input:input-motionprediction:1.0.0-beta01"
}
Implementacja
Biblioteka prognoz ruchu zawiera interfejs MotionEventPredictor
, który definiuje te metody:
record()
: zapisuje obiektyMotionEvent
jako rejestr działań użytkownikapredict()
: zwraca przewidywaną wartośćMotionEvent
Zadeklaruj wystąpienie elementu MotionEventPredictor
Kotlin
var motionEventPredictor = MotionEventPredictor.newInstance(view)
Java
MotionEventPredictor motionEventPredictor = MotionEventPredictor.newInstance(surfaceView);
Podaj dane prognozy
Kotlin
motionEventPredictor.record(motionEvent)
Java
motionEventPredictor.record(motionEvent);
Prognoza
Kotlin
when (motionEvent.action) { MotionEvent.ACTION_MOVE -> { val predictedMotionEvent = motionEventPredictor?.predict() if(predictedMotionEvent != null) { // use predicted MotionEvent to inject a new artificial point } } }
Java
switch (motionEvent.getAction()) { case MotionEvent.ACTION_MOVE: { MotionEvent predictedMotionEvent = motionEventPredictor.predict(); if(predictedMotionEvent != null) { // use predicted MotionEvent to inject a new artificial point } } break; }
Co należy, a czego nie należy robić w przypadku prognozowania ruchu
Należy
Po dodaniu nowego punktu prognozy usuń punkty prognozy.
Przeciwwskazania
Nie używaj punktów prognozy do końcowego renderowania.
Notatki
ChromeOS umożliwia aplikacji deklarowanie niektórych działań związanych z notatkami.
Aby zarejestrować aplikację w ChromeOS jako aplikację do robienia notatek, przeczytaj artykuł Zgodność urządzeń wejściowych.
Aby zarejestrować aplikację na Androidzie jako aplikację do notatek, przeczytaj artykuł Tworzenie aplikacji do notatek.
W Androidzie 14 (poziom interfejsu API 34) wprowadziliśmy intencję ACTION_CREATE_NOTE
, która umożliwia aplikacji rozpoczynanie robienia notatek na ekranie blokady.
Cyfrowe rozpoznawanie tuszu za pomocą ML Kit
Dzięki cyfrowemu rozpoznawaniu pisma ML Kit Twoja aplikacja może rozpoznawać w setkach języków tekst odręczny na cyfrowej powierzchni. Możesz też klasyfikować szkice.
ML Kit udostępnia klasę Ink.Stroke.Builder
w celu tworzenia obiektów Ink
, które mogą być przetwarzane przez modele systemów uczących się w celu konwertowania pisma odręcznego na tekst.
Oprócz rozpoznawania pisma odręcznego model rozpoznaje gesty takie jak usunięcie czy zakreślenie.
Więcej informacji znajdziesz w artykule Cyfrowe rozpoznawanie atramentu.
Dodatkowe materiały
Przewodniki dla programistów
- Tworzenie aplikacji do robienia notatek
- Rozpoznawanie tuszu cyfrowego za pomocą ML Kit na Androidzie