PDF व्यूअर लागू करना

PdfViewerFragment एक खास Fragment है. इसका इस्तेमाल, अपने Android ऐप्लिकेशन में PDF दस्तावेज़ दिखाने के लिए किया जा सकता है. PdfViewerFragment की मदद से, PDF को रेंडर करना आसान हो जाता है. इससे आपको अपने ऐप्लिकेशन की अन्य सुविधाओं पर ध्यान देने में मदद मिलती है.

नतीजे

PdfViewerFragment का इस्तेमाल करके, Android ऐप्लिकेशन में रेंडर किया गया PDF दस्तावेज़.
किसी ऐप्लिकेशन में दिखाया गया PDF दस्तावेज़.

वर्शन के साथ काम करने की ज़रूरी शर्तें

PdfViewerFragment का इस्तेमाल करने के लिए, आपके ऐप्लिकेशन को कम से कम Android S (एपीआई लेवल 31) और एसडीके एक्सटेंशन लेवल 13 को टारगेट करना होगा. अगर ये ज़रूरी शर्तें पूरी नहीं होती हैं, तो लाइब्रेरी UnsupportedOperationException जनरेट करती है.

SdkExtensions मॉड्यूल का इस्तेमाल करके, रनटाइम के दौरान एसडीके एक्सटेंशन का वर्शन देखा जा सकता है. इससे, डिवाइस के ज़रूरी शर्तें पूरी करने पर ही, फ़्रैगमेंट और PDF दस्तावेज़ को लोड किया जा सकता है.

if (SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S) >= 13) {
    // Load the fragment and document.
}

डिपेंडेंसी

अपने ऐप्लिकेशन में PDF व्यूअर को शामिल करने के लिए, अपने ऐप्लिकेशन के मॉड्यूल build.gradle फ़ाइल में androidx.pdf डिपेंडेंसी का एलान करें. PDF लाइब्रेरी, Google की मेवन रिपॉज़िटरीपर उपलब्ध है.

dependencies {
    val pdfVersion = "1.0.0-alpha0X"
    implementation("androidx.pdf:pdf:pdf-viewer-fragment:$pdfVersion")
}

PdfViewerFragment की सुविधाएं

PdfViewerFragment, PDF दस्तावेज़ों को पेज के हिसाब से फ़ॉर्मैट में दिखाता है. इससे उन्हें नेविगेट करना आसान हो जाता है. तेज़ी से लोड करने के लिए, फ़्रैगमेंट दो‑पास रेंडरिंग की रणनीति का इस्तेमाल करता है. इससे पेज के डाइमेंशन धीरे-धीरे लोड होते हैं.

मेमोरी के इस्तेमाल को ऑप्टिमाइज़ करने के लिए, PdfViewerFragment सिर्फ़ वे पेज रेंडर करता है जो फ़िलहाल दिख रहे हैं. साथ ही, स्क्रीन से बाहर मौजूद पेजों के बिटमैप रिलीज़ कर देता है. इसके अलावा, PdfViewerFragment में फ़्लोट करने वाला कार्रवाई बटन (एफ़एबी) भी शामिल है. यह दस्तावेज़ के यूआरआई वाला, android.intent.action.ANNOTATE इंप्लिसिट इंटेंट भेजकर, एनोटेशन की सुविधा देता है.

लागू करना

अपने Android ऐप्लिकेशन में PDF व्यूअर जोड़ना एक से ज़्यादा चरणों वाली प्रोसेस है.

ऐक्टिविटी का लेआउट बनाना

सबसे पहले, PDF व्यूअर को होस्ट करने वाली ऐक्टिविटी के लिए, लेआउट एक्सएमएल तय करें. लेआउट में, FrameLayout और PdfViewerFragment और उपयोगकर्ता के इंटरैक्शन के लिए बटन शामिल होने चाहिए. जैसे, दस्तावेज़ में खोजना.

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

ऐक्टिविटी सेट अप करना

को होस्ट करने वाली ऐक्टिविटी को AppCompatActivity से एक्सटेंड करना होगा.PdfViewerFragment ऐक्टिविटी के onCreate() तरीके में, कॉन्टेंट व्यू को आपके बनाए गए लेआउट पर सेट करें. साथ ही, ज़रूरी यूज़र इंटरफ़ेस (यूआई) एलिमेंट शुरू करें.

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 को शुरू करना

getSupportFragmentManager() से मिले फ़्रैगमेंट मैनेजर का इस्तेमाल करके, PdfViewerFragment का इंस्टेंस बनाएं. खास तौर पर, कॉन्फ़िगरेशन में बदलाव के दौरान, नया इंस्टेंस बनाने से पहले यह देखें कि फ़्रैगमेंट का कोई इंस्टेंस पहले से मौजूद है या नहीं.

यहां दिए गए उदाहरण में, initializePdfViewerFragment() फ़ंक्शन, फ़्रैगमेंट ट्रांज़ैक्शन को बनाने और कमिट करने की प्रोसेस को मैनेज करता है. यह फ़ंक्शन, किसी कंटेनर में मौजूद फ़्रैगमेंट को आपके 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 की सुविधाओं को बढ़ाना

PdfViewerFragment , सार्वजनिक फ़ंक्शन दिखाता है. इसकी क्षमताओं को बढ़ाने के लिए, इन फ़ंक्शन को बदला जा सकता है. PdfViewerFragment से इनहेरिट होने वाली नई क्लास बनाएं. अपनी सबक्लास में, onLoadDocumentSuccess() और onLoadDocumentError() जैसे तरीकों को बदलकर, ज़रूरत के हिसाब से लॉजिक जोड़ें. जैसे, मेट्रिक लॉग करना.

@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)
          }
}

PdfViewerFragment में, खोज के लिए कोई इन-बिल्ट मेन्यू शामिल नहीं होता. हालांकि, इसमें खोज बार की सुविधा होती है. isTextSearchActive एपीआई का इस्तेमाल करके, खोज बार की विज़िबिलिटी को कंट्रोल किया जा सकता है. दस्तावेज़ में खोजने की सुविधा चालू करने के लिए, अपने PdfViewerFragment इंस्टेंस की isTextSearchActive प्रॉपर्टी सेट करें.

WindowInsetsCompat को कॉन्टेंट व्यू में सही तरीके से पास करने के लिए, WindowCompat.setDecorFitsSystemWindows() का इस्तेमाल करें. खोज व्यू को सही जगह पर दिखाने के लिए, यह ज़रूरी है.

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

फ़ाइल पिकर के साथ इंटिग्रेट करना

उपयोगकर्ताओं को अपने डिवाइस से PDF फ़ाइलें चुनने की अनुमति देने के लिए, PdfViewerFragment को Android फ़ाइल पिकर के साथ इंटिग्रेट करें. सबसे पहले, अपनी ऐक्टिविटी के लेआउट एक्सएमएल को अपडेट करें, ताकि उसमें फ़ाइल पिकर लॉन्च करने वाला बटन शामिल हो.

<androidx.constraintlayout.widget.ConstraintLayout
    ...
    tools:context=".MainActivity">

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

इसके बाद, अपनी ऐक्टिविटी में, फ़ाइल पिकर लॉन्च करने के लिए registerForActivityResult(GetContent()) का इस्तेमाल करें. जब उपयोगकर्ता कोई फ़ाइल चुनता है, तो कॉलबैक एक यूआरआई उपलब्ध कराता है. इसके बाद, चुने गए PDF को लोड करने और दिखाने के लिए, इस यूआरआई के साथ अपने PdfViewerFragment इंस्टेंस की documentUri प्रॉपर्टी सेट करें.

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"
        // ...
    }
}

यूज़र इंटरफ़ेस (यूआई) को पसंद के मुताबिक बनाना

लाइब्रेरी के दिखाए गए एक्सएमएल एट्रिब्यूट को बदलकर, PdfViewerFragment के यूज़र इंटरफ़ेस (यूआई) को पसंद के मुताबिक बनाया जा सकता है. इससे, स्क्रोलबार और पेज इंडिकेटर जैसे एलिमेंट के दिखने के तरीके को अपने ऐप्लिकेशन के डिज़ाइन के हिसाब से बनाया जा सकता है.

पसंद के मुताबिक बनाए जा सकने वाले एट्रिब्यूट में ये शामिल हैं:

  • fastScrollVerticalThumbDrawable — स्क्रोलबार थंब के लिए ड्रॉएबल सेट करता है.
  • fastScrollPageIndicatorBackgroundDrawable — पेज इंडिकेटर के लिए बैकग्राउंड ड्रॉएबल सेट करता है.
  • fastScrollPageIndicatorMarginEnd — पेज इंडिकेटर के लिए दायां मार्जिन सेट करता है. पक्का करें कि मार्जिन की वैल्यू पॉज़िटिव हों.
  • fastScrollVerticalThumbMarginEnd — वर्टिकल स्क्रोलबार थंब के लिए दायां मार्जिन सेट करता है. पक्का करें कि मार्जिन की वैल्यू पॉज़िटिव हों.

इन बदलावों को लागू करने के लिए, अपने एक्सएमएल रिसॉर्स में कोई कस्टम स्टाइल तय करें.

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

इसके बाद, कस्टम स्टाइल रिसॉर्स को PdfViewerFragment का इस्तेमाल करके PdfStylingOptions उपलब्ध कराएं, जब आप फ़्रैगमेंट का इंस्टेंस बनाते हैं, तो PdfViewerFragment.newInstance(stylingOptions) का इस्तेमाल करें.

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

अगर आपने PdfViewerFragment की सबक्लास बनाई है, तो स्टाइलिंग के विकल्प उपलब्ध कराने के लिए, प्रोटेक्टेड कंस्ट्रक्टर का इस्तेमाल करें. इससे यह पक्का होता है कि आपके एक्सटेंड किए गए फ़्रैगमेंट पर, आपकी पसंद के मुताबिक स्टाइल सही तरीके से लागू हों.

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

लागू करने की प्रोसेस पूरी करना

यहां दिए गए कोड में, अपनी ऐक्टिविटी में PdfViewerFragment को लागू करने का पूरा उदाहरण दिया गया है. इसमें, शुरू करने, फ़ाइल पिकर इंटिग्रेशन, खोज की सुविधा, और यूज़र इंटरफ़ेस (यूआई) को पसंद के मुताबिक बनाने की प्रोसेस शामिल है.

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

कोड के बारे में अहम बातें

  • पक्का करें कि आपका प्रोजेक्ट, एपीआई लेवल और एसडीके एक्सटेंशन की ज़रूरी शर्तें पूरी करता हो.
  • PdfViewerFragment को होस्ट करने वाली ऐक्टिविटी को AppCompatActivity से एक्सटेंड करना होगा.
  • ज़रूरत के हिसाब से व्यवहार जोड़ने के लिए, PdfViewerFragment को एक्सटेंड किया जा सकता है.
  • एक्सएमएल एट्रिब्यूट को बदलकर, PdfViewerFragment के यूज़र इंटरफ़ेस (यूआई) को पसंद के मुताबिक बनाया जा सकता है.