একটি PDF ভিউয়ার বাস্তবায়ন করুন, একটি PDF ভিউয়ার বাস্তবায়ন করুন

PdfViewerFragment হলো একটি বিশেষায়িত Fragment যা আপনি আপনার অ্যান্ড্রয়েড অ্যাপ্লিকেশনে পিডিএফ ডকুমেন্ট প্রদর্শন করতে ব্যবহার করতে পারেন। PdfViewerFragment পিডিএফ রেন্ডারিং সহজ করে, ফলে আপনি আপনার অ্যাপের কার্যকারিতার অন্যান্য দিকগুলিতে মনোযোগ দিতে পারেন।

ফলাফল

PdfViewerFragment ব্যবহার করে একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশনের মধ্যে রেন্ডার করা একটি পিডিএফ ডকুমেন্ট।
একটি অ্যাপে পিডিএফ ডকুমেন্ট প্রদর্শিত হচ্ছে।

সংস্করণ সামঞ্জস্যতা

PdfViewerFragment ব্যবহার করার জন্য, আপনার অ্যাপ্লিকেশনটিকে অবশ্যই ন্যূনতম Android S (API লেভেল 31) এবং SDK এক্সটেনশন লেভেল 13 টার্গেট করতে হবে। যদি এই সামঞ্জস্যের শর্তগুলো পূরণ না হয়, তাহলে লাইব্রেরিটি একটি UnsupportedOperationException থ্রো করে।

আপনি SdkExtensions মডিউল ব্যবহার করে রানটাইমে SDK এক্সটেনশনের সংস্করণ যাচাই করতে পারেন। এর ফলে, ডিভাইসটি প্রয়োজনীয় শর্ত পূরণ করলেই আপনি শর্তসাপেক্ষে ফ্র্যাগমেন্ট এবং পিডিএফ ডকুমেন্ট লোড করতে পারবেন।

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

নির্ভরশীলতা

আপনার অ্যাপ্লিকেশনে পিডিএফ ভিউয়ার অন্তর্ভুক্ত করতে, আপনার অ্যাপের মডিউল build.gradle ফাইলে androidx.pdf ডিপেন্ডেন্সিটি ঘোষণা করুন। পিডিএফ লাইব্রেরিটি গুগল ম্যাভেন রিপোজিটরি থেকে পাওয়া যায়।

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

PdfViewerFragment বৈশিষ্ট্য

PdfViewerFragment পিডিএফ ডকুমেন্টকে পৃষ্ঠাঙ্কিত বিন্যাসে উপস্থাপন করে, ফলে এগুলিতে নেভিগেট করা সহজ হয়। কার্যকর লোডিংয়ের জন্য, এই ফ্র্যাগমেন্টটি একটি দ্বি-স্তরীয় রেন্ডারিং কৌশল ব্যবহার করে, যা পর্যায়ক্রমে পৃষ্ঠার মাপ লোড করে।

মেমরি ব্যবহার অপ্টিমাইজ করার জন্য, PdfViewerFragment শুধুমাত্র বর্তমানে দৃশ্যমান পৃষ্ঠাগুলি রেন্ডার করে এবং স্ক্রিনের বাইরে থাকা পৃষ্ঠাগুলির বিটম্যাপ রিলিজ করে। এছাড়াও, PdfViewerFragment একটি ফ্লোটিং অ্যাকশন বাটন (FAB) অন্তর্ভুক্ত রয়েছে যা ডকুমেন্ট URI সম্বলিত একটি ইমপ্লিসিট android.intent.action.ANNOTATE ইন্টেন্ট ফায়ার করার মাধ্যমে অ্যানোটেশন সমর্থন করে।

বাস্তবায়ন

আপনার অ্যান্ড্রয়েড অ্যাপ্লিকেশনে একটি পিডিএফ ভিউয়ার যুক্ত করা একটি বহু-ধাপের প্রক্রিয়া।

অ্যাক্টিভিটি লেআউট তৈরি করুন

প্রথমে, যে অ্যাক্টিভিটিতে পিডিএফ ভিউয়ারটি থাকবে, তার লেআউট XML নির্ধারণ করুন। এই লেআউটে PdfViewerFragment কে ধারণ করার জন্য একটি FrameLayout এবং ডকুমেন্টের মধ্যে অনুসন্ধানের মতো ব্যবহারকারীর কার্যকলাপের জন্য বাটন থাকা উচিত।

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

কার্যকলাপটি সেট আপ করুন

যে অ্যাক্টিভিটিটি PdfViewerFragment হোস্ট করে, সেটিকে অবশ্যই AppCompatActivity এক্সটেন্ড করতে হবে। অ্যাক্টিভিটির onCreate() মেথডে, কন্টেন্ট ভিউ হিসেবে আপনার তৈরি করা লেআউটটি সেট করুন এবং প্রয়োজনীয় UI এলিমেন্টগুলো ইনিশিয়ালাইজ করুন।

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 API ব্যবহার করে সার্চ বারের দৃশ্যমানতা নিয়ন্ত্রণ করতে পারেন। ডকুমেন্ট সার্চ সক্রিয় করতে, আপনাকে আপনার 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)
    }
}

ফাইল পিকারের সাথে একীভূত করুন

ব্যবহারকারীদের তাদের ডিভাইস থেকে পিডিএফ ফাইল নির্বাচন করার সুযোগ দিতে, অ্যান্ড্রয়েড ফাইল পিকারের সাথে PdfViewerFragment সংযুক্ত করুন। প্রথমে, আপনার অ্যাক্টিভিটির লেআউট XML আপডেট করে তাতে একটি বাটন যুক্ত করুন যা ফাইল পিকারটি চালু করবে।

<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()) ব্যবহার করে ফাইল পিকারটি চালু করুন। যখন ব্যবহারকারী একটি ফাইল নির্বাচন করেন, তখন কলব্যাকটি একটি URI প্রদান করে। তারপর, নির্বাচিত PDF ফাইলটি লোড ও প্রদর্শন করার জন্য, আপনি আপনার PdfViewerFragment ইনস্ট্যান্সের documentUri প্রপার্টিতে এই URI-টি সেট করবেন।

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

UI কাস্টমাইজ করুন

লাইব্রেরি দ্বারা প্রদত্ত XML অ্যাট্রিবিউটগুলো ওভাররাইড করার মাধ্যমে আপনি PdfViewerFragment এর ইউজার ইন্টারফেস কাস্টমাইজ করতে পারেন। এর ফলে আপনি স্ক্রলবার এবং পেজ ইন্ডিকেটরের মতো এলিমেন্টগুলোর চেহারা আপনার অ্যাপের ডিজাইনের সাথে মিলিয়ে সাজিয়ে নিতে পারবেন।

কাস্টমাইজযোগ্য বৈশিষ্ট্যগুলির মধ্যে রয়েছে:

  • fastScrollVerticalThumbDrawable — স্ক্রলবার থাম্বের জন্য ড্রয়েবল নির্ধারণ করে।
  • fastScrollPageIndicatorBackgroundDrawable — পেজ ইন্ডিকেটরের জন্য ব্যাকগ্রাউন্ড ড্রয়েবল সেট করে।
  • fastScrollPageIndicatorMarginEnd — পেজ ইন্ডিকেটরের জন্য ডান মার্জিন নির্ধারণ করে। মার্জিনের মান অবশ্যই ধনাত্মক হতে হবে।
  • fastScrollVerticalThumbMarginEnd — ভার্টিকাল স্ক্রলবার থাম্বের জন্য ডান মার্জিন নির্ধারণ করে। মার্জিনের মান অবশ্যই ধনাত্মক হতে হবে।

এই কাস্টমাইজেশনগুলো প্রয়োগ করতে, আপনার XML রিসোর্সগুলিতে একটি কাস্টম স্টাইল সংজ্ঞায়িত করুন।

<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.newInstance(stylingOptions) ব্যবহার করে ফ্র্যাগমেন্টের একটি ইনস্ট্যান্স তৈরি করার সময়, PdfStylingOptions ব্যবহার করে PdfViewerFragment কে কাস্টম স্টাইল রিসোর্সটি প্রদান করুন।

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 সাবক্লাস করে থাকেন, তাহলে স্টাইলিং অপশনগুলো দেওয়ার জন্য protected কনস্ট্রাক্টর ব্যবহার করুন। এটি নিশ্চিত করে যে আপনার কাস্টম স্টাইলগুলো আপনার বর্ধিত ফ্র্যাগমেন্টে সঠিকভাবে প্রয়োগ হবে।

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 কীভাবে প্রয়োগ করতে হয় তার একটি সম্পূর্ণ উদাহরণ দেওয়া হয়েছে, যার মধ্যে রয়েছে ইনিশিয়ালাইজেশন, ফাইল পিকার ইন্টিগ্রেশন, সার্চ ফাংশনালিটি এবং UI কাস্টমাইজেশন।

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 এক্সটেন্ড করতে পারেন।
  • XML অ্যাট্রিবিউট ওভাররাইড করে PdfViewerFragment এর UI কাস্টমাইজ করুন।