Skip to content

Commit ba82835

Browse files
miseke-ffwrschattauer
authored andcommitted
Implement render quality and scroll to top listener
1 parent a9ac5de commit ba82835

File tree

5 files changed

+58
-8
lines changed

5 files changed

+58
-8
lines changed

pdfViewer/src/main/java/com/rajat/pdfviewer/PdfRendererView.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ class PdfRendererView @JvmOverloads constructor(
7676
// endregion
7777

7878
var zoomListener: ZoomListener? = null
79+
var scrollListener: ScrollListener? = null
7980
var statusListener: StatusCallBack? = null
81+
var renderQuality: RenderQuality = RenderQuality.NORMAL
8082

8183
//region Public APIs
8284
fun isZoomedIn(): Boolean = this::recyclerView.isInitialized && recyclerView.isZoomedIn()
@@ -217,7 +219,8 @@ class PdfRendererView @JvmOverloads constructor(
217219
pdfRendererCore,
218220
this,
219221
pageMargin,
220-
enableLoadingForPages
222+
enableLoadingForPages,
223+
renderQuality
221224
)
222225

223226
recyclerView.apply {
@@ -230,6 +233,7 @@ class PdfRendererView @JvmOverloads constructor(
230233
}.let { addItemDecoration(it) }
231234
}
232235
setZoomEnabled(isZoomEnabled)
236+
setRenderQuality(renderQuality)
233237
}
234238

235239
recyclerView.addOnScrollListener(
@@ -253,6 +257,9 @@ class PdfRendererView @JvmOverloads constructor(
253257
recyclerView.setOnZoomChangeListener { isZoomedIn, scale ->
254258
zoomListener?.onZoomChanged(isZoomedIn, scale)
255259
}
260+
recyclerView.setScrollListener { isScrolledToTop ->
261+
scrollListener?.onScroll(isScrolledToTop)
262+
}
256263

257264
recyclerView.post {
258265
postInitializationAction?.invoke()
@@ -478,4 +485,8 @@ class PdfRendererView @JvmOverloads constructor(
478485
interface ZoomListener {
479486
fun onZoomChanged(isZoomedIn: Boolean, scale: Float)
480487
}
488+
489+
interface ScrollListener {
490+
fun onScroll(isScrolledToTop: Boolean)
491+
}
481492
}

pdfViewer/src/main/java/com/rajat/pdfviewer/PdfViewAdapter.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ internal class PdfViewAdapter(
2525
private val renderer: PdfRendererCore,
2626
private val parentView: PdfRendererView,
2727
private val pageSpacing: Rect,
28-
private val enableLoadingForPages: Boolean
28+
private val enableLoadingForPages: Boolean,
29+
private val renderQuality: RenderQuality,
2930
) : RecyclerView.Adapter<PdfViewAdapter.PdfPageViewHolder>() {
3031

3132
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PdfPageViewHolder =
@@ -75,6 +76,9 @@ internal class PdfViewAdapter(
7576

7677
if (cached != null && currentBoundPage == position) {
7778
if (DEBUG_LOGS_ENABLED) Log.d("PdfViewAdapter", "✅ Loaded page $position from cache")
79+
val aspectRatio = cached.width.toFloat() / cached.height.toFloat()
80+
val height = (displayWidth / aspectRatio).toInt()
81+
itemBinding.updateLayoutParams(height)
7882
itemBinding.pageView.setImageBitmap(cached)
7983
hasRealBitmap = true
8084
applyFadeInAnimation(itemBinding.pageView)
@@ -89,7 +93,9 @@ internal class PdfViewAdapter(
8993
val height = (displayWidth / aspectRatio).toInt()
9094
itemBinding.updateLayoutParams(height)
9195

92-
renderAndApplyBitmap(position, displayWidth, height)
96+
val bitmapWidth = (displayWidth * renderQuality.qualityMultiplier).toInt()
97+
val bitmapHeight = (height * renderQuality.qualityMultiplier).toInt()
98+
renderAndApplyBitmap(position, bitmapWidth, bitmapHeight)
9399
}
94100
}
95101

@@ -127,7 +133,7 @@ internal class PdfViewAdapter(
127133
}
128134

129135
private fun retryRenderOnce(page: Int, width: Int, height: Int) {
130-
val retryBitmap = CommonUtils.Companion.BitmapPool.getBitmap(width, height)
136+
val retryBitmap = CommonUtils.Companion.BitmapPool.getBitmap(width, maxOf(1, height))
131137
renderer.renderPage(page, retryBitmap) { success, retryPageNo, rendered ->
132138
scope.launch {
133139
if (success && retryPageNo == currentBoundPage && !hasRealBitmap) {

pdfViewer/src/main/java/com/rajat/pdfviewer/PinchZoomRecyclerView.kt

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ class PinchZoomRecyclerView @JvmOverloads constructor(
2323
private val gestureDetector = GestureDetector(context, GestureListener())
2424

2525
// Zoom and pan state
26+
private var renderQuality = RenderQuality.NORMAL
2627
private var scaleFactor = 1f
2728
private var isZoomEnabled = true
28-
private var maxZoom = MAX_ZOOM
29+
private val maxZoom get() = MAX_ZOOM * renderQuality.qualityMultiplier
2930
private var zoomDuration = ZOOM_DURATION
3031
private var isZoomingInProgress = false
32+
private var isOnTop = true
3133

3234
// Panning offsets and touch memory
3335
private var lastTouchX = 0f
@@ -36,6 +38,7 @@ class PinchZoomRecyclerView @JvmOverloads constructor(
3638
private var posY = 0f
3739

3840
private var zoomChangeListener: ((Boolean, Float) -> Unit)? = null
41+
private var scrollListener: ((Boolean) -> Unit)? = null
3942

4043
init {
4144
setWillNotDraw(false)
@@ -53,6 +56,14 @@ class PinchZoomRecyclerView @JvmOverloads constructor(
5356
zoomChangeListener = listener
5457
}
5558

59+
fun setScrollListener(listener: (isScrolledToTop: Boolean) -> Unit) {
60+
scrollListener = listener
61+
}
62+
63+
fun setRenderQuality(quality: RenderQuality) {
64+
renderQuality = quality
65+
}
66+
5667
/**
5768
* Handles touch interactions — zoom, pan, and scroll.
5869
*/
@@ -73,9 +84,9 @@ class PinchZoomRecyclerView @JvmOverloads constructor(
7384
activePointerId = ev.getPointerId(0)
7485
}
7586
MotionEvent.ACTION_MOVE -> {
76-
if (!scaleDetector.isInProgress && scaleFactor > 1f) {
77-
val pointerIndex = ev.findPointerIndex(activePointerId)
78-
if (pointerIndex != -1) {
87+
val pointerIndex = ev.findPointerIndex(activePointerId)
88+
if (pointerIndex != -1) {
89+
if (!scaleDetector.isInProgress && scaleFactor > 1f) {
7990
val x = ev.getX(pointerIndex)
8091
val y = ev.getY(pointerIndex)
8192
val dx = x - lastTouchX
@@ -88,6 +99,16 @@ class PinchZoomRecyclerView @JvmOverloads constructor(
8899
lastTouchX = x
89100
lastTouchY = y
90101
}
102+
103+
val isScrolledOut = !scaleDetector.isInProgress && scaleFactor == 1f
104+
val currentScrollOffset = computeVerticalScrollOffset()
105+
if (currentScrollOffset == 0 && isScrolledOut && !isOnTop) {
106+
scrollListener?.invoke(true)
107+
isOnTop = true
108+
} else if ((currentScrollOffset != 0 || isScrolledOut.not()) && isOnTop) {
109+
scrollListener?.invoke(false)
110+
isOnTop = false
111+
}
91112
}
92113
}
93114
MotionEvent.ACTION_POINTER_UP -> {
@@ -178,6 +199,8 @@ class PinchZoomRecyclerView @JvmOverloads constructor(
178199
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
179200
isZoomingInProgress = true
180201
suppressLayout(true)
202+
scrollListener?.invoke(false)
203+
isOnTop = false
181204
return true
182205
}
183206

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.rajat.pdfviewer
2+
3+
enum class RenderQuality(val qualityMultiplier: Float) {
4+
NORMAL(qualityMultiplier = 1f), HIGH(qualityMultiplier = 2f), ULTRA(qualityMultiplier = 3f)
5+
}

pdfViewer/src/main/java/com/rajat/pdfviewer/compose/PdfRendererCompose.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
1414
import androidx.lifecycle.lifecycleScope
1515
import com.rajat.pdfviewer.HeaderData
1616
import com.rajat.pdfviewer.PdfRendererView
17+
import com.rajat.pdfviewer.RenderQuality
1718
import com.rajat.pdfviewer.util.CacheStrategy
1819
import com.rajat.pdfviewer.util.FileUtils.fileFromAsset
1920
import com.rajat.pdfviewer.util.PdfSource
@@ -23,12 +24,14 @@ import java.io.File
2324
fun PdfRendererViewCompose(
2425
source: PdfSource,
2526
modifier: Modifier = Modifier,
27+
renderQuality: RenderQuality = RenderQuality.NORMAL,
2628
headers: HeaderData = HeaderData(),
2729
cacheStrategy: CacheStrategy = CacheStrategy.MAXIMIZE_PERFORMANCE,
2830
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
2931
jumpToPage: Int? = null,
3032
statusCallBack: PdfRendererView.StatusCallBack? = null,
3133
zoomListener: PdfRendererView.ZoomListener? = null,
34+
scrollListener: PdfRendererView.ScrollListener? = null,
3235
onReady: ((PdfRendererView) -> Unit)? = null,
3336
) {
3437
val context = LocalContext.current
@@ -69,6 +72,8 @@ fun PdfRendererViewCompose(
6972
update = { view ->
7073
view.statusListener = combinedCallback
7174
view.zoomListener = zoomListener
75+
view.scrollListener = scrollListener
76+
view.renderQuality = renderQuality
7277

7378
if (!initialized) {
7479
when (source) {

0 commit comments

Comments
 (0)