Refactor Presentation's view to be reusable

This commit is contained in:
Luke Hubmayer-Werner 2024-09-01 04:04:11 +09:30
parent 03f981d3d8
commit c64bc5f403
2 changed files with 97 additions and 64 deletions

View File

@ -6,11 +6,9 @@ import android.graphics.Bitmap
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.Display import android.view.Display
import android.view.WindowManager import android.view.WindowManager
import android.widget.HorizontalScrollView
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import com.lhw.pdf.ui.HorizontalGallery
class MyPresentation(outerContext: Context, display: Display) : Presentation(outerContext, display) { class MyPresentation(outerContext: Context, display: Display) : Presentation(outerContext, display) {
val displayMetrics = DisplayMetrics() val displayMetrics = DisplayMetrics()
@ -20,8 +18,7 @@ class MyPresentation(outerContext: Context, display: Display) : Presentation(out
private val bitmaps = mutableListOf<Bitmap>() private val bitmaps = mutableListOf<Bitmap>()
private val bitmapCumWidths = mutableListOf<Int>(0) private val bitmapCumWidths = mutableListOf<Int>(0)
private val layout = LinearLayout(this.context) private val scroll = HorizontalGallery(this.context)
private val scroll = HorizontalScrollView(this.context)
private var scrollProgress = 0f private var scrollProgress = 0f
private val layoutParams = WindowManager.LayoutParams() private val layoutParams = WindowManager.LayoutParams()
init { init {
@ -31,75 +28,19 @@ class MyPresentation(outerContext: Context, display: Display) : Presentation(out
WindowCompat.getInsetsController(it, it.decorView) WindowCompat.getInsetsController(it, it.decorView)
.hide(WindowInsetsCompat.Type.systemBars()) .hide(WindowInsetsCompat.Type.systemBars())
} }
scroll.addView(layout)
println(layoutParams) println(layoutParams)
addContentView(scroll, layoutParams) addContentView(scroll, layoutParams)
} }
fun updateImages(bitmaps: Iterable<Bitmap>) { fun updateImages(bitmaps: Iterable<Bitmap>) {
println("Updating presentation images") scroll.updateImages(bitmaps)
println("Layout has scale ${layout.scaleX} ${layout.scaleY}")
layout.removeAllViewsInLayout()
this.bitmaps.clear()
bitmapCumWidths.clear()
bitmapCumWidths.add(0)
bitmaps.forEach {
this.bitmaps.add(it)
bitmapCumWidths.add(it.width + bitmapCumWidths.last())
}
if (lazyScroll) {
lazyIdxStart = -1
lazyIdxEnd = -1
layoutVisibleBitmaps()
} else {
layoutAllBitmaps()
}
}
private fun layoutBitmap(bitmap: Bitmap) {
val img = ImageView(this.context)
img.setImageBitmap(bitmap)
img.minimumWidth = bitmap.width // No idea what broke when I refactored this class
img.minimumHeight = bitmap.height
println("${bitmap.width}x${bitmap.height}")
layout.addView(img)
}
private fun layoutAllBitmaps() {
bitmaps.forEach(::layoutBitmap)
println("Presentation heights ${scroll.height} ${layout.height}")
}
private fun layoutVisibleBitmaps() {
val xStart = (scrollProgress * (bitmapCumWidths.last() - scroll.width)).toInt()
val xEnd = xStart + scroll.width
// bitmapCumWidths has a prepended 0
val idxStart = bitmapCumWidths.indexOfFirst { it > xStart }.let { if (it >= 1) it-1 else 0 }
val idxEnd = bitmapCumWidths.indexOfFirst { it > xEnd }.let { if (it >= 0) it else bitmaps.size}
layout.removeAllViewsInLayout()
(idxStart..<idxEnd).map(bitmaps::get).forEach(::layoutBitmap)
lazyIdxStart = idxStart
lazyIdxEnd = idxEnd
println("Laying out pages $idxStart up to $idxEnd - scrollable width ${layout.width}")
} }
fun setScrollProgress(progress: Float) { fun setScrollProgress(progress: Float) {
scrollProgress = progress scroll.setScrollProgress(progress)
var progressPx = (progress * (bitmapCumWidths.last() - scroll.width)).toInt()
if (lazyScroll) {
layoutVisibleBitmaps()
progressPx -= bitmapCumWidths[lazyIdxStart]
}
println("Scrolling view to x=$progressPx of scrollable ${layout.width} (visible width ${scroll.width})")
scroll.scrollTo(progressPx, 0)
} }
fun setScrollPagesProgress(pagesProgress: Float) { fun setScrollPagesProgress(pagesProgress: Float) {
// NB this is nonlinear with unequal page widths scroll.setScrollPagesProgress(pagesProgress)
val p = pagesProgress.toInt()
val progressPx = bitmapCumWidths[p] + (bitmaps[p].width * (pagesProgress % 1F))
val progress = progressPx / (bitmapCumWidths.last() - scroll.width).toFloat()
setScrollProgress(progress)
} }
} }

View File

@ -0,0 +1,92 @@
package com.lhw.pdf.ui
import android.content.Context
import android.graphics.Bitmap
import android.util.DisplayMetrics
import android.view.WindowManager
import android.widget.HorizontalScrollView
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
class HorizontalGallery(outerContext: Context) : HorizontalScrollView(outerContext) {
private val lazyScroll = android.os.Build.VERSION.SDK_INT < 34 //android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
private var lazyIdxStart = -1
private var lazyIdxEnd = -1
private val bitmaps = mutableListOf<Bitmap>()
private val bitmapCumWidths = mutableListOf<Int>(0)
private val layout = LinearLayout(this.context)
private var scrollProgress = 0f
init {
addView(layout)
}
fun updateImages(bitmaps: Iterable<Bitmap>) {
println("Updating presentation images")
println("Layout has scale ${layout.scaleX} ${layout.scaleY}")
layout.removeAllViewsInLayout()
this.bitmaps.clear()
bitmapCumWidths.clear()
bitmapCumWidths.add(0)
bitmaps.forEach {
this.bitmaps.add(it)
bitmapCumWidths.add(it.width + bitmapCumWidths.last())
}
if (lazyScroll) {
lazyIdxStart = -1
lazyIdxEnd = -1
layoutVisibleBitmaps()
} else {
layoutAllBitmaps()
}
}
private fun layoutBitmap(bitmap: Bitmap) {
val img = ImageView(this.context)
img.setImageBitmap(bitmap)
img.minimumWidth = bitmap.width // No idea what broke when I refactored this class
img.minimumHeight = bitmap.height
println("${bitmap.width}x${bitmap.height}")
layout.addView(img)
}
private fun layoutAllBitmaps() {
bitmaps.forEach(::layoutBitmap)
println("Presentation heights $height ${layout.height}")
}
private fun layoutVisibleBitmaps() {
val xStart = (scrollProgress * (bitmapCumWidths.last() - width)).toInt()
val xEnd = xStart + width
// bitmapCumWidths has a prepended 0
val idxStart = bitmapCumWidths.indexOfFirst { it > xStart }.let { if (it >= 1) it-1 else 0 }
val idxEnd = bitmapCumWidths.indexOfFirst { it > xEnd }.let { if (it >= 0) it else bitmaps.size}
layout.removeAllViewsInLayout()
(idxStart..<idxEnd).map(bitmaps::get).forEach(::layoutBitmap)
lazyIdxStart = idxStart
lazyIdxEnd = idxEnd
println("Laying out pages $idxStart up to $idxEnd - scrollable width ${layout.width}")
}
fun setScrollProgress(progress: Float) {
scrollProgress = progress
var progressPx = (progress * (bitmapCumWidths.last() - width)).toInt()
if (lazyScroll) {
layoutVisibleBitmaps()
progressPx -= bitmapCumWidths[lazyIdxStart]
}
println("Scrolling view to x=$progressPx of scrollable ${layout.width} (visible width $width)")
scrollTo(progressPx, 0)
}
fun setScrollPagesProgress(pagesProgress: Float) {
// NB this is nonlinear with unequal page widths
val p = pagesProgress.toInt()
val progressPx = bitmapCumWidths[p] + (bitmaps[p].width * (pagesProgress % 1F))
val progress = progressPx / (bitmapCumWidths.last() - width).toFloat()
setScrollProgress(progress)
}
}