Instrukcje

Przedstawiamy Cahier: nowy przykład kodu Androida na GitHubie dotyczący produktywności i kreatywności na dużych ekranach

Czas czytania: 11 minut
Chris Assigbe
Inżynier ds. relacji z deweloperami

Ink API jest teraz w wersji beta i możesz go zintegrować z aplikacją. Ten kamień milowy został osiągnięty dzięki cennym opiniom deweloperów, które pozwoliły nam stale ulepszać wydajność, stabilność i jakość wizualną interfejsu API.

Aplikacje Google, takie jak Dokumenty Google, Pixel Studio, Zdjęcia Google, Chrome PDF, Kreator efektów YouTube i unikalne funkcje na Androidzie, takie jak Zaznacz, aby wyszukać, korzystają z najnowszych interfejsów API. 

Z tej okazji z przyjemnością ogłaszamy wprowadzenie Cahier, kompleksowej aplikacji do robienia notatek zoptymalizowanej pod kątem urządzeń z Androidem o różnych rozmiarach, zwłaszcza tabletów i telefonów składanych.

Co to jest Cahier?

Cahier (z francuskiego „zeszyt”) to przykładowa aplikacja, która pokazuje, jak stworzyć aplikację umożliwiającą użytkownikom zapisywanie i porządkowanie myśli poprzez łączenie tekstu, rysunków i obrazów. 

Przykładowy kod może służyć jako punkt odniesienia do zwiększania produktywności i kreatywności użytkowników na dużych ekranach. Pokazuje sprawdzone metody tworzenia takich funkcji, przyspieszając zrozumienie przez deweloperów powiązanych, zaawansowanych interfejsów API i technik oraz ich wdrażanie. W tym poście znajdziesz opis najważniejszych funkcji Cahier, kluczowych interfejsów API i decyzji architektonicznych, które sprawiają, że ten przykład jest doskonałym odniesieniem dla Twoich aplikacji.

Przykładowe funkcje:

  • Wszechstronne tworzenie notatek: pokazuje, jak wdrożyć elastyczny system tworzenia treści, który obsługuje wiele formatów w ramach jednej notatki, w tym tekst, rysunki odręczne i załączniki w postaci obrazów.
  • Kreatywne narzędzia do rysowania: zapewniają wysoką wydajność i małe opóźnienia podczas rysowania dzięki interfejsowi Ink API. Przykładowy kod zawiera praktyczny przykład integracji różnych pędzli, próbnika kolorów, funkcji cofania i ponawiania oraz narzędzia do wymazywania.
  • Płynna integracja treści z funkcją przeciągania i upuszczania: pokazuje, jak obsługiwać treści przychodzące i wychodzące za pomocą funkcji przeciągania i upuszczania. Obejmuje to akceptowanie obrazów upuszczonych z innych aplikacji i umożliwianie użytkownikom przeciągania treści z aplikacji w celu bezproblemowego udostępniania.
  • Organizowanie notatek: oznaczaj notatki jako ulubione, aby mieć do nich szybki dostęp. Filtruj widok, aby zachować porządek.
  • Architektura offline first: aplikacja została stworzona w architekturze offline first z użyciem Room, dzięki czemu wszystkie dane są zapisywane lokalnie, a aplikacja pozostaje w pełni funkcjonalna bez połączenia z internetem.
  • Zaawansowana obsługa trybu podzielonego i trybu wielu okien: pokazuje, jak obsługiwać wiele instancji, umożliwiając uruchamianie aplikacji w wielu oknach, aby użytkownicy mogli pracować nad różnymi notatkami obok siebie, co zwiększa produktywność i kreatywność na dużych ekranach.
  • Adaptacyjny interfejs użytkownika na wszystkich ekranach: interfejs użytkownika płynnie dostosowuje się do różnych rozmiarów i orientacji ekranu za pomocą komponentów ListDetailPaneScaffoldNavigationSuiteScaffold, aby zapewnić optymalne wrażenia użytkownikom na telefonach, tabletach i urządzeniach składanych.
  • Głęboka integracja z systemem: przewodnik po tym, jak sprawić, aby aplikacja stała się domyślną aplikacją do robienia notatek na urządzeniach z Androidem 14 lub nowszym. Wystarczy, że będzie ona odpowiadać na intencje dotyczące notatek w systemie, co umożliwi szybkie przechwytywanie treści z różnych punktów wejścia w systemie.

Urządzenie stworzone z myślą o produktywności i kreatywności na dużych ekranach

Na początku skupimy się na kilku głównych funkcjach, które sprawiają, że Cahier to kluczowy materiał do nauki, zarówno w przypadku produktywności, jak i kreatywności.

Podstawa adaptacyjności

Cahier został zaprojektowany od podstaw z myślą o adaptacyjności. Przykładowa aplikacja korzysta z biblioteki material3-adaptive, a w szczególności z komponentów ListDetailPaneScaffoldNavigationSuiteScaffold, aby płynnie dostosowywać układ aplikacji do różnych rozmiarów i orientacji ekranu. Jest to kluczowy element nowoczesnej aplikacji na Androida, a Cahier stanowi jasny przykład tego, jak go skutecznie wdrożyć.

Interfejs adaptacyjny Cahier utworzony za pomocą biblioteki adaptacyjnej Material 3.gif

Interfejs adaptacyjny Cahier oparty na bibliotece adaptacyjnej Material 3

Prezentacja najważniejszych interfejsów API i integracji

Przykłady koncentrują się na prezentowaniu zaawansowanych interfejsów API zwiększających produktywność, które możesz wykorzystać we własnych aplikacjach, w tym:

Szczegółowe informacje o kluczowych interfejsach API

Przyjrzyjmy się bliżej dwóm podstawowym interfejsom API, które Cahier integruje, aby zapewnić najwyższą jakość notowania.

Tworzenie naturalnych doświadczeń związanych z pisaniem odręcznym za pomocą interfejsu Ink API

Wejście za pomocą rysika przekształca urządzenia z dużym ekranem w cyfrowe notatniki i szkicowniki. Aby pomóc Ci w tworzeniu płynnych i naturalnych wrażeń związanych z pisaniem, uczyniliśmy interfejs Ink API podstawą przykładu. Interfejs Ink API ułatwia tworzenie, renderowanie i manipulowanie pięknymi pociągnięciami pióra przy zachowaniu najkrótszego czasu oczekiwania.

Interfejs Ink API ma architekturę modułową, dzięki czemu możesz dostosować go do konkretnego stosu i potrzeb aplikacji. Moduły interfejsu API obejmują:

  • Moduły do tworzenia treści (Tworzenie – widoki): obsługują wprowadzanie pisma odręcznego w czasie rzeczywistym, aby tworzyć płynne pociągnięcia z najmniejszym opóźnieniem, jakie może zapewnić urządzenie.
    • DrawingSurface Cahier używa nowo wprowadzonego komponentu InProgressStrokes do obsługi danych wejściowych z rysika lub dotyku w czasie rzeczywistym. Ten moduł odpowiada za rejestrowanie zdarzeń wskaźnika i renderowanie pociągnięć mokrym atramentem z najmniejszym możliwym opóźnieniem.
  • Moduł Strokes: reprezentuje dane wejściowe dotyczące pisma odręcznego i ich wizualną reprezentację. Gdy użytkownik skończy rysować linię, wywołanie zwrotne onStrokesFinished przekazuje do aplikacji ostateczny obiekt Stroke. Ten niezmienny obiekt, który reprezentuje ukończone pociągnięcie piórem, jest następnie zarządzany w DrawingCanvasViewModel.
  • Moduł renderowania: wydajnie wyświetla pociągnięcia piórem, umożliwiając ich łączenie z Jetpack Compose lub widokami Androida.
  • Moduły pędzla (Composewidoki): umożliwiają deklaratywne określanie stylu wizualnego pociągnięć. Ostatnie aktualizacje (od wersji alpha03) obejmują nowe narzędzie do rysowania linii przerywanych, które jest szczególnie przydatne w przypadku funkcji takich jak zaznaczanie lassem. DrawingCanvasViewModel przechowuje stan bieżącego pędzla. Panel narzędzi w DrawingCanvas umożliwia użytkownikom wybieranie różnych rodzin pędzli (np. StockBrushes.pressurePen() lub StockBrushes.highlighter()) i zmianę kolorów. ViewModel aktualizuje obiekt Brush, który jest następnie używany przez komponent InProgressStrokes do tworzenia nowych pociągnięć.
  • Moduły geometrii (Compose – widoki): umożliwiają manipulowanie pociągnięciami i ich analizowanie na potrzeby funkcji takich jak wymazywanie i wybieranie.
    • Narzędzie do wymazywania w przyborniku i funkcje w DrawingCanvasViewModel korzystają z modułu geometrii. Gdy gumka jest aktywna, tworzy MutableParallelogram wokół ścieżki gestu użytkownika. Gumka sprawdza następnie przecięcia między kształtem a ramkami ograniczającymi istniejących pociągnięć, aby określić, które pociągnięcia należy usunąć. Dzięki temu gumka jest intuicyjna i precyzyjna.
  • Moduł Storage: zapewnia wydajne możliwości serializacji i deserializacji danych o atramencie, co pozwala znacznie zmniejszyć rozmiar dysku i sieci. Aby zapisać rysunki, Cahier przechowuje obiekty Stroke w bazie danych Room. W sekcji Konwertery przykład używa funkcji encode modułu pamięci do serializacji StrokeInputBatch (surowych danych punktowych) do postaci ByteArray. Tablica bajtów wraz z właściwościami pędzla jest zapisywana jako ciąg znaków JSON. Funkcja decode służy do odtwarzania pociągnięć piórem podczas wczytywania notatki.
orion.png

Oprócz tych podstawowych modułów ostatnie aktualizacje rozszerzyły możliwości interfejsu Ink API:

  • Nowe eksperymentalne interfejsy API dla niestandardowych obiektów BrushFamily umożliwiają programistom tworzenie kreatywnych i unikalnych rodzajów pędzli, co daje możliwości tworzenia narzędzi takich jak pędzle OłówekWskaźnik laserowy.

Cahier wykorzystuje niestandardowe pędzle, w tym unikalny pędzel muzyczny pokazany poniżej, aby zilustrować zaawansowane możliwości twórcze.

Tęczowy laser utworzony za pomocą niestandardowych pędzli interfejsu Ink API.gif

Tęcza utworzona za pomocą niestandardowych pędzli interfejsu Ink API

notes.png

Pędzel muzyczny utworzony za pomocą pędzli niestandardowych interfejsu Ink API

  • Moduły interoperacyjności Jetpack Compose ułatwiają integrację funkcji pisania odręcznego bezpośrednio w interfejsach Compose, co zapewnia bardziej idiomatyczne i wydajne środowisko programistyczne.

Interfejs Ink API ma kilka zalet, które sprawiają, że jest idealnym wyborem dla aplikacji zwiększających produktywność i kreatywność w porównaniu z niestandardową implementacją:

  • Łatwość używania: interfejs Ink API upraszcza złożone aspekty grafiki i geometrii, dzięki czemu możesz skupić się na podstawowych funkcjach Cahier.
  • Wydajność: wbudowana obsługa małych opóźnień i zoptymalizowane renderowanie zapewniają płynne i szybkie pisanie.
  • Elastyczność: modułowa konstrukcja umożliwia wybieranie potrzebnych komponentów, co pozwala na płynną integrację interfejsu Ink API z architekturą Cahier.

Interfejs Ink API został już wdrożony w wielu aplikacjach Google, m.in. w funkcji adnotacji w Dokumentach i w funkcji „Zaznacz, aby wyszukać”, a także w aplikacjach partnerów, takich jak Orion NotesSkaner PDF.

„Interfejs Ink API był naszym pierwszym wyborem w przypadku funkcji „Zaznacz, aby wyszukać”. Dzięki obszernej dokumentacji integracja interfejsu Ink API była bardzo prosta i umożliwiła nam stworzenie pierwszego działającego prototypu w ciągu zaledwie tygodnia. Dzięki niestandardowej teksturze pędzla i obsłudze animacji w Ink mogliśmy szybko iterować projekt pociągnięcia”. – Jordan Komoda, inżynier oprogramowania w Google

Ustawianie domyślnej aplikacji do notatek z rolą notatek

Robienie notatek to podstawowa funkcja, która zwiększa produktywność użytkowników urządzeń z dużym ekranem. Dzięki funkcji roli notatek użytkownicy mogą uzyskiwać dostęp do zgodnych aplikacji z poziomu ekranu blokady lub podczas korzystania z innych aplikacji. Ta funkcja identyfikuje i ustawia domyślne aplikacje do robienia notatek w całym systemie oraz przyznaje im uprawnienia do uruchamiania w celu zapisywania treści. 

Implementacja w Cahier

Wdrożenie roli notatki obejmuje kilka kluczowych kroków, które zostały przedstawione w przykładzie:

  1. Deklaracja w pliku manifestu: najpierw aplikacja musi zadeklarować, że może obsługiwać intencje związane z robieniem notatek. W pliku AndroidManifest.xml aplikacja Cahier zawiera <intent-filter> dla działania android.intent.action.CREATE_NOTE. Sygnalizuje to systemowi, że aplikacja może pełnić rolę notatek.
  2. Sprawdzanie stanu roli: SettingsViewModel używa RoleManager Androida do określania bieżącego stanu. SettingsViewModel sprawdza, czy rola notatek jest dostępna na urządzeniu (isRoleAvailable), i czy Cahier ma obecnie tę rolę (isRoleHeld). Ten stan jest udostępniany interfejsowi za pomocą przepływów Kotlin.
  3. Prośba o rolę: w pliku Settings.kt wyświetla się przycisk, jeśli rola jest dostępna, ale nie jest przypisana do użytkownika. Po kliknięciu przycisku wywoływana jest funkcja requestNotesRole w obiekcie ViewModel. Funkcja tworzy intencję otwarcia domyślnego ekranu ustawień aplikacji, na którym użytkownik może wybrać Cahier. Proces jest zarządzany za pomocą interfejsu API rememberLauncherForActivityResult, który obsługuje uruchamianie intencji i odbieranie wyniku.
  4. Aktualizowanie interfejsu: gdy użytkownik wróci z ekranu ustawień, wywołanie zwrotne ActivityResultLauncher uruchomi w ViewModel funkcję aktualizującą stan roli, dzięki czemu interfejs będzie prawidłowo odzwierciedlać, czy aplikacja jest teraz domyślna.

Więcej informacji o integracji roli notatek w aplikacji znajdziesz w naszym przewodniku po tworzeniu aplikacji do robienia notatek.

helloworld.png

Cahier uruchamia się w pływającym oknie jako domyślna aplikacja do robienia notatek na tablecie Lenovo

Ważny krok naprzód: Lenovo umożliwia korzystanie z roli Notatki

Z przyjemnością informujemy o ważnym kroku w zwiększaniu produktywności na urządzeniach z Androidem wyposażonych w duży ekran: firma Lenovo wprowadziła obsługę roli Notatki na tabletach z Androidem 15 i nowszym. Dzięki tej aktualizacji możesz zaktualizować aplikacje do robienia notatek, aby użytkownicy zgodnych urządzeń Lenovo mogli ustawić je jako domyślne, co zapewni bezproblemowy dostęp z ekranu blokady i odblokuje funkcje przechwytywania treści na poziomie systemu.

To zobowiązanie ze strony wiodącego producenta OEM pokazuje rosnące znaczenie notatek w zapewnianiu prawdziwie zintegrowanych i wydajnych wrażeń użytkownika na Androidzie. 

Tryb podzielony, tryb wielu okien i tryb okien na pulpicie

Produktywność na dużym ekranie polega na efektywnym zarządzaniu informacjami i przepływami pracy. Dlatego Cahier w pełni wykorzystuje zaawansowane funkcje okien Androida, zapewniając elastyczną przestrzeń roboczą, która dostosowuje się do potrzeb użytkownika. Aplikacja obsługuje:

  • Wielookienkowość: podstawowa funkcja umożliwiająca uruchamianie aplikacji obok siebie w trybie podzielonego ekranu lub w trybie dowolnym. Jest to niezbędne w przypadku zadań takich jak odwoływanie się do strony internetowej podczas robienia notatek w Cahier.
  • Tryb podzielony: w tym trybie wielozadaniowość jest naprawdę przydatna. Cahier umożliwia użytkownikom otwieranie wielu niezależnych okien aplikacji jednocześnie. Wyobraź sobie porównywanie dwóch różnych notatek obok siebie lub odwoływanie się do notatki tekstowej w jednym oknie podczas pracy nad rysunkiem w innym. Cahier pokazuje, jak zarządzać tymi oddzielnymi instancjami, z których każda ma własny stan, przekształcając aplikację w potężne, wieloaspektowe narzędzie.
  • Tryb okien na pulpicie: po podłączeniu do wyświetlacza zewnętrznego tryb pulpitu Androida przekształca tablet lub urządzenie składane w stację roboczą. Cahier ma adaptacyjny interfejs i obsługuje tryb podzielony, więc w tym środowisku działa bez zarzutu. Użytkownicy mogą otwierać, zmieniać rozmiar i położenie wielu okien Cahier tak jak na tradycyjnym komputerze, co umożliwia złożone procesy, które wcześniej były niedostępne na urządzeniach mobilnych.
cahier-desktop-windowing.webp

Aplikacja Cahier w trybie okna na urządzeniu Pixel Tablet

Oto jak wdrożyliśmy te funkcje w Cahier:

Aby włączyć tryb podzielony, musieliśmy najpierw poinformować system, że aplikacja obsługuje wielokrotne uruchamianie, dodając właściwość PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI do deklaracji MainActivityAndroidManifest:

<activity

    android:name="com.example.cahier.MainActivity"

    android:exported="true"

    android:label="@string/app_name"

    android:theme="@style/Theme.MyApplication"

    android:showWhenLocked="true"

    android:turnScreenOn="true"

    android:resizeableActivity="true"

    android:launchMode="singleInstancePerTask">


    <property

        android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"

        android:value="true"/>

    ...

</activity>

Następnie wdrożyliśmy logikę uruchamiania nowej instancji aplikacji. W pliku CahierHomeScreen.kt, gdy użytkownik zdecyduje się otworzyć notatkę w nowym oknie, tworzymy nowy obiekt Intent z określonymi flagami, które informują system o tym, jak obsługiwać uruchamianie nowego działania. Połączenie klawiszy FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_MULTIPLE_TASKFLAG_ACTIVITY_LAUNCH_ADJACENT sprawia, że notatka otwiera się w nowym, osobnym oknie obok istniejącego.

fun openNewWindow(activity: Activity?, note: Note) {

    val intent = Intent(activity, MainActivity::class.java)

    intent.putExtra(AppArgs.NOTE_TYPE_KEY, note.type)

    intent.putExtra(AppArgs.NOTE_ID_KEY, note.id)

    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or

        Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT


    activity?.startActivity(intent)

}

Aby obsługiwać tryb wielu okien, musieliśmy poinformować system, że aplikacja obsługuje zmianę rozmiaru, ustawiając element <activity> lub <application> w pliku manifestu.

<activity

    android:name="com.example.cahier.MainActivity"

    android:resizeableActivity="true"

    ...>

</activity>

Interfejs użytkownika jest zbudowany przy użyciu biblioteki adaptacyjnej Material 3, dzięki czemu może się płynnie dostosowywać w scenariuszach z wieloma oknami, takich jak tryb podzielonego ekranu na Androidzie. 

Aby zwiększyć komfort użytkowników, dodaliśmy obsługę przeciągania i upuszczania. Poniżej dowiesz się, jak zaimplementowaliśmy to w Cahier.

Przeciąganie i upuszczanie

Prawdziwie produktywna lub kreatywna aplikacja nie działa w izolacji, ale płynnie współdziała z pozostałymi elementami ekosystemu urządzenia. Przeciąganie i upuszczanie to podstawa tej interakcji, zwłaszcza na dużych ekranach, na których użytkownicy często pracują w wielu oknach aplikacji. Cahier w pełni wykorzystuje tę funkcję, implementując intuicyjną funkcję przeciągania i upuszczania zarówno w przypadku dodawania, jak i udostępniania treści.

  • Łatwe importowanie: użytkownicy mogą przeciągać obrazy z innych aplikacji, takich jak przeglądarka internetowa, galeria zdjęć lub menedżer plików, i upuszczać je bezpośrednio na obszar notatki. W tym celu Cahier używa modyfikatora dragAndDropTarget, aby zdefiniować strefę upuszczania, sprawdzić zgodność treści (np. image/*) i przetworzyć przychodzący identyfikator URI.
  • Łatwe udostępnianie: treści w Cahier można udostępniać tak samo łatwo jak treści z innych aplikacji. Użytkownicy mogą przytrzymać obraz w nocie tekstowej lub przytrzymać całe pole robocze notatki z rysunkiem i kompozycją obrazu, a następnie przeciągnąć je do innej aplikacji.

Szczegółowe informacje techniczne: przeciąganie z obszaru rysowania

Wdrożenie gestu przeciągnięcia w obszarze rysowania stanowi wyjątkowe wyzwanie. W naszym DrawingSurface elementy kompozycyjne, które obsługują dane wejściowe rysowania na żywo (InProgressStrokes interfejsu Ink API) i Box, który wykrywa gest długiego naciśnięcia, aby rozpocząć przeciąganie, są elementami kompozycyjnymi tego samego poziomu.

Domyślnie system danych wejściowych wskaźnika Jetpack Compose jest zaprojektowany tak, aby tylko jeden element kompozycyjny na tym samym poziomie – pierwszy w kolejności deklaracji, który pokrywa się z miejscem dotknięcia – otrzymywał zdarzenie. W przypadku Cahier chcemy, aby nasza logika obsługi danych wejściowych typu „przeciągnij i upuść” miała szansę na uruchomienie i potencjalne wykorzystanie danych wejściowych, zanim funkcja kompozycyjna InProgressStrokes użyje wszystkich niewykorzystanych danych wejściowych do rysowania, a następnie je wykorzysta. Jeśli nie ułożymy ich w odpowiedniej kolejności, urządzenie Box nie wykryje gestu długiego naciśnięcia, aby rozpocząć przeciąganie, lub InProgressStrokes nie otrzyma danych wejściowych do rysowania.

Aby rozwiązać ten problem, utworzyliśmy niestandardowy modyfikator pointerInputWithSiblingFallthrough i umieściliśmy nasz element Box, który korzysta z tego modyfikatora, przed elementem InProgressStrokes w kodzie funkcji kompozycyjnej. To narzędzie jest cienką otoczką standardowego systemu pointerInput, ale z jedną kluczową zmianą: zastępuje funkcję sharePointerInputWithSiblings(), aby zwracać wartość true. Informuje to platformę Compose, że zdarzenia wskaźnika mogą przechodzić do elementów kompozycyjnych tego samego poziomu, nawet po ich wykorzystaniu.

internal fun Modifier.pointerInputWithSiblingFallthrough(

    pointerInputEventHandler: PointerInputEventHandler

) = this then PointerInputSiblingFallthroughElement(pointerInputEventHandler)


private class PointerInputSiblingFallthroughModifierNode(

    pointerInputEventHandler: PointerInputEventHandler

) : PointerInputModifierNode, DelegatingNode() {


    var pointerInputEventHandler: PointerInputEventHandler

        get() = delegateNode.pointerInputEventHandler

        set(value) {

            delegateNode.pointerInputEventHandler = value

        }


    val delegateNode = delegate(

        SuspendingPointerInputModifierNode(pointerInputEventHandler)

    )


    override fun onPointerEvent(

        pointerEvent: PointerEvent,

        pass: PointerEventPass,

        bounds: IntSize

    ) {

        delegateNode.onPointerEvent(pointerEvent, pass, bounds)

    }


    override fun onCancelPointerInput() {

        delegateNode.onCancelPointerInput()

    }


    override fun sharePointerInputWithSiblings() = true

}


private data class PointerInputSiblingFallthroughElement(

    val pointerInputEventHandler: PointerInputEventHandler

) : ModifierNodeElement<PointerInputSiblingFallthroughModifierNode>() {


    override fun create() = PointerInputSiblingFallthroughModifierNode(pointerInputEventHandler)


    override fun update(node: PointerInputSiblingFallthroughModifierNode) {

        node.pointerInputEventHandler = pointerInputEventHandler

    }


    override fun InspectorInfo.inspectableProperties() {

        name = "pointerInputWithSiblingFallthrough"

        properties["pointerInputEventHandler"] = pointerInputEventHandler

    }

}

Oto jak jest używany w DrawingSurface:

Box(

    modifier = Modifier

        .fillMaxSize()

        // Our custom modifier enables this gesture to coexist with the drawing input.

        .pointerInputWithSiblingFallthrough {

            detectDragGesturesAfterLongPress(

                onDragStart = { onStartDrag() },

                onDrag = { _, _ -> /* consume drag events */ },

                onDragEnd = { /* No action needed */ }

            )

        }

) 

// The Ink API's composable for live drawing sits here as a sibling.

InProgressStrokes(...)

Dzięki temu system prawidłowo wykrywa jednocześnie pociągnięcia rysika i gest przeciągnięcia z długim naciśnięciem. Po rozpoczęciu przeciągania tworzymy identyfikator URI z możliwością udostępniania content:// za pomocą klasy FileProvider i przekazujemy identyfikator URI do systemu przeciągania i upuszczania za pomocą metody view.startDragAndDrop(). To rozwiązanie zapewnia solidne i intuicyjne wrażenia użytkownika, pokazując, jak pokonać złożone konflikty gestów w warstwowych interfejsach.

Nowoczesna architektura

Oprócz konkretnych interfejsów API Cahier prezentuje kluczowe wzorce architektoniczne do tworzenia wysokiej jakości aplikacji adaptacyjnych.

Warstwa prezentacji: Jetpack Compose i dostosowywanie

Warstwa prezentacji jest w całości zbudowana za pomocą Jetpack Compose. Jak wspomnieliśmy, Cahier korzysta z biblioteki material3-adaptive, aby dostosowywać interfejs. Zarządzanie stanem odbywa się zgodnie ze ścisłym wzorcem jednokierunkowego przepływu danych (UDF), a instancje ViewModel są używane jako kontenery danych, które zawierają informacje o notatkach i stan interfejsu.

Warstwa danych: repozytoria i biblioteka Room

W przypadku warstwy danych Cahier używa interfejsu NoteRepository do abstrakcyjnego przedstawiania wszystkich operacji na danych. Dzięki temu aplikacja może łatwo przełączać się między lokalnym źródłem danych (Room) a potencjalnym przyszłym backendem zdalnym. Przepływ danych w przypadku działania takiego jak edytowanie notatki jest prosty:

  1. Interfejs Jetpack Compose wywołuje metodę w obiekcie ViewModel.
  2. ViewModel pobiera notatkę z NoteRepository, obsługuje logikę i przekazuje zaktualizowaną notatkę z powrotem do repozytorium.
  3. NoteRepository zapisuje aktualizację w bazie danych Room.

Kompleksowa obsługa wprowadzania danych

Aby aplikacja była naprawdę wydajna, musi bezbłędnie obsługiwać różne metody wprowadzania danych. Cahier jest zgodny z wytycznymi dotyczącymi wprowadzania danych na dużych ekranach i obsługuje:

  • Rysik: integracja z interfejsem Ink API, odrzucanie dłoni, rejestracja w roli notatek, wpisywanie rysikiem w polach tekstowych i tryb immersyjny.
  • Klawiatura: obsługa najpopularniejszych skrótów klawiszowych i kombinacji (np. Ctrl+kliknięcie, Meta+kliknięcie) oraz wyraźne wskazanie fokusu klawiatury.
  • Mysz i trackpad: obsługa kliknięcia prawym przyciskiem myszy i stanów najechania kursorem.

Obsługa zaawansowanych interakcji z klawiaturą, myszą i trackpadem jest kluczowym elementem dalszych ulepszeń. 

Zacznij już dziś

Mamy nadzieję, że Cahier będzie dla Ciebie punktem wyjścia do stworzenia kolejnej świetnej aplikacji. Została ona zaprojektowana jako kompleksowe, otwarte źródło informacji, które pokazuje, jak połączyć adaptacyjny interfejs użytkownika, zaawansowane interfejsy API, takie jak Ink i rola notatek, oraz nowoczesną, adaptacyjną architekturę.

Wszystko gotowe?

  • Poznaj kod: przejdź do naszego repozytorium GitHub, aby poznać bazę kodu Cahier i zobaczyć, jak działają zasady projektowania.
  • Stwórz własną: użyj Cahier jako podstawy własnej aplikacji do robienia notatek, oznaczania dokumentów lub tworzenia treści.
  • Udostępnianie treści: chętnie poznamy Twoją opinię. Pomóż nam ulepszyć Cahier, aby był jeszcze lepszym źródłem informacji dla społeczności deweloperów Androida.

Zapoznaj się z oficjalnymi przewodnikami dla programistów i już dziś zacznij tworzyć aplikację nowej generacji, która zwiększy produktywność i kreatywność. Nie możemy się doczekać, co stworzysz.

Autor:

Czytaj dalej