Einige Anwendungen wie Apps zum Zeichnen, Seitenlayout-Apps und andere Apps, die sich auf grafische Ausgabe. Das Erstellen ansprechender gedruckter Seiten ist eine wichtige Funktion. In diesem Fall reicht es nicht aus, um ein Bild oder HTML-Dokument zu drucken. Die Druckausgabe für diese Arten von Anwendungen muss Kontrolle über alles, was auf einer Seite erscheint, einschließlich Schriftarten, Textfluss, Seitenumbrüchen Kopf-, Fußzeilen und Grafikelementen.
Das Erstellen von Druckausgaben, die vollständig an Ihre Anwendung angepasst sind, erfordert mehr als die zuvor erläuterten Ansätze. Sie müssen Komponenten erstellen, Kommunikation mit dem Print-Framework, Anpassen der Druckereinstellungen, Zeichnen von Seitenelementen mehrere Seiten zu drucken.
In dieser Lektion erfahren Sie, wie Sie eine Verbindung zum Druckmanager herstellen, einen Druckadapter erstellen und Druckinhalte erstellen können.
Mit dem Druckmanager verbinden
Wenn Ihre Anwendung den Druckvorgang direkt verwaltet, ist der erste Schritt nach Erhalt eines
Druckanfrage von Ihrem Nutzer besteht darin, eine Verbindung zum Android Print Framework herzustellen und eine Instanz
der Klasse PrintManager
. Mit dieser Klasse können Sie einen Druckauftrag initialisieren
und beginnen den Druckvorgang. Das folgende Codebeispiel zeigt, wie Sie den Druckmanager abrufen.
und starten Sie den Druckvorgang.
Kotlin
private fun doPrint() { activity?.also { context -> // Get a PrintManager instance val printManager = context.getSystemService(Context.PRINT_SERVICE) as PrintManager // Set job name, which will be displayed in the print queue val jobName = "${context.getString(R.string.app_name)} Document" // Start a print job, passing in a PrintDocumentAdapter implementation // to handle the generation of a print document printManager.print(jobName, MyPrintDocumentAdapter(context), null) } }
Java
private void doPrint() { // Get a PrintManager instance PrintManager printManager = (PrintManager) getActivity() .getSystemService(Context.PRINT_SERVICE); // Set job name, which will be displayed in the print queue String jobName = getActivity().getString(R.string.app_name) + " Document"; // Start a print job, passing in a PrintDocumentAdapter implementation // to handle the generation of a print document printManager.print(jobName, new MyPrintDocumentAdapter(getActivity()), null); // }
Der Beispielcode oben zeigt, wie ein Druckauftrag benannt und eine Instanz der PrintDocumentAdapter
-Klasse festgelegt wird, die die Schritte des Drucklebenszyklus verarbeitet. Die
Implementierung der Klasse der Druckadapter wird im nächsten Abschnitt erläutert.
Hinweis: Der letzte Parameter im Feld print()
verwendet ein PrintAttributes
-Objekt. Mit diesem Parameter können Sie
bieten Hinweise auf das Druckframework und voreingestellte Optionen basierend auf dem vorherigen Druckzyklus,
und so die User Experience verbessert. Sie können mit diesem Parameter auch Optionen festlegen,
besser zum Druckinhalt passen, indem Sie z. B. die Ausrichtung auf Querformat festlegen
wenn Sie ein Foto in dieser Ausrichtung drucken.
Druckadapter erstellen
Ein Druckadapter interagiert mit dem Android Print-Framework und verarbeitet die Schritte der Druckverfahren. Bei diesem Vorgang müssen Nutzer vor dem Erstellen Drucker und Druckoptionen auswählen ein Dokument zum Drucken. Diese Auswahl kann sich auf die endgültige Ausgabe auswirken, wenn die Nutzenden sie auswählen. Drucker mit unterschiedlichen Ausgabefunktionen, unterschiedlichen Seitengrößen oder Seitenausrichtungen. Während dieser Auswahl fordert das Print-Framework Ihren Adapter auf, ein Layout zu erstellen und ein Druckdokument zur Vorbereitung auf die endgültige Ausgabe. Sobald Nutzende auf die Schaltfläche „Drucken“ tippen, nimmt das fertige Druckdokument und übergibt es zur Ausgabe an einen Anbieter für Druck. Während des Druckens kann der Nutzer die Druckaktion abbrechen. Daher muss Ihr Druckadapter auch und auf Kündigungsanfragen reagieren.
Die abstrakte Klasse PrintDocumentAdapter
dient der Verarbeitung von
mit vier Callback-Methoden. Sie müssen diese Methoden implementieren
in Ihrem Druckeradapter verwenden, damit Sie ordnungsgemäß mit dem Print-Framework interagieren können:
onStart()
: 1 Aufruf am des Druckvorgangs beginnen. Wenn Ihre Anwendung einmalige Vorbereitungsaufgaben umfasst, ausgeführt werden sollen, z. B. um einen Snapshot der zu druckenden Daten zu erhalten, führen Sie sie hier aus. Implementieren Diese Methode in Ihrem Adapter ist nicht erforderlich.onLayout()
– Wird jedes Mal aufgerufen, wenn ein der Nutzer eine Druckeinstellung ändert, die sich auf die Ausgabe auswirkt, z. B. eine andere Seitengröße, oder Seitenausrichtung. So kann Ihre Anwendung das Layout der Seite zu druckenden Seiten. Diese Methode muss mindestens zurückgeben, wie viele Seiten erwartet werden im gedruckten Dokument.onWrite()
– Zum Rendern gedruckt aufgerufen Seiten in eine zu druckende Datei. Diese Methode kann nach jeder Methode einmal oder mehrmals aufgerufen werden.onLayout()
Anruf.onFinish()
– Wird am Ende einmal aufgerufen des Druckvorgangs. Wenn für Ihre Anwendung einmalige Löschaufgaben ausgeführt werden müssen, führen Sie sie hier aus. Die Implementierung dieser Methode in Ihrem Adapter ist nicht erforderlich.
In den folgenden Abschnitten wird beschrieben, wie die Layout- und Schreibmethoden implementiert werden. entscheidend für die Funktion eines Printadapters ist.
Hinweis:Diese Adaptermethoden werden im Hauptthread Ihrer Anwendung aufgerufen. Wenn
erwarten Sie, dass die Ausführung dieser Methoden in Ihrer Implementierung erheblich
implementieren Sie sie so, dass sie
in einem separaten Thread ausgeführt werden. Sie können beispielsweise die
das Schreiben von Dokumenten in separaten AsyncTask
-Objekten.
Informationen zu Druckdokumenten berechnen
Innerhalb einer Implementierung der PrintDocumentAdapter
-Klasse enthält Ihr
Anwendung muss den erstellten Dokumenttyp angeben und die Gesamtsumme berechnen können.
Anzahl der Seiten für den Druckauftrag unter Angabe der Größe der gedruckten Seite.
Die Implementierung der Methode onLayout()
in
führt der Adapter diese Berechnungen durch und liefert Informationen zur erwarteten Ausgabe des
die Anzahl der Druckaufträge in einem PrintDocumentInfo
-Kurs, einschließlich der Anzahl der Seiten und
Inhaltstyp auswählen. Das folgende Codebeispiel zeigt eine einfache Implementierung der onLayout()
-Methode für ein PrintDocumentAdapter
-Element:
Kotlin
override fun onLayout( oldAttributes: PrintAttributes?, newAttributes: PrintAttributes, cancellationSignal: CancellationSignal?, callback: LayoutResultCallback, extras: Bundle? ) { // Create a new PdfDocument with the requested page attributes pdfDocument = PrintedPdfDocument(activity, newAttributes) // Respond to cancellation request if (cancellationSignal?.isCanceled == true) { callback.onLayoutCancelled() return } // Compute the expected number of printed pages val pages = computePageCount(newAttributes) if (pages > 0) { // Return print information to print framework PrintDocumentInfo.Builder("print_output.pdf") .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) .setPageCount(pages) .build() .also { info -> // Content layout reflow is complete callback.onLayoutFinished(info, true) } } else { // Otherwise report an error to the print framework callback.onLayoutFailed("Page count calculation failed.") } }
Java
@Override public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle metadata) { // Create a new PdfDocument with the requested page attributes pdfDocument = new PrintedPdfDocument(getActivity(), newAttributes); // Respond to cancellation request if (cancellationSignal.isCanceled() ) { callback.onLayoutCancelled(); return; } // Compute the expected number of printed pages int pages = computePageCount(newAttributes); if (pages > 0) { // Return print information to print framework PrintDocumentInfo info = new PrintDocumentInfo .Builder("print_output.pdf") .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) .setPageCount(pages) .build(); // Content layout reflow is complete callback.onLayoutFinished(info, true); } else { // Otherwise report an error to the print framework callback.onLayoutFailed("Page count calculation failed."); } }
Die Ausführung der Methode onLayout()
kann
drei Ergebnisse haben: Abschluss, Stornierung oder Misserfolg, falls die Berechnung des
Layout nicht fertiggestellt werden kann. Sie müssen eines dieser Ergebnisse angeben, indem Sie das entsprechende
des PrintDocumentAdapter.LayoutResultCallback
-Objekts.
Hinweis:Der boolesche Parameter der
Die Methode onLayoutFinished()
gibt an, ob sich der Layoutinhalt tatsächlich geändert hat.
seit der letzten Anfrage. Wenn Sie diesen Parameter korrekt festlegen, kann das Print-Framework
die Methode onWrite()
unnötigerweise aufrufen,
Das zuvor geschriebene Druckdokument wird im Prinzip im Cache gespeichert,
um die Leistung zu verbessern.
Die Hauptaufgabe von onLayout()
ist
Berechnung der Anzahl der Seiten, die aufgrund der Druckerattribute als Ausgabe erwartet werden.
Wie Sie diese Zahl berechnen, hängt stark davon ab, wie die Seiten Ihrer App
Drucken. Das folgende Codebeispiel zeigt eine Implementierung, bei der die Anzahl der Seiten
Druckausrichtung festgelegt:
Kotlin
private fun computePageCount(printAttributes: PrintAttributes): Int { var itemsPerPage = 4 // default item count for portrait mode val pageSize = printAttributes.mediaSize if (!pageSize.isPortrait) { // Six items per page in landscape orientation itemsPerPage = 6 } // Determine number of print items val printItemCount: Int = getPrintItemCount() return Math.ceil((printItemCount / itemsPerPage.toDouble())).toInt() }
Java
private int computePageCount(PrintAttributes printAttributes) { int itemsPerPage = 4; // default item count for portrait mode MediaSize pageSize = printAttributes.getMediaSize(); if (!pageSize.isPortrait()) { // Six items per page in landscape orientation itemsPerPage = 6; } // Determine number of print items int printItemCount = getPrintItemCount(); return (int) Math.ceil(printItemCount / itemsPerPage); }
Druckdokumentdatei schreiben
Wenn es an der Zeit ist, die Druckausgabe in eine Datei zu schreiben, ruft das Android Print Framework die Methode onWrite()
der PrintDocumentAdapter
-Klasse Ihrer App auf. Die Parameter der Methode legen fest, welche Seiten
und die zu verwendende Ausgabedatei. Ihre Implementierung dieser Methode muss dann jedes
die angeforderte Inhaltsseite in eine mehrseitige PDF-Dokumentdatei umwandeln. Nach Abschluss dieses Vorgangs
onWriteFinished()
-Methode des Callback-Objekts aufrufen
Hinweis: Das Android Print-Framework kann die onWrite()
-Methode einmal oder mehrmals für jeden
onLayout()
. Aus diesem Grund
ist es wichtig, den booleschen Parameter
onLayoutFinished()
auf false
, wenn das Layout der Druckinhalte nicht geändert wurde
um unnötiges Umschreiben des Druckdokuments zu vermeiden.
Hinweis:Der boolesche Parameter der
Die Methode onLayoutFinished()
gibt an, ob sich der Layoutinhalt tatsächlich geändert hat.
seit der letzten Anfrage. Wenn Sie diesen Parameter korrekt festlegen, kann das Print-Framework
die Methode onLayout()
unnötigerweise aufrufen,
Das zuvor geschriebene Druckdokument wird im Prinzip im Cache gespeichert,
um die Leistung zu verbessern.
Im folgenden Beispiel werden die grundlegenden Mechanismen dieses Prozesses anhand der Klasse PrintedPdfDocument
zum Erstellen einer PDF-Datei veranschaulicht:
Kotlin
override fun onWrite( pageRanges: Array<out PageRange>, destination: ParcelFileDescriptor, cancellationSignal: CancellationSignal?, callback: WriteResultCallback ) { // Iterate over each page of the document, // check if it's in the output range. for (i in 0 until totalPages) { // Check to see if this page is in the output range. if (containsPage(pageRanges, i)) { // If so, add it to writtenPagesArray. writtenPagesArray.size() // is used to compute the next output page index. writtenPagesArray.append(writtenPagesArray.size(), i) pdfDocument?.startPage(i)?.also { page -> // check for cancellation if (cancellationSignal?.isCanceled == true) { callback.onWriteCancelled() pdfDocument?.close() pdfDocument = null return } // Draw page content for printing drawPage(page) // Rendering is complete, so page can be finalized. pdfDocument?.finishPage(page) } } } // Write PDF document to file try { pdfDocument?.writeTo(FileOutputStream(destination.fileDescriptor)) } catch (e: IOException) { callback.onWriteFailed(e.toString()) return } finally { pdfDocument?.close() pdfDocument = null } val writtenPages = computeWrittenPages() // Signal the print framework the document is complete callback.onWriteFinished(writtenPages) ... }
Java
@Override public void onWrite(final PageRange[] pageRanges, final ParcelFileDescriptor destination, final CancellationSignal cancellationSignal, final WriteResultCallback callback) { // Iterate over each page of the document, // check if it's in the output range. for (int i = 0; i < totalPages; i++) { // Check to see if this page is in the output range. if (containsPage(pageRanges, i)) { // If so, add it to writtenPagesArray. writtenPagesArray.size() // is used to compute the next output page index. writtenPagesArray.append(writtenPagesArray.size(), i); PdfDocument.Page page = pdfDocument.startPage(i); // check for cancellation if (cancellationSignal.isCanceled()) { callback.onWriteCancelled(); pdfDocument.close(); pdfDocument = null; return; } // Draw page content for printing drawPage(page); // Rendering is complete, so page can be finalized. pdfDocument.finishPage(page); } } // Write PDF document to file try { pdfDocument.writeTo(new FileOutputStream( destination.getFileDescriptor())); } catch (IOException e) { callback.onWriteFailed(e.toString()); return; } finally { pdfDocument.close(); pdfDocument = null; } PageRange[] writtenPages = computeWrittenPages(); // Signal the print framework the document is complete callback.onWriteFinished(writtenPages); ... }
In diesem Beispiel wird das Rendern von PDF-Seiteninhalten an drawPage()
delegiert.
, die im nächsten Abschnitt erläutert wird.
Wie beim Layout wird die Ausführung von onWrite()
kann drei Ergebnisse haben: Abschluss, Abbruch oder Fehler, falls der
kann der Inhalt nicht geschrieben werden. Sie müssen eines dieser Ergebnisse angeben, indem Sie die Methode
Methode des PrintDocumentAdapter.WriteResultCallback
-Objekts.
Hinweis:Das Rendern eines Dokuments zum Drucken kann ein ressourcenintensiver Vorgang sein. In
Damit der Hauptthread der Benutzeroberfläche Ihrer Anwendung nicht blockiert wird, sollten Sie
das Rendern der Seite und die Schreibvorgänge in einem separaten Thread ausführen, z. B.
in einem AsyncTask
.
Weitere Informationen zur Arbeit mit Ausführungs-Threads wie asynchronen Aufgaben
Siehe Prozesse
und Threads.
Zeichnung (PDF) Seiteninhalt
Wenn Ihre Anwendung gedruckt wird, muss sie ein PDF-Dokument generieren und an
das Druck-Framework von Android. Sie können dafür eine beliebige Bibliothek zur PDF-Erstellung verwenden
zu verstehen. In dieser Lektion erfahren Sie, wie Sie den PrintedPdfDocument
-Kurs verwenden.
um aus Ihren Inhalten PDF-Seiten zu generieren.
Für die Klasse PrintedPdfDocument
wird ein Canvas
verwendet.
-Objekt, um Elemente auf einer PDF-Seite zu zeichnen, ähnlich wie beim Zeichnen in einem Aktivitätslayout. Sie können zeichnen,
Elemente auf der gedruckten Seite mithilfe der Canvas
-Zeichnungsmethoden. Die folgenden
Beispielcode zeigt, wie Sie mit diesen Funktionen einfache Elemente auf einer PDF-Dokumentseite zeichnen.
Methoden:
Kotlin
private fun drawPage(page: PdfDocument.Page) { page.canvas.apply { // units are in points (1/72 of an inch) val titleBaseLine = 72f val leftMargin = 54f val paint = Paint() paint.color = Color.BLACK paint.textSize = 36f drawText("Test Title", leftMargin, titleBaseLine, paint) paint.textSize = 11f drawText("Test paragraph", leftMargin, titleBaseLine + 25, paint) paint.color = Color.BLUE drawRect(100f, 100f, 172f, 172f, paint) } }
Java
private void drawPage(PdfDocument.Page page) { Canvas canvas = page.getCanvas(); // units are in points (1/72 of an inch) int titleBaseLine = 72; int leftMargin = 54; Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setTextSize(36); canvas.drawText("Test Title", leftMargin, titleBaseLine, paint); paint.setTextSize(11); canvas.drawText("Test paragraph", leftMargin, titleBaseLine + 25, paint); paint.setColor(Color.BLUE); canvas.drawRect(100, 100, 172, 172, paint); }
Wenn Sie mit Canvas
auf einer PDF-Seite zeichnen, werden Elemente in
was 1/72 Zoll entspricht. Achten Sie darauf, diese Maßeinheit für die Angabe der Größe zu verwenden.
von Elementen auf der Seite. Für die Positionierung gezeichneter Elemente beginnt das Koordinatensystem bei 0,0.
für die obere linke Ecke der Seite.
Tipp:Mit dem Canvas
-Objekt können Sie zwar drucken,
Elemente am Rand eines PDF-Dokuments können viele Drucker nicht
normales Blatt Papier. Achten Sie darauf, dass Sie die nicht druckbaren Ränder der Seite berücksichtigen, wenn Sie
erstellen Sie in diesem Kurs ein Druckdokument.