PdfViewerFragment เป็น Fragment เฉพาะทางที่คุณใช้เพื่อแสดงเอกสาร PDF ภายในแอปพลิเคชัน Android ได้
PdfViewerFragment ช่วยให้การแสดงผล PDF ง่ายขึ้น คุณจึงมุ่งเน้นไปที่
ฟังก์ชันการทำงานอื่นๆ ของแอปได้
ผลลัพธ์
ความเข้ากันได้ของเวอร์ชัน
หากต้องการใช้ PdfViewerFragment แอปพลิเคชันของคุณต้องกำหนดเป้าหมายเป็น Android S
(API ระดับ 31) และระดับส่วนขยาย SDK 13 เป็นอย่างน้อย หากไม่เป็นไปตามข้อกำหนดด้านความเข้ากันได้เหล่านี้
ไลบรารีจะแสดง
UnsupportedOperationException
คุณสามารถตรวจสอบเวอร์ชันส่วนขยาย SDK ได้ที่รันไทม์โดยใช้โมดูล SdkExtensions
ซึ่งช่วยให้คุณโหลด Fragment และเอกสาร PDF แบบมีเงื่อนไขได้
ก็ต่อเมื่ออุปกรณ์เป็นไปตามข้อกำหนดที่จำเป็นเท่านั้น
if (SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S) >= 13) {
// Load the fragment and document.
}
การขึ้นต่อกัน
หากต้องการรวมโปรแกรมดู PDF ไว้ในแอปพลิเคชัน ให้ประกาศทรัพยากร Dependency androidx.pdf ในไฟล์ build.gradle
ของโมดูลแอป เข้าถึงไลบรารี PDF ได้จากที่เก็บ Maven ของ Google
dependencies {
val pdfVersion = "1.0.0-alpha0X"
implementation("androidx.pdf:pdf:pdf-viewer-fragment:$pdfVersion")
}
ฟีเจอร์ PdfViewerFragment รายการ
PdfViewerFragment จะแสดงเอกสาร PDF ในรูปแบบที่มีการแบ่งหน้า ทำให้ไปยังส่วนต่างๆ ได้ง่าย
เพื่อการโหลดที่มีประสิทธิภาพ Fragment ใช้กลยุทธ์การแสดงผลแบบ 2 รอบ
ซึ่งจะโหลดมิติข้อมูลหน้าเว็บแบบทีละรายการ
PdfViewerFragment จะแสดงเฉพาะหน้าเว็บที่มองเห็นได้ในปัจจุบันและปล่อยบิตแมปสำหรับหน้าเว็บที่อยู่นอกหน้าจอเพื่อเพิ่มประสิทธิภาพการใช้หน่วยความจำ
นอกจากนี้ PdfViewerFragment ยังมีปุ่มการทำงานแบบลอย (FAB) ที่
รองรับคำอธิบายประกอบโดยการเรียกใช้ android.intent.action.ANNOTATE
Intent โดยนัยซึ่งมี URI ของเอกสาร
การใช้งาน
การเพิ่มโปรแกรมดู PDF ลงในแอปพลิเคชัน Android เป็นกระบวนการที่มีหลายขั้นตอน
สร้างเลย์เอาต์กิจกรรม
เริ่มต้นด้วยการกำหนด XML ของเลย์เอาต์สำหรับกิจกรรมที่โฮสต์โปรแกรมดู 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>
ตั้งค่ากิจกรรม
กิจกรรมที่โฮสต์ 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
สร้างอินสแตนซ์ของ PdfViewerFragment โดยใช้ FragmentManager ที่ได้จาก
getSupportFragmentManager() ตรวจสอบว่ามีอินสแตนซ์ของ Fragment อยู่แล้วหรือไม่ก่อนสร้างอินสแตนซ์ใหม่ โดยเฉพาะอย่างยิ่ง
ในระหว่างการเปลี่ยนแปลงการกำหนดค่า
ในตัวอย่างต่อไปนี้ ฟังก์ชัน initializePdfViewerFragment() จะจัดการ
การสร้างและการคอมมิตธุรกรรมของ Fragment ฟังก์ชันนี้จะแทนที่ Fragment ที่มีอยู่ในคอนเทนเนอร์ด้วยอินสแตนซ์ของ 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 หากต้องการเปิดใช้การค้นหาเอกสาร ให้ตั้งค่าพร็อพเพอร์ตี้
isTextSearchActive ของอินสแตนซ์ PdfViewerFragment
ใช้
WindowCompat.setDecorFitsSystemWindows()
เพื่อให้แน่ใจว่า WindowInsetsCompat จะส่งไปยังมุมมองเนื้อหาอย่างถูกต้อง ซึ่งเป็นสิ่งจำเป็นสำหรับการวางตำแหน่งมุมมองการค้นหาอย่างเหมาะสม
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 ก่อนอื่น ให้อัปเดต XML เลย์เอาต์ของกิจกรรม
ให้มีปุ่มที่เปิดตัวเลือกไฟล์
<...>
<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 จากนั้นตั้งค่าพร็อพเพอร์ตี้ documentUri ของอินสแตนซ์ PdfViewerFragment ด้วย URI นี้เพื่อโหลดและแสดง PDF ที่เลือก
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
คุณปรับแต่งอินเทอร์เฟซผู้ใช้ของ PdfViewerFragment ได้โดยการลบล้างแอตทริบิวต์ XML
ที่ไลบรารีแสดง ซึ่งจะช่วยให้คุณปรับแต่งลักษณะที่ปรากฏขององค์ประกอบต่างๆ เช่น แถบเลื่อนและตัวบ่งหน้า ให้ตรงกับการออกแบบของแอปได้
แอตทริบิวต์ที่ปรับแต่งได้ ได้แก่
fastScrollVerticalThumbDrawable— ตั้งค่า Drawable สำหรับ แถบเลื่อนfastScrollPageIndicatorBackgroundDrawable— ตั้งค่า Drawable พื้นหลังสำหรับตัวระบุหน้า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 โดยใช้
PdfStylingOptions เมื่อสร้างอินสแตนซ์ของ Fragment ด้วย
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 ให้ใช้ตัวสร้างที่ได้รับการป้องกันเพื่อ
ระบุตัวเลือกการจัดรูปแบบ เพื่อให้มั่นใจว่าระบบจะใช้สไตล์ที่กำหนดเองกับ Fragment ที่ขยายอย่างถูกต้อง
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"
}
}
ประเด็นสำคัญเกี่ยวกับโค้ด
- ตรวจสอบว่าโปรเจ็กต์เป็นไปตามข้อกำหนดระดับ API ขั้นต่ำและส่วนขยาย SDK
- กิจกรรมที่โฮสต์
PdfViewerFragmentต้องขยายAppCompatActivity - คุณขยาย
PdfViewerFragmentเพื่อเพิ่มลักษณะการทำงานที่กำหนดเองได้ - ปรับแต่ง UI ของ
PdfViewerFragmentโดยการลบล้างแอตทริบิวต์ XML