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 ของเลย์เอาต์
กิจกรรมให้มีปุ่มที่เปิดเครื่องมือเลือกไฟล์
<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 จากนั้นตั้งค่าพร็อพเพอร์ตี้ 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