Anleitungen

Cahier: Neues Android-GitHub-Beispiel für Produktivität und Kreativität auf großen Displays

Lesezeit: 11 Minuten
Chris Assigbe
Developer Relations Engineer

Die Ink API befindet sich jetzt in der Betaphase und kann in Ihre App eingebunden werden. Dieser Meilenstein wurde durch wertvolles Entwicklerfeedback ermöglicht, das zu kontinuierlichen Verbesserungen der Leistung, Stabilität und visuellen Qualität der API geführt hat.

Google-Apps wie Google Docs, Pixel Studio, Google Fotos, Chrome PDF, YouTube Effect Maker und einzigartige Funktionen auf Android wie Circle to Search verwenden alle die neuesten APIs. 

Anlässlich dieses Meilensteins freuen wir uns, die Einführung von Cahier bekanntzugeben. Dabei handelt es sich um eine umfassende Beispiel-App für Notizen, die für Android-Geräte aller Größen optimiert ist, insbesondere für Tablets und faltbare Smartphones.

Was ist Cahier?

Cahier („Notizbuch“ auf Französisch) ist eine Beispiel-App, die zeigt, wie Sie eine Anwendung erstellen können, mit der Nutzer ihre Gedanken in Form von Text, Zeichnungen und Bildern festhalten und organisieren können. 

Das Beispiel kann als Referenz dienen, um die Produktivität und Kreativität der Nutzer auf großen Bildschirmen zu steigern. Darin werden Best Practices für die Entwicklung solcher Funktionen vorgestellt, um das Verständnis und die Einführung der zugehörigen leistungsstarken APIs und Techniken durch Entwickler zu beschleunigen. In diesem Beitrag werden die wichtigsten Funktionen von Cahier, die wichtigsten APIs und die Architekturentscheidungen beschrieben, die das Beispiel zu einer hervorragenden Referenz für Ihre eigenen Apps machen.

Die wichtigsten Funktionen, die im Beispiel demonstriert werden:

  • Vielseitige Notizenerstellung:Hier wird gezeigt, wie Sie ein flexibles System zur Inhaltserstellung implementieren, das mehrere Formate in einer einzelnen Notiz unterstützt, darunter Text, Freihandzeichnungen und Bildanhänge.
  • Tools für kreatives Inking: Implementiert eine leistungsstarke Zeichenfunktion mit geringer Latenz mithilfe der Ink API. Das Beispiel bietet ein praktisches Beispiel für die Integration verschiedener Pinsel, einer Farbauswahl, der Funktionen „Rückgängig“ und „Wiederholen“ sowie eines Radiergummis.
  • Integration von fließenden Inhalten per Drag-and-drop: Hier wird gezeigt, wie eingehende und ausgehende Inhalte per Drag-and-drop verarbeitet werden. Dazu gehört, dass Sie Bilder akzeptieren, die aus anderen Apps gezogen werden, und Nutzern ermöglichen, Inhalte aus Ihrer App zu ziehen, um sie nahtlos zu teilen.
  • Notizen organisieren: Markieren Sie Notizen als Favoriten, um schnell darauf zugreifen zu können. Ansicht filtern, um den Überblick zu behalten
  • Offline-First-Architektur:Die App wurde mit einer Offline-First-Architektur mit Room entwickelt. So werden alle Daten lokal gespeichert und die App bleibt auch ohne Internetverbindung voll funktionsfähig.
  • Leistungsstarke Unterstützung für Mehrfenstermodus und mehrere Instanzen: Hier wird gezeigt, wie Sie mehrere Instanzen unterstützen, damit Ihre App in mehreren Fenstern gestartet werden kann. So können Nutzer auf großen Bildschirmen nebeneinander an verschiedenen Notizen arbeiten, was die Produktivität und Kreativität steigert.
  • Adaptive Benutzeroberfläche für alle Bildschirme: Die Benutzeroberfläche passt sich nahtlos an verschiedene Bildschirmgrößen und ‑ausrichtungen an. Dazu werden ListDetailPaneScaffold und NavigationSuiteScaffold verwendet, um eine optimierte Nutzerfreundlichkeit auf Smartphones, Tablets und faltbaren Geräten zu bieten.
  • Umfassende Systemintegration: Hier erfahren Sie, wie Sie Ihre App zur Standard-Notizen-App unter Android 14 und höher machen können, indem Sie auf systemweite Notes-Intents reagieren und so das schnelle Erfassen von Inhalten über verschiedene Systemeinstiegspunkte ermöglichen.

Für Produktivität und Kreativität auf großen Displays entwickelt

Bei der ersten Einführung konzentrieren wir uns auf einige Kernfunktionen, die Cahier zu einer wichtigen Lernressource für Produktivitäts- und Kreativitätsanwendungsfälle machen.

Grundlage für Anpassungsfähigkeit

Cahier wurde von Grund auf so konzipiert, dass es sich anpasst. Im Beispiel werden die Bibliothek material3-adaptive und insbesondere ListDetailPaneScaffold und NavigationSuiteScaffold verwendet, um das App-Layout nahtlos an verschiedene Bildschirmgrößen und ‑ausrichtungen anzupassen. Dies ist ein wichtiger Bestandteil einer modernen Android-App. Cahier bietet ein klares Beispiel dafür, wie Sie ihn effektiv implementieren können.

Cahier adaptive UI built with Material 3 Adaptive library..gif

Adaptive Benutzeroberfläche von Cahier, die mit der adaptiven Material 3-Bibliothek erstellt wurde

Wichtige APIs und Integrationen präsentieren

Das Beispiel konzentriert sich auf leistungsstarke Produktivitäts-APIs, die Sie in Ihren eigenen Anwendungen nutzen können, darunter:

Wichtige APIs im Detail

Sehen wir uns zwei der wichtigsten APIs an, die Cahier integriert, um erstklassige Notizen zu ermöglichen.

Natürliche Freihandfunktionen mit der Ink API erstellen

Mit der Stifteingabe werden Geräte mit großem Display zu digitalen Notiz- und Skizzenbüchern. Damit Sie flüssige und natürliche Tinteneingaben erstellen können, haben wir die Ink API zum Herzstück des Beispiels gemacht. Mit der Ink API lassen sich ganz einfach schöne Striche mit geringer Latenz erstellen, rendern und bearbeiten.

Die Ink API bietet eine modulare Architektur, sodass Sie sie an den spezifischen Stack und die Anforderungen Ihrer App anpassen können. Die API-Module umfassen:

  • Authoring-Module (Compose – Ansichten):
      Echtzeit-Eingabe für das Schreiben verarbeiten, um flüssige Linien mit der geringsten Latenz zu erstellen, die ein Gerät bieten kann.
    • In DrawingSurface verwendet Cahier die neu eingeführte zusammensetzbare Funktion InProgressStrokes, um Stift- oder Toucheingaben in Echtzeit zu verarbeiten. Dieses Modul ist für das Erfassen von Zeigerereignissen und das Rendern von Tinte mit der geringstmöglichen Latenz verantwortlich.
  • Modul „Striche“:Stellt die Stifteingabe und ihre visuelle Darstellung dar. Wenn ein Nutzer eine Linie fertig gezeichnet hat, wird über den Callback onStrokesFinished ein endgültiges/trockenes Stroke-Objekt an die App übergeben. Dieses unveränderliche Objekt, das den abgeschlossenen Tuschestrich darstellt, wird dann in DrawingCanvasViewModel verwaltet.
  • Rendering-Modul:Stellt Tintenstriche effizient dar, sodass sie mit Jetpack Compose oder Android-Views kombiniert werden können.
  • Pinselmodule (Compose – Ansichten): Bieten eine deklarative Möglichkeit, den visuellen Stil von Strichen zu definieren. Zu den letzten Updates (seit der Alpha03-Version) gehört ein neuer Pinsel für gestrichelte Linien, der sich besonders für Funktionen wie die Lasso-Auswahl eignet. DrawingCanvasViewModel enthält den Status für den aktuellen Pinsel. In der DrawingCanvas-Toolbox können Nutzer verschiedene Pinseltypen (z. B. StockBrushes.pressurePen() oder StockBrushes.highlighter()) auswählen und Farben ändern. Das ViewModel aktualisiert das Brush-Objekt, das dann von der zusammensetzbaren Funktion InProgressStrokes für neue Striche verwendet wird.
  • Geometriemodule (Compose – Ansichten): Unterstützen die Bearbeitung und Analyse von Strichen für Funktionen wie Löschen und Auswählen.
    • Das Radiergummi-Tool in der Toolbox und die Funktionen in DrawingCanvasViewModel basieren auf dem Geometriemodul. Wenn der Radierer aktiv ist, wird ein MutableParallelogram um den Pfad der Nutzergeste erstellt. Das Radiergummi sucht dann nach Überschneidungen zwischen der Form und den Begrenzungsrahmen vorhandener Striche, um zu bestimmen, welche Striche gelöscht werden sollen. So fühlt sich das Radiergummi intuitiv und präzise an.
  • Speichermodul:Bietet effiziente Serialisierungs- und Deserialisierungsfunktionen für Tinte-Daten, was zu erheblichen Einsparungen bei der Festplatten- und Netzwerkgröße führt. Zum Speichern von Zeichnungen speichert Cahier die Stroke-Objekte in der Room-Datenbank. Im Beispiel wird in Converters die Funktion encode des Speichermoduls verwendet, um den StrokeInputBatch (die Rohpunktdaten) in ein ByteArray zu serialisieren. Das Byte-Array wird zusammen mit den Pinselfunktionen als JSON-String gespeichert. Die Funktion decode wird verwendet, um die Striche zu rekonstruieren, wenn eine Notiz geladen wird.
orion.png

Neben diesen Kernmodulen wurden die Funktionen der Ink API durch aktuelle Updates erweitert:

  • Neue experimentelle APIs für benutzerdefinierte BrushFamily-Objekte ermöglichen es Entwicklern, kreative und einzigartige Pinseltypen zu erstellen, z. B. für die Tools Bleistift und Laserpointer.

Cahier nutzt benutzerdefinierte Pinsel, darunter den einzigartigen Musikpinsel unten, um erweiterte kreative Möglichkeiten zu veranschaulichen.

Regenbogenlaser, der mit den benutzerdefinierten Pinseln der Ink API erstellt wurde.gif

Regenbogenlaser mit benutzerdefinierten Pinseln der Ink API

notes.png

Mit benutzerdefinierten Pinseln der Ink API erstellter Musikpinsel

  • Native Jetpack Compose-Interoperabilitätsmodule optimieren die Integration von Inking-Funktionen direkt in Ihre Compose-UIs und sorgen so für eine idiomatische und effiziente Entwicklung.

Die Ink API bietet mehrere Vorteile, die sie zur idealen Wahl für Produktivitäts- und Kreativitäts-Apps gegenüber einer benutzerdefinierten Implementierung machen:

  • Nutzerfreundlichkeit:Die Ink API abstrahiert die Komplexität von Grafiken und Geometrie, sodass Sie sich auf die Kernfunktionen von Cahier konzentrieren können.
  • Leistung:Die integrierte Unterstützung für niedrige Latenz und das optimierte Rendering sorgen für ein flüssiges und reaktionsschnelles Schreiben.
  • Flexibilität:Das modulare Design ermöglicht es Ihnen, die benötigten Komponenten auszuwählen und so die Ink API nahtlos in die Architektur von Cahier zu integrieren.

Die Ink API wird bereits in vielen Google-Apps verwendet, z. B. für Markierungen in Google Docs und für „Circle to Search“ sowie in Partner-Apps wie Orion Notes und PDF Scanner.

„Die Ink API war unsere erste Wahl für Circle to Search (CtS). Dank der umfangreichen Dokumentation war die Integration der Ink API ein Kinderspiel. Wir konnten innerhalb einer Woche den ersten funktionierenden Prototyp erstellen. Die Unterstützung von benutzerdefinierten Pinselstrukturen und Animationen in Ink hat es uns ermöglicht, das Strichdesign schnell zu optimieren.“ – Jordan Komoda, Software Engineer bei Google

Standard-Notizen-App mit der Rolle „Notizen“ werden

Das Erstellen von Notizen ist eine Kernfunktion, die die Nutzerproduktivität auf Geräten mit großen Bildschirmen steigert. Mit der Funktion für Notizenrollen können Nutzer über den Sperrbildschirm oder während andere Apps ausgeführt werden auf Ihre kompatiblen Apps zugreifen. Mit dieser Funktion werden systemweite Standard-Apps für Notizen identifiziert und festgelegt und ihnen die Berechtigung zum Starten für die Aufnahme von Inhalten erteilt. 

Implementierung in Cahier

Die Implementierung der Notizenrolle umfasst einige wichtige Schritte, die alle im Beispiel gezeigt werden:

  1. Manifestdeklaration: Zuerst muss die App deklarieren, dass sie Notiz-Intents verarbeiten kann. In AndroidManifest.xml enthält Cahier ein <intent-filter> für die Aktion android.intent.action.CREATE_NOTE. Das signalisiert dem System, dass die App ein potenzieller Kandidat für die Notizenrolle ist.
  2. Rollenstatus prüfenSettingsViewModel verwendet den RoleManager von Android, um den aktuellen Status zu ermitteln. SettingsViewModel prüft, ob die Notizenrolle auf dem Gerät verfügbar ist (isRoleAvailable) und ob Cahier diese Rolle derzeit innehat (isRoleHeld). Dieser Status wird über Kotlin-Flows in der Benutzeroberfläche angezeigt.
  3. Rolle anfordern: In der Datei Settings.kt wird dem Nutzer eine Schaltfläche angezeigt, wenn die Rolle verfügbar ist, aber nicht zugewiesen wurde. Wenn darauf geklickt wird, ruft die Schaltfläche die Funktion requestNotesRole im ViewModel auf. Die Funktion erstellt eine Absicht zum Öffnen des Standardbildschirms für App-Einstellungen, auf dem der Nutzer Cahier auswählen kann. Der Prozess wird mit der API rememberLauncherForActivityResult verwaltet, die das Starten des Intents und den Empfang des Ergebnisses übernimmt.
  4. UI aktualisieren: Nachdem der Nutzer vom Einstellungsbildschirm zurückkehrt, löst der ActivityResultLauncher-Callback eine Funktion im ViewModel aus, um den Rollenstatus zu aktualisieren. So wird sichergestellt, dass die UI genau widerspiegelt, ob die App jetzt die Standard-App ist.

Weitere Informationen zum Einbinden der Notizenrolle in Ihre App

helloworld.png

Cahier wird auf einem Lenovo-Tablet in einem unverankerten Fenster als Standard-App für Notizen gestartet

Wichtiger Schritt nach vorn: Lenovo aktiviert die Rolle „Notizen“

Wir freuen uns, einen wichtigen Schritt nach vorn für die Produktivität auf Android-Geräten mit großem Display bekannt zu geben: Lenovo hat die Unterstützung für die Notizenrolle auf Tablets mit Android 15 und höher aktiviert. Mit diesem Update können Sie jetzt Ihre Notizen-Apps aktualisieren, damit Nutzer mit kompatiblen Lenovo-Geräten sie als Standard-App festlegen können. So erhalten sie nahtlosen Zugriff über den Sperrbildschirm und können Funktionen zum Erfassen von Inhalten auf Systemebene nutzen.

Dieses Engagement eines führenden OEM zeigt, wie wichtig Notizen für eine wirklich integrierte und produktive Nutzererfahrung auf Android sind. 

Mehrere Instanzen, Mehrfenstermodus und Desktop-Freiform-Fenster

Bei der Produktivität auf einem großen Bildschirm geht es darum, Informationen und Arbeitsabläufe effizient zu verwalten. Deshalb nutzt Cahier die erweiterten Fensterfunktionen von Android in vollem Umfang und bietet einen flexiblen Arbeitsbereich, der sich an die Bedürfnisse der Nutzer anpasst. Die App unterstützt:

  • Multifenster: Die grundlegende Möglichkeit, eine App im Splitscreen- oder Freiform-Modus neben einer anderen App auszuführen. Das ist für Aufgaben wie das Referenzieren einer Webseite beim Erstellen von Notizen in Cahier unerlässlich.
  • Multi-Instanz: Hier kommt das wahre Multitasking zum Vorschein. Mit Cahier können Nutzer mehrere unabhängige Fenster der App gleichzeitig öffnen. Stellen Sie sich vor, Sie vergleichen zwei verschiedene Notizen nebeneinander oder verweisen in einem Fenster auf eine Textnotiz, während Sie in einem anderen an einer Zeichnung arbeiten. Cahier zeigt, wie diese separaten Instanzen mit jeweils eigenem Status verwaltet werden, wodurch Ihre App zu einem leistungsstarken, vielseitigen Tool wird.
  • Desktop-Freiform-Fenster: Wenn ein Tablet oder Foldable mit einem externen Display verbunden ist, wird es im Android-Desktopmodus in eine Workstation verwandelt. Da Cahier mit einer adaptiven Benutzeroberfläche entwickelt wurde und mehrere Instanzen unterstützt, funktioniert die App in dieser Umgebung hervorragend. Nutzer können mehrere Cahier-Fenster öffnen, ihre Größe anpassen und sie positionieren – genau wie auf einem herkömmlichen Desktop. So sind komplexe Arbeitsabläufe möglich, die auf Mobilgeräten bisher nicht möglich waren.
cahier-desktop-windowing.webp

Cahier im Desktop-Fenstermodus auf dem Pixel Tablet

So haben wir diese Funktionen in Cahier implementiert:

Um die Multi-Instanz-Funktion zu aktivieren, mussten wir dem System zuerst signalisieren, dass die App mehrere Starts unterstützt. Dazu haben wir der Deklaration von MainActivity in AndroidManifest die Property PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI hinzugefügt:

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

Als Nächstes haben wir die Logik zum Starten einer neuen Instanz der App implementiert. Wenn ein Nutzer in CahierHomeScreen.kt eine Notiz in einem neuen Fenster öffnen möchte, erstellen wir einen neuen Intent mit bestimmten Flags, die das System anweisen, wie der neue Aktivitätsstart zu behandeln ist. Durch die Kombination von FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_MULTIPLE_TASK und FLAG_ACTIVITY_LAUNCH_ADJACENT wird die Notiz in einem neuen, separaten Fenster neben dem vorhandenen Fenster geöffnet.

  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)

}

Um den Multi-Window-Modus zu unterstützen, mussten wir dem System signalisieren, dass die App die Größenänderung unterstützt. Dazu haben wir das Element <activity> oder <application> im Manifest festgelegt.

  <activity

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

    android:resizeableActivity="true"

    ...>

</activity>

Die Benutzeroberfläche selbst basiert auf der adaptiven Material 3-Bibliothek und kann daher nahtlos an Multi-Window-Szenarien wie den Splitscreen-Modus von Android angepasst werden. 

Zur Verbesserung der Nutzerfreundlichkeit haben wir die Drag-and-drop-Funktion hinzugefügt. Unten sehen Sie, wie wir das in Cahier umgesetzt haben.

Drag-and-drop

Eine wirklich produktive oder kreative App funktioniert nicht isoliert, sondern interagiert nahtlos mit dem Rest des Ökosystems des Geräts. Drag-and-drop ist ein wichtiger Bestandteil dieser Interaktion, insbesondere auf großen Displays, auf denen Nutzer häufig mit mehreren App-Fenstern arbeiten. Cahier setzt voll und ganz auf diese Idee und bietet eine intuitive Drag-and-drop-Funktion zum Hinzufügen und Teilen von Inhalten.

  • Einfaches Importieren: Nutzer können Bilder aus anderen Anwendungen wie einem Webbrowser, einer Fotogalerie oder einem Dateimanager per Drag-and-drop direkt in eine Notiz einfügen. Dazu verwendet Cahier den Modifier dragAndDropTarget, um eine Drop-Zone zu definieren, nach kompatiblen Inhalten (wie image/*) zu suchen und den eingehenden URI zu verarbeiten.
  • Einfaches Teilen: Inhalte in Cahier lassen sich genauso einfach teilen wie Inhalte aus anderen Apps. Nutzer können in einer Textnotiz lange auf ein Bild oder auf den gesamten Canvas einer Notiz mit Zeichnung und Bildkomposition tippen und es in eine andere Anwendung ziehen.

Technische Details: Ziehen aus dem Zeichenbereich

Die Implementierung der Ziehbewegung auf dem Zeichen-Canvas stellt eine besondere Herausforderung dar. In unserer DrawingSurface sind die Composables, die die Live-Zeichnungseingabe verarbeiten (die InProgressStrokes der Ink API) und die Box, die die Geste zum langen Drücken zum Starten eines Ziehvorgangs erkennt, Geschwister-Composables.

Standardmäßig ist das Jetpack Compose-System für Zeigereingaben so konzipiert, dass nur ein untergeordnetes Composable das Ereignis empfängt – das erste in der Deklarationsreihenfolge, das sich mit der Berührungsposition überschneidet. Im Fall von Cahier soll die Drag-and-drop-Logik für die Eingabebehandlung ausgeführt werden und Eingaben möglicherweise verarbeiten, bevor die zusammensetzbare Funktion InProgressStrokes alle unverarbeiteten Eingaben zum Zeichnen verwendet und diese Eingaben dann verarbeitet. Wenn wir die Dinge nicht in der richtigen Reihenfolge anordnen, erkennt unsere Box die Geste zum langen Drücken nicht, um einen Drag-Vorgang zu starten, oder InProgressStrokes empfängt die Eingabe zum Zeichnen nicht.

Um dieses Problem zu beheben, haben wir einen benutzerdefinierten pointerInputWithSiblingFallthrough-Modifikator erstellt und unser Box mit diesem Modifikator vor InProgressStrokes im zusammensetzbaren Code platziert. Dieses Dienstprogramm ist ein einfacher Wrapper für das Standardsystem pointerInput, aber mit einer wichtigen Änderung: Es überschreibt die Funktion sharePointerInputWithSiblings(), um true zurückzugeben. Dadurch wird dem Compose-Framework mitgeteilt, dass Pointer-Ereignisse an untergeordnete Composables weitergeleitet werden dürfen, auch nachdem sie verarbeitet wurden.

  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

    }

}

So wird sie in DrawingSurface verwendet:

  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(...)

Wenn das der Fall ist, erkennt das System sowohl die Zeichenstriche als auch die Geste „Langes Drücken und Ziehen“ gleichzeitig richtig. Sobald der Drag-Vorgang gestartet wird, erstellen wir mit FileProvider einen freigabefähigen content://-URI und übergeben den URI mit view.startDragAndDrop() an das Drag-and-Drop-Framework des Systems. Diese Lösung sorgt für eine robuste und intuitive Nutzerfreundlichkeit und zeigt, wie komplexe Konflikte bei Gesten in mehrschichtigen Benutzeroberflächen vermieden werden können.

Gebäude mit moderner Architektur

Neben bestimmten APIs demonstriert Cahier wichtige Architekturmuster für die Entwicklung hochwertiger, adaptiver Anwendungen.

Die Darstellungsschicht: Jetpack Compose und Anpassungsfähigkeit

Die Darstellungsschicht wird vollständig mit Jetpack Compose erstellt. Wie bereits erwähnt, verwendet Cahier die material3-adaptive-Bibliothek für die Anpassungsfähigkeit der Benutzeroberfläche. Die Statusverwaltung folgt einem strengen unidirektionalen Datenflussmuster (Unidirectional Data Flow, UDF). ViewModel-Instanzen werden als Datencontainer verwendet, die Notizinformationen und den UI-Status enthalten.

Die Datenschicht: Repositories und Room

Für die Datenschicht verwendet Cahier eine NoteRepository-Schnittstelle, um alle Datenvorgänge zu abstrahieren. Durch diese Designentscheidung kann die App problemlos zwischen einer lokalen Datenquelle (Room) und einem potenziellen zukünftigen Remote-Backend wechseln. Der Datenfluss für eine Aktion wie das Bearbeiten einer Notiz ist einfach:

  1. Die Jetpack Compose-Benutzeroberfläche löst eine Methode im ViewModel aus.
  2. Das ViewModel ruft die Notiz aus NoteRepository ab, verarbeitet die Logik und übergibt die aktualisierte Notiz zurück an das Repository.
  3. NoteRepository speichert die Aktualisierung in einer Room-Datenbank.

Umfassende Unterstützung von Eingaben

Damit eine App wirklich produktiv ist, muss sie eine Vielzahl von Eingabemethoden fehlerfrei verarbeiten. Cahier wurde so entwickelt, dass es den Richtlinien für die Eingabe auf großen Bildschirmen entspricht und Folgendes unterstützt:

  • Eingabestift:Integration mit der Ink API, Handballenabweisung, Registrierung für die Notizenrolle, Eingabestift-Eingabe in Textfeldern und Immersive Mode.
  • Tastatur:Unterstützung der gängigsten Tastenkombinationen (z. B. Strg + Klick, Meta + Klick) und klare Angabe des Tastaturfokus.
  • Maus und Touchpad:Unterstützung für Rechtsklick und Hover-Zustände.

Die Unterstützung für erweiterte Tastatur-, Maus- und Touchpad-Interaktionen ist ein wichtiger Schwerpunkt für weitere Verbesserungen. 

Starten Sie noch heute!

Wir hoffen, dass Cahier als Ausgangspunkt für Ihre nächste großartige App dienen kann. Wir haben die App als umfassende Open-Source-Ressource entwickelt, die zeigt, wie sich eine adaptive Benutzeroberfläche, leistungsstarke APIs wie Ink und die Notizenrolle sowie eine moderne, adaptive Architektur kombinieren lassen.

Bist du bereit, loszulegen?

  • Code ansehen: In unserem GitHub-Repository können Sie sich die Cahier-Codebasis ansehen und die Designprinzipien in Aktion sehen.
  • Eigene App erstellen: Verwenden Sie Cahier als Grundlage für Ihre eigene Notizen-, Dokumentmarkierungs- oder Kreativanwendung.
  • Beiträge leisten: Wir freuen uns über Ihre Beiträge! Helfen Sie uns, Cahier zu einer noch besseren Ressource für die Android-Entwickler-Community zu machen.

Offizielle Entwicklerleitfäden Wir freuen uns schon auf eure Kreationen!

Verfasst von:

Weiterlesen