PdfViewerFragment ist ein spezielles Fragment, mit dem Sie PDF-Dokumente in Ihrer Android-Anwendung anzeigen können.
PdfViewerFragment vereinfacht das Rendern von PDFs, sodass Sie sich auf andere Aspekte der Funktionen Ihrer App konzentrieren können.
Ergebnisse
Versionskompatibilität
Damit Sie PdfViewerFragment verwenden können, muss Ihre Anwendung mindestens auf Android S (API-Level 31) und SDK-Erweiterungslevel 13 ausgerichtet sein. Wenn diese Kompatibilitätsanforderungen nicht erfüllt sind, löst die Bibliothek eine UnsupportedOperationException aus.
Sie können die SDK-Erweiterungsversion zur Laufzeit mit dem Modul SdkExtensions prüfen. So können Sie das Fragment und das PDF-Dokument nur dann bedingt laden, wenn das Gerät die erforderlichen Anforderungen erfüllt.
if (SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S) >= 13) {
// Load the fragment and document.
}
Abhängigkeiten
Wenn Sie den PDF-Viewer in Ihre Anwendung einbinden möchten, deklarieren Sie die Abhängigkeit androidx.pdf in der Datei build.gradle des Moduls Ihrer App. Die PDF-Bibliothek ist über das Google Maven-Repository verfügbar.
dependencies {
val pdfVersion = "1.0.0-alpha0X"
implementation("androidx.pdf:pdf:pdf-viewer-fragment:$pdfVersion")
}
PdfViewerFragment Funktionen
PdfViewerFragment präsentiert PDF-Dokumente in einem paginierten Format, das die Navigation erleichtert. Für ein effizientes Laden wird im Fragment eine Rendering-Strategie mit zwei Durchgängen verwendet, bei der die Seitendimensionen nach und nach geladen werden.
Zur Optimierung der Speicherauslastung rendert PdfViewerFragment nur die aktuell sichtbaren Seiten und gibt die Bitmaps für Seiten frei, die nicht auf dem Bildschirm angezeigt werden.
Außerdem enthält PdfViewerFragment eine unverankerte Aktionsschaltfläche (UAS), die Anmerkungen unterstützt, indem sie einen impliziten android.intent.action.ANNOTATE-Intent mit dem Dokument-URI auslöst.
Implementierung
Das Hinzufügen eines PDF-Viewers zu Ihrer Android-Anwendung erfolgt in mehreren Schritten.
Aktivitätslayout erstellen
Definieren Sie zuerst das Layout-XML für die Aktivität, in der der PDF-Viewer gehostet wird. Das Layout sollte ein FrameLayout enthalten, in dem das PdfViewerFragment und Schaltflächen für Nutzerinteraktionen wie die Suche im Dokument untergebracht sind.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/pdf_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/fragment_container_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/search_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/search_string"
app:strokeWidth="1dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Aktivität einrichten
Die Aktivität, die PdfViewerFragment hostet, muss AppCompatActivity erweitern. Legen Sie in der onCreate()-Methode der Aktivität die Inhaltsansicht auf das von Ihnen erstellte Layout fest und initialisieren Sie alle erforderlichen UI-Elemente.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val getContentButton: MaterialButton = findViewById(R.id.launch_button)
val searchButton: MaterialButton = findViewById(R.id.search_button)
}
}
PdfViewerFragment initialisieren
Erstellen Sie eine Instanz von PdfViewerFragment mit einem Fragmentmanager, der von getSupportFragmentManager() abgerufen wurde. Prüfen Sie, ob bereits eine Instanz des Fragments vorhanden ist, bevor Sie eine neue erstellen, insbesondere bei Konfigurationsänderungen.
Im folgenden Beispiel übernimmt die Funktion initializePdfViewerFragment() das Erstellen und Committen der Fragmenttransaktion. Die Funktion ersetzt ein vorhandenes Fragment in einem Container durch eine Instanz von PdfViewerFragment.
class MainActivity : AppCompatActivity() {
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 13)
private var pdfViewerFragment: PdfViewerFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
// ...
if (pdfViewerFragment == null) {
pdfViewerFragment =
supportFragmentManager
.findFragmentByTag(PDF_VIEWER_FRAGMENT_TAG) as PdfViewerFragment?
}
}
// Used to instantiate and commit the fragment.
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 13)
private fun initializePdfViewerFragment() {
// This condition can be skipped if you want to create a new fragment every time.
if (pdfViewerFragment == null) {
val fragmentManager: FragmentManager = supportFragmentManager
// Fragment initialization.
pdfViewerFragment = PdfViewerFragmentExtended()
val transaction: FragmentTransaction = fragmentManager.beginTransaction()
// Replace an existing fragment in a container with an instance of a new fragment.
transaction.replace(
R.id.fragment,4_container_view,
pdfViewerFragment!!,
PDF_VIEWER_FRAGMENT_TAG
)
transaction.commitAllowingStateLoss()
fragmentManager.executePendingTransactions()
}
}
companion object {
private const val MIME_TYPE_PDF = "application/pdf"
private const val PDF_VIEWER_FRAGMENT_TAG = "pdf_viewer_fragment_tag"
}
}
PdfViewerFragment-Funktionen erweitern
PdfViewerFragment stellt öffentliche Funktionen bereit, die Sie überschreiben können, um die Funktionen zu erweitern. Erstellen Sie eine neue Klasse, die von PdfViewerFragment erbt. Überschreiben Sie in Ihrer Unterklasse Methoden wie onLoadDocumentSuccess() und onLoadDocumentError(), um benutzerdefinierte Logik wie das Protokollieren von Messwerten hinzuzufügen.
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 13)
class PdfViewerFragmentExtended : PdfViewerFragment() {
private val someLogger : SomeLogger = // ... used to log metrics
override fun onLoadDocumentSuccess() {
someLogger.log(/** log document success */)
}
override fun onLoadDocumentError(error: Throwable) {
someLogger.log(/** log document error */, error)
}
}
Dokumentsuche aktivieren
PdfViewerFragment bietet zwar kein integriertes Suchmenü, aber eine Suchleiste. Sie steuern die Sichtbarkeit der Suchleiste mit der isTextSearchActive API. Um die Dokumentsuche zu aktivieren, legen Sie die isTextSearchActive-Eigenschaft Ihrer PdfViewerFragment-Instanz fest.
Verwenden Sie WindowCompat.setDecorFitsSystemWindows(), damit WindowInsetsCompat korrekt an Inhaltsansichten übergeben wird. Das ist für die richtige Positionierung der Suchansicht erforderlich.
class MainActivity : AppCompatActivity() {
@RequiresExtension(extension = Build.VERSION_CODES.S, version = 13)
override fun onCreate(savedInstanceState: Bundle?) {
// ...
searchButton.setOnClickListener {
pdfViewerFragment?.isTextSearchActive =
pdfViewerFragment?.isTextSearchActive == false
}
// Ensure WindowInsetsCompat are passed to content views without being
// consumed by the decor view. These insets are used to calculate the
// position of the search view.
WindowCompat.setDecorFitsSystemWindows(window, false)
}
}
Integration in die Dateiauswahl
Wenn Sie Nutzern die Auswahl von PDF-Dateien auf ihrem Gerät ermöglichen möchten, integrieren Sie PdfViewerFragment in die Android-Dateiauswahl. Aktualisieren Sie zuerst das XML-Layout Ihrer Aktivität, damit es eine Schaltfläche enthält, mit der die Dateiauswahl gestartet wird.
<...>
<FrameLayout
...
app:layout_constraintBottom_toTopOf="@+id/launch_button"/>
// Adding a button to open file picker.
<com.google.android.material.button.MaterialButton
android:id="@+id/launch_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/launch_string"
app:strokeWidth="1dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/search_button"/>
<com.google.android.material.button.MaterialButton
...
app:layout_constraintStart_toEndOf="@id/launch_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
Starten Sie als Nächstes in Ihrer Aktivität die Dateiauswahl mit registerForActivityResult(GetContent()). Wenn der Nutzer eine Datei auswählt, wird im Callback ein URI bereitgestellt. Anschließend legen Sie die documentUri-Eigenschaft Ihrer PdfViewerFragment-Instanz mit diesem URI fest, um das ausgewählte PDF zu laden und anzuzeigen.
class MainActivity : AppCompatActivity() {
// ...
private var filePicker: ActivityResultLauncher<String> =
registerForActivityResult(GetContent()) { uri: Uri? ->
uri?.let {
initializePdfViewerFragment()
pdfViewerFragment?.documentUri = uri
}
}
override fun onCreate(savedInstanceState: Bundle?) {
// ...
getContentButton.setOnClickListener { filePicker.launch(MIME_TYPE_PDF) }
}
private fun initializePdfViewerFragment() {
// ...
}
companion object {
private const val MIME_TYPE_PDF = "application/pdf"
// ...
}
}
Benutzeroberfläche anpassen
Sie können die Benutzeroberfläche von PdfViewerFragment anpassen, indem Sie XML-Attribute überschreiben, die von der Bibliothek bereitgestellt werden. So können Sie das Erscheinungsbild von Elementen wie der Scrollleiste und der Seitenanzeige an das Design Ihrer App anpassen.
Die anpassbaren Attribute umfassen:
fastScrollVerticalThumbDrawable: Legt die Drawables für den Scrollleisten-Thumb fest.fastScrollPageIndicatorBackgroundDrawable: Legt den Hintergrund-Drawable für die Seitenanzeige fest.fastScrollPageIndicatorMarginEnd: Legt den rechten Rand für die Seitenanzeige fest. Die Grenzwerte müssen positiv sein.fastScrollVerticalThumbMarginEnd: Legt den rechten Rand für den Ziehpunkt der vertikalen Scrollleiste fest. Die Grenzwerte müssen positiv sein.
Um diese Anpassungen anzuwenden, definieren Sie ein benutzerdefiniertes Design in Ihren XML-Ressourcen.
<resources>
<style name="pdfContainerStyle">
<item name="fastScrollVerticalThumbDrawable">@drawable/custom_thumb_drawable</item>
<item name="fastScrollPageIndicatorBackgroundDrawable">@drawable/custom_page_indicator_background</item>
<item name="fastScrollVerticalThumbMarginEnd">8dp</item>
</style>
</resources>
Stellen Sie dann die benutzerdefinierte Stilressource für PdfViewerFragment mit PdfStylingOptions bereit, wenn Sie eine Instanz des Fragments mit PdfViewerFragment.newInstance(stylingOptions) erstellen.
private fun initializePdfViewerFragment() {
// This condition can be skipped if you want to create a new fragment every time.
if (pdfViewerFragment == null) {
val fragmentManager: FragmentManager = supportFragmentManager
// Create styling options.
val stylingOptions = PdfStylingOptions(R.style.pdfContainerStyle)
// Fragment initialization.
pdfViewerFragment = PdfViewerFragment.newInstance(stylingOptions)
// Execute fragment transaction.
}
}
Wenn Sie eine Unterklasse von PdfViewerFragment erstellt haben, verwenden Sie den geschützten Konstruktor, um die Formatierungsoptionen anzugeben. So wird sichergestellt, dass Ihre benutzerdefinierten Stile korrekt auf das erweiterte Fragment angewendet werden.
class StyledPdfViewerFragment: PdfViewerFragment {
constructor() : super()
private constructor(pdfStylingOptions: PdfStylingOptions) : super(pdfStylingOptions)
companion object {
fun newInstance(): StyledPdfViewerFragment {
val stylingOptions = PdfStylingOptions(R.style.pdfContainerStyle)
return StyledPdfViewerFragment(stylingOptions)
}
}
}
Vollständige Implementierung
Der folgende Code enthält ein vollständiges Beispiel für die Implementierung von PdfViewerFragment in Ihrer Aktivität, einschließlich Initialisierung, Einbindung der Dateiauswahl, Suchfunktion und Anpassung der Benutzeroberfläche.
class MainActivity : AppCompatActivity() {
private var pdfViewerFragment: PdfViewerFragment? = null
private var filePicker: ActivityResultLauncher<String> =
registerForActivityResult(GetContent()) { uri: Uri? ->
uri?.let {
initializePdfViewerFragment()
pdfViewerFragment?.documentUri = uri
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (pdfViewerFragment == null) {
pdfViewerFragment =
supportFragmentManager
.findFragmentByTag(PDF_VIEWER_FRAGMENT_TAG) as PdfViewerFragment?
}
val getContentButton: MaterialButton = findViewById(R.id.launch_button)
val searchButton: MaterialButton = findViewById(R.id.search_button)
getContentButton.setOnClickListener { filePicker.launch(MIME_TYPE_PDF) }
searchButton.setOnClickListener {
pdfViewerFragment?.isTextSearchActive = pdfViewerFragment?.isTextSearchActive == false
}
}
private fun initializePdfViewerFragment() {
// This condition can be skipped if you want to create a new fragment every time.
if (pdfViewerFragment == null) {
val fragmentManager: FragmentManager = supportFragmentManager
// Create styling options.
// val stylingOptions = PdfStylingOptions(R.style.pdfContainerStyle)
// Fragment initialization.
// For customization:
// pdfViewerFragment = PdfViewerFragment.newInstance(stylingOptions)
pdfViewerFragment = PdfViewerFragmentExtended()
val transaction: FragmentTransaction = fragmentManager.beginTransaction()
// Replace an existing fragment in a container with an instance of a new fragment.
transaction.replace(
R.id.fragment_container_view,
pdfViewerFragment!!,
PDF_VIEWER_FRAGMENT_TAG
)
transaction.commitAllowingStateLoss()
fragmentManager.executePendingTransactions()
}
}
companion object {
private const val MIME_TYPE_PDF = "application/pdf"
private const val PDF_VIEWER_FRAGMENT_TAG = "pdf_viewer_fragment_tag"
}
}
Wichtige Punkte zum Code
- Prüfen Sie, ob Ihr Projekt die Mindestanforderungen an das API-Level und die SDK-Erweiterung erfüllt.
- Die Aktivität, die
PdfViewerFragmenthostet, mussAppCompatActivityerweitern. - Sie können
PdfViewerFragmenterweitern, um benutzerdefinierte Verhaltensweisen hinzuzufügen. - Sie können die Benutzeroberfläche von
PdfViewerFragmentanpassen, indem Sie XML-Attribute überschreiben.