Android i ChromeOS udostępniają różne interfejsy API, które ułatwiają tworzenie aplikacji zapewniających użytkownikom wyjątkowe korzystanie z rysika. Klasa MotionEvent
udostępnia informacje o interakcjach rysika z ekranem, w tym o naciskaniu rysika, orientacji, przechylaniu, najeżdżaniu kursorem i wykrywaniu dłoni. Biblioteki prognozowania ruchu i grafiki z małym opóźnieniem ulepszają renderowanie rysika na ekranie, zapewniając naturalne wrażenie, jak w papierze.
MotionEvent
Klasa MotionEvent
reprezentuje interakcje użytkowników, takie jak pozycja i ruch wskaźników dotykowych na ekranie. Podczas wpisywania danych rysikiem MotionEvent
pokazuje też dane dotyczące nacisku, orientacji, nachylenia i najechania kursorem.
Dane zdarzenia
Aby uzyskać dostęp do danych MotionEvent
, 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 w interfejsie:
- Działania: fizyczna interakcja z urządzeniem – dotykanie ekranu, przesuwanie wskaźnika po powierzchni ekranu, najeżdżanie kursorem na powierzchnię ekranu
- Wskaźniki: identyfikatory obiektów wchodzących w interakcję z ekranem – palca, stylu, myszki
- Oś: typ danych – współrzędne X i Y, ciśnienie, nachylenie, orientacja i odległość (odległość).
Działania
Aby zaimplementować obsługę rysika, musisz wiedzieć, jakie działanie wykonuje użytkownik.
Funkcja MotionEvent
udostępnia wiele różnych 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 skontaktował się z ekranem. |
PRZENIESIENIE | Wskaźnik porusza się po ekranie. |
ACTION_UP ACTION_POINTER_UP |
Wskaźnik nie kontaktuje się już z ekranem. |
ACTION_CANCEL | Kiedy ma zostać anulowany poprzedni lub bieżący ustawiony ruch. |
Aplikacja może wykonywać takie zadania jak na przykład rozpoczynanie nowego pociągnięcia, gdy wystąpi ACTION_DOWN
, rysowanie kreski znakiem ACTION_MOVE,
i jej zakończenie po uruchomieniu ACTION_UP
.
Zbiór działań MotionEvent
od ACTION_DOWN
do ACTION_UP
dla danego wskaźnika nazywany jest zestawem akcji.
Wskaźniki
Większość ekranów jest wielodotykowych: system przypisuje wskaźnik do każdego palca, rysika, myszy lub innego obiektu wskazującego, który styka się z ekranem. Indeks wskaźnika pozwala uzyskać informacje o osi dla konkretnego wskaźnika, na przykład położenia pierwszego palca dotykającego ekranu lub drugiego.
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)
.
Jeśli indeks wskaźnika zostanie pominięty, system zwraca wartość pierwszego wskaźnika, czyli wskaźnika 0 (0).
Obiekty MotionEvent
zawierają informacje o typie używanego wskaźnika. Aby uzyskać typ wskaźnika, wykonaj iteracje za pomocą 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
Dane wejściowe rysika możesz filtrować za pomocą TOOL_TYPE_STYLUS
:
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 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
udostępniają dane osi dotyczące rysika, takie jak współrzędne X i Y, nacisk, orientacja, nachylenie i najechanie kursorem.
Aby umożliwić dostęp do tych danych, interfejs MotionEvent
API udostępnia zmienną getAxisValue(int)
, w której parametrem jest dowolny 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: 1 – gdy jest naciśnięty przycisk główny, 0 – jeśli nie jest naciśnięty. |
AXIS_ORIENTATION |
w przypadku ekranu dotykowego lub touchpada – 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 funkcja MotionEvent.getAxisValue(AXIS_X)
zwraca współrzędną X pierwszego wskaźnika.
Zobacz też Obsługa gestów wielodotykowych.
Pozycja
Współrzędne x i y wskaźnika można pobrać przy użyciu tych wywołań:
MotionEvent#getAxisValue(AXIS_X)
lubMotionEvent#getX()
MotionEvent#getAxisValue(AXIS_Y)
lubMotionEvent#getY()
Ciśnienie
Ciśnienie wskaźnika można pobrać za pomocą MotionEvent#getAxisValue(AXIS_PRESSURE)
lub, w przypadku pierwszego wskaźnika, MotionEvent#getPressure()
.
Wartość nacisku w przypadku ekranów dotykowych lub touchpadów mieści się w zakresie od 0 (brak nacisku) do 1, ale wyższe wartości mogą być zwracane w zależności od kalibracji ekranu.
Orientacja
Orientacja wskazuje, w którym kierunku wskazuje rysik.
Orientację wskaźnika można pobrać za pomocą 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 wdrożenie rzeczywistego pędzla. Jeśli na przykład stylem jest płaski pędzel, jego szerokość zależy od orientacji stylu.
Przechylenie
Pochylenie mierzy pochylenie rysika względem ekranu.
Funkcja przechylania zwraca dodatni kąt rysika w radianach, gdzie 0 jest prostopadłe do ekranu, a liczba π/2 jest płaska na powierzchni.
Kąt nachylenia można określić za pomocą funkcji getAxisValue(AXIS_TILT)
(nie można użyć skrótu do pierwszego wskaźnika).
Za pomocą przechylenia można uzyskać jak najbardziej zbliżone do rzeczywistych narzędzia, np. imitację cieniowania przechylonym ołówkiem.
Najechanie
Odległość rysika od ekranu można sprawdzić za pomocą funkcji getAxisValue(AXIS_DISTANCE)
. Gdy rysik oddala się od ekranu, metoda zwraca wartość z 0,0 (kontakt z ekranem) do wyższych wartości. Odległość między ekranem a stalnikiem (punktem) rysika zależy od producenta zarówno ekranu, jak i rysika. Implementacje mogą się różnić, dlatego w przypadku funkcji o znaczeniu krytycznym dla aplikacji nie należy polegać na precyzyjnych wartościach.
Najechanie rysikiem pozwala wyświetlić podgląd rozmiaru pędzla lub wskazać, że zostanie wybrany przycisk.
Uwaga: w narzędziu Compose dostępne są modyfikatory, które wpływają na interaktywny stan elementów interfejsu:
hoverable
: skonfiguruj komponent tak, aby można było najechać na niego kursorem, korzystając ze zdarzeń wejścia i wyjścia wskaźnika.indication
: po wystąpieniu interakcji generuje efekty wizualne dla tego komponentu.
Odrzucanie dłoni, nawigacja i niechciane dane wejściowe
Czasami ekrany wielodotykowe rejestrują niepożądane dotknięcia, np. gdy użytkownik w naturalny sposób opiera dłoń na ekranie, aby uzyskać wsparcie podczas pisania odręcznego.
Odrzucenie przez Palmę to mechanizm, który wykrywa takie zachowanie i powiadamia Cię o anulowaniu ostatniego zestawu MotionEvent
.
Dlatego musisz przechowywać historię działań wprowadzonych przez użytkownika, aby umożliwić usunięcie z ekranu niepożądanych dotknięć i ponowne wyrenderowanie prawidłowych danych wejściowych użytkownika.
ACTION_CANCEL i FLAG_CANCELED
Zarówno ACTION_CANCEL
, jak i FLAG_CANCELED
informują, że poprzedni zestaw MotionEvent
powinien zostać anulowany od ostatniego ACTION_DOWN
. Dzięki temu można na przykład cofnąć ostatnie pociągnięcie aplikacji do rysowania w przypadku danego wskaźnika.
ACTION_CANCEL
Dodane w Androidzie 1.0 (poziom API 1)
ACTION_CANCEL
wskazuje, że poprzedni zestaw zdarzeń ruchu powinien zostać anulowany.
Funkcja ACTION_CANCEL
jest wyzwalana, gdy zostanie wykryty dowolny z tych elementów:
- Gesty do nawigacji
- Odrzucenie palm
Po wywołaniu zdarzenia ACTION_CANCEL
aktywny wskaźnik należy wskazać za pomocą getPointerId(getActionIndex())
. Następnie usuń kreskę utworzoną przy użyciu tego wskaźnika z historii wprowadzania i ponownie wyrenderuj scenę.
FLAG_CANCELED (ANULOWANO)
Dodano w Androidzie 13 (poziom API 33)
FLAG_CANCELED
wskazuje, że wyświetlający się wskaźnik w górę było wynikiem niezamierzonego dotknięcia użytkownika. Flaga jest zwykle ustawiana, gdy użytkownik przypadkowo dotknie ekranu, np. przez chwytanie urządzenia lub położenie dłoni na ekranie.
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 MotionEvent
od ostatniego ACTION_DOWN
od tego wskaźnika.
Podobnie jak ACTION_CANCEL
, wskaźnik można znaleźć w getPointerId(actionIndex)
.
Pełnoekranowy, obraz od krawędzi do krawędzi i gesty nawigacji
Jeśli aplikacja działa na pełnym ekranie i w pobliżu krawędzi znajdują się interaktywne elementy, takie jak płótno służące do rysowania lub aplikacji do sporządzania notatek, przesunięcie palcem z dołu ekranu w celu wyświetlenia nawigacji lub przeniesienie aplikacji na tło może spowodować niezamierzone kliknięcie obszaru roboczego.
Aby nie dopuszczać do niechcianych dotknięć w aplikacji gestami, możesz skorzystać z zestawów i ACTION_CANCEL
.
Zapoznaj się też z sekcją Odrzucanie, nawigacja i niechciane dane wejściowe.
Użyj metody setSystemBarsBehavior()
i BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
z WindowInsetsController
, aby zapobiegać wywoływaniu niepożądanych zdarzeń dotyku 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 i gestami znajdziesz tutaj:
- Ukrywanie pasków systemowych w trybie pojemnym
- Zapewnianie zgodności dzięki nawigacji przy użyciu gestów
- Wyświetlaj treści w aplikacji od krawędzi do krawędzi
Małe opóźnienie
Czas oczekiwania to czas wymagany przez sprzęt, system i aplikację na przetworzenie i wyrenderowanie danych wejściowych użytkownika.
Czas oczekiwania = przetwarzanie danych wejściowych przez sprzęt i system operacyjny + przetwarzanie aplikacji + komponowanie systemu
- renderowanie sprzętowe
Źródło czasu oczekiwania
- Rejestrowanie rysika na ekranie dotykowym (sprzęt): wstępne połączenie bezprzewodowe, gdy rysik i system operacyjny komunikowają się w celu zarejestrowania i zsynchronizowania.
- Częstotliwość próbkowania ekranu dotykowego (sprzęt): liczba przypadków, gdy ekran dotykowy na sekundę sprawdza, czy wskaźnik dotyka powierzchni. Wartość mieści się w zakresie od 60 do 1000 Hz.
- Przetwarzanie danych wejściowych (aplikacja): stosowanie kolorów, efektów graficznych i przekształcenia na danych wejściowych użytkownika.
- Renderowanie graficzne (system operacyjny i sprzęt): wymiana buforów, przetwarzanie sprzętowe.
Obrazy z małym opóźnieniem
Biblioteka grafiki Jetpack z krótkimi opóźnieniami skraca czas przetwarzania między danymi wprowadzonymi przez użytkownika a renderowaniem na ekranie.
Biblioteka skraca czas przetwarzania, ponieważ eliminuje renderowanie na wielu buforach i wykorzystuje technikę renderowania bufora przedniego, co oznacza pisanie bezpośrednio na ekranie.
Renderowanie bufora przedniego
Przedni bufor to pamięć używana przez ekran do renderowania. To aplikacja, która najlepiej znajduje się na ekranie. Biblioteka o małym opóźnieniu umożliwia renderowanie aplikacji bezpośrednio w przednim buforze. Zwiększa to wydajność, zapobiegając zamienianiu buforów, które ma miejsce w przypadku standardowego renderowania w kilku buforach lub w przypadku podwójnego bufora (najczęstsza sytuacja).
Renderowanie przedniego bufora to świetna technika do renderowania małego obszaru ekranu, ale nie służy do odświeżania całego ekranu. Dzięki renderowaniu przedniego bufora aplikacja renderuje treści w buforze, z którego odczytuje wyświetlacz. W związku z tym istnieje możliwość renderowania artefaktów lub podrażania (patrz poniżej).
Biblioteka niskiego opóźnienia 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 interfejsu API 29) i nowszym.
Zależności
Biblioteka o małym opóźnieniu dostarcza komponenty implementacji renderowania frontendu w trybie bufora. 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 z krótkim czasem oczekiwania zawiera interfejs GLFrontBufferRenderer.Callback
, który definiuje te metody:
W bibliotece małego opóźnienia nie ma znaczenia, jakiego typu danych używasz w usłudze GLFrontBufferRenderer
.
Biblioteka przetwarza jednak dane w postaci strumienia setek punktów danych, projektując je w taki sposób, aby zoptymalizować wykorzystanie i alokację pamięci.
Wywołania zwrotne
Aby włączyć renderowanie wywołań zwrotnych, zaimplementuj funkcję GLFrontBufferedRenderer.Callback
i zastąp onDrawFrontBufferedLayer()
oraz onDrawDoubleBufferedLayer()
.
Funkcja GLFrontBufferedRenderer
używa wywołań zwrotnych, aby renderować dane w możliwie 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. } };
Zadeklarowanie wystąpienia komponentu GLFrontBufferedRenderer
Przygotuj GLFrontBufferedRenderer
, podając utworzone wcześniej wywołania SurfaceView
i wywołania zwrotne. GLFrontBufferedRenderer
optymalizuje renderowanie na przedniej stronie i podwójne buforowanie za pomocą 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 frontendu rozpoczyna się po wywołaniu metody renderFrontBufferedLayer()
, która aktywuje wywołanie zwrotne onDrawFrontBufferedLayer()
.
Renderowanie z podwójnym buforem jest wznawiane po wywołaniu funkcji commit()
, która wywołuje wywołanie zwrotne onDrawMultiDoubleBufferedLayer()
.
W poniższym przykładzie proces renderuje się w przednim buforze (szybkie renderowanie), gdy użytkownik zaczyna rysować na ekranie (ACTION_DOWN
) i przesuwa wskaźnik (ACTION_MOVE
). Proces jest renderowany w podwójnym buforze, gdy wskaźnik opuści powierzchnię ekranu (ACTION_UP
).
Możesz użyć parametru requestUnbufferedDispatch()
, aby zapytać, czy system wejściowy nie grupuje zdarzeń ruchu, ale zamiast tego dostarcza 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 unikać w przypadku renderowania
Małe fragmenty ekranu, pismo odręczne, rysunek, szkicowanie.
Aktualizacja na pełnym ekranie, przesuwanie, powiększanie. Może dojść do rozerwania.
Rozdarcie
Zerwanie ma miejsce, gdy ekran odświeża się, gdy jednocześnie zmieniasz bufor ekranu. Na innej części ekranu widać nowe dane, a inna – stare.
Przewidywanie ruchu
Biblioteka prognozowania ruchu Jetpacka zmniejsza widoczne opóźnienie, szacując ścieżkę użytkownika i przekazując mechanizmowi renderowania tymczasowe, sztuczne punkty.
Biblioteka prognozowania ruchu pobiera dane wejściowe użytkownika jako obiekty MotionEvent
.
Obiekty zawierają informacje o współrzędnych x i y, ciśnieniu i czasie, które są używane przez prognozy ruchu do prognozowania przyszłych obiektów MotionEvent
.
Prognozowane obiekty MotionEvent
są tylko szacunkami. Prognozowane zdarzenia mogą zmniejszyć postrzegany czas oczekiwania, ale dane prognozowane muszą zostać zastąpione rzeczywistymi danymi MotionEvent
po ich otrzymaniu.
Biblioteka prognozowania ruchu jest dostępna od Androida 4.4 (poziom interfejsu API 19) i nowszych oraz na urządzeniach z ChromeOS z Androidem 9 (poziom interfejsu API 28) lub nowszym.
Zależności
Implementację prognozowania umożliwia biblioteka prognozowania ruchu. 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 prognozowania ruchu zawiera interfejs MotionEventPredictor
, który definiuje te metody:
record()
: przechowuje obiektyMotionEvent
jako zapis działań użytkownikapredict()
: Zwraca przewidywaną wartośćMotionEvent
Zadeklaruj wystąpienie instancji MotionEventPredictor
Kotlin
var motionEventPredictor = MotionEventPredictor.newInstance(view)
Java
MotionEventPredictor motionEventPredictor = MotionEventPredictor.newInstance(surfaceView);
Dodaj dane do prognozowania
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; }
Zalecenia i ograniczenia związane z prognozowaniem ruchu
Usuń punkty prognozy po dodaniu nowego przewidywanego punktu.
Nie używaj punktów prognozy do ostatecznego renderowania.
Notatki
ChromeOS umożliwia aplikacji deklarowanie niektórych działań związanych z robieniem notatek.
Aby zarejestrować aplikację jako aplikację do robienia notatek w ChromeOS, zapoznaj się z sekcją Zgodność urządzeń wejściowych.
Aby zarejestrować aplikację do robienia notatek na Androidzie, przeczytaj artykuł Tworzenie aplikacji do notatek.
W Androidzie 14 (poziom interfejsu API 34) wprowadziliśmy intencję ACTION_CREATE_NOTE
, która umożliwia aplikacji uruchamianie notatek na ekranie blokady.
Rozpoznawanie cyfrowego atramentu przy użyciu ML Kit
Dzięki funkcjom rozpoznawania cyfrowego atramentu ML Kit aplikacja rozpoznaje odręczny tekst na platformie cyfrowej w setkach języków. Możesz też klasyfikować szkice.
ML Kit udostępnia klasę Ink.Stroke.Builder
do tworzenia obiektów Ink
, które modele systemów uczących się mogą przetworzyć w celu konwertowania pisma odręcznego na tekst.
Oprócz rozpoznawania pisma odręcznego model rozpoznaje gesty, takie jak usuwanie czy zakreślanie.
Więcej informacji znajdziesz w sekcji Rozpoznawanie cyfrowego atramentu.