使用 MuPDF 庫橫屏閱讀 PDF 時,頁面被縮小顯示整頁,而非寬度自適應螢幕。期望效果:橫屏時頁面寬度撐滿螢幕,高度可垂直滑動,支援雙指縮放。
MuPDF 默認渲染邏輯為 FitPage(整頁適應),未根據螢幕方向動態切換渲染模式。需手動計算縮放矩陣實現 FitWidth(寬度適應)。
class CustomMuPDFView(context: Context, attrs: AttributeSet) : MuPDFView(context, attrs) {
private var fitWidth = false
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
if (changed || !fitWidth) {
applyFitWidth()
}
}
private fun applyFitWidth() {
val pageWidth = getPageWidth(0).toFloat()
val viewWidth = width.toFloat()
if (pageWidth > 0) {
val scale = viewWidth / pageWidth
// 設置縮放矩陣:寬度適應,居中顯示
val matrix = Matrix().apply {
setScale(scale, scale)
postTranslate(0f, 0f) // 垂直方向不偏移,允許滑動
}
setDisplayMatrix(matrix)
fitWidth = true
}
}
// 暴露方法供 Activity/Fragment 在旋轉時調用
fun refreshFitWidth() {
fitWidth = false
applyFitWidth()
}
}
private val scaleDetector = ScaleGestureDetector(context, object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
override fun onScale(detector: ScaleGestureDetector): Boolean {
val matrix = getDisplayMatrix()
val scaleFactor = detector.scaleFactor
// 限制縮放範圍 0.5x ~ 3.0x
val currentScale = getCurrentScale(matrix)
val newScale = (currentScale * scaleFactor).coerceIn(0.5f, 3.0f)
val finalFactor = newScale / currentScale
matrix.postScale(finalFactor, finalFactor, detector.focusX, detector.focusY)
setDisplayMatrix(matrix)
return true
}
})
override fun onTouchEvent(ev: MotionEvent): Boolean {
scaleDetector.onTouchEvent(ev)
return super.onTouchEvent(ev)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
muPDFView.refreshFitWidth() // 旋轉後重新計算 FitWidth
}
別忘在 `AndroidManifest.xml` 中聲明:
<activity
android:name=".PdfReaderActivity"
android:configChanges="orientation|screenSize|screenLayout"
android:windowSoftInputMode="adjustResize">
| 方案 | 優點 | 缺點 |
|---|---|---|
| MuPDF 自定義 | 功能全、渲染快、支援註釋 | 體積大、需 NDK、授權 GPL |
| Android PdfRenderer | 系統級、無依賴、體積小 | 僅支援 API 21+、功能較簡單 |
| PDFViewPager / pdfviewer | 封裝好、易用 | 依賴 MuPDF 或 PdfRenderer、定制難 |
MuPDF 橫屏寬度自適應關鍵在於根據 View 寬度動態計算縮放矩陣並應用,而非依賴庫默認行為。結合 `ScaleGestureDetector` 即可實現完整的「寬度適應 + 垂直滑動 + 雙指縮放」閱讀體驗。若項目允許,API 21+ 可考慮系統 `PdfRenderer` 簡化依賴。