У меня есть свой собственный вид, который расширяет RecyclerView
, и я использую его для отображения документа на нескольких страницах.Каждый элемент в адаптере - это страница.
Я хочу добавить возможность масштабирования и панорамирования всего документа (не каждой страницы отдельно).
Я пытался следовать руководству по Android здесь , но я все еще не могу заставить и зум, и панорамирование работать должным образом.
Мой текущий подход таков:
- Имею
GestureDetector
для обнаружения жестов панорамирования - Имеют
ScaleGestureDetector
для обнаружения жестов щипка - Когда каждый из этих детекторов регистрирует события, сохраните информацию о текущем масштабном коэффициенте и панорамировании, позвоните
invalidate()
и измените Canvas
в методе drawChild
соответствующим образом.
Это последний шаг, который я не знаю, как правильно реализовать.
Я использую этот класс данных для отслеживаниятекущее панорамирование и масштабирование представления:
private data class PanAndZoom(
var scaleFactor: Float,
var focusX: Float,
var focusY: Float,
var panX: Float ,
var panY: Float
)
// field in my custom view initialised like this:
private val panAndZoom = PanAndZoom(1f, 0f, 0f, 0f, 0f)
, и вот как я обновляю значения при получении жестов:
private val scaleGestureDetector = ScaleGestureDetector(context, object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
override fun onScale(detector: ScaleGestureDetector): Boolean {
panAndZoom.scaleFactor *= detector.scaleFactor
panAndZoom.focusX = detector.focusX
panAndZoom.focusY = detector.focusY
invalidate()
return true
}
}
private val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
panAndZoom.panX -= distanceX
panAndZoom.panY -= distanceY
invalidate()
return true
}
}
Я переопределяю два метода в моем настраиваемом представлении, один для передачиприкоснуться к событиям моих детекторов жестов и один, чтобы нарисовать ребенка VIew:
override fun onTouchEvent(e: MotionEvent): Boolean {
gestureDetector.onTouchEvent(e)
scaleGestureDetector.onTouchEvent(e)
return super.onTouchEvent(e)
}
override fun drawChild(canvas: Canvas, child: View, drawingTime: Long): Boolean {
val save = canvas.save()
canvas.scale(panAndZoom.scaleFactor, panAndZoom.scaleFactor, panAndZoom.focusX, panAndZoom.focusY)
canvas.translate(panAndZoom.panX, panAndZoom.panY)
val result = super.drawChild(canvas, child, drawingTime)
canvas.restoreToCount(save)
return result
}
Однако это не дает ожидаемого результата, а именно:
- Я могу полностью выйти за пределы RV (я понимаю, что не ограничиваю своизначения панорамы, но как мне это сделать?) *
- Панорамирование, кажется, идет очень быстро при увеличении (как мне масштабировать значения панорамирования, чтобы они учитывали коэффициент масштабирования)?
- Если я нахожусь на странице 2 документа, и я увеличиваю, а затем перемещаюсь на страницу 3, менеджер по расположению не понимает, что представление фактически прокручивалось (то есть, вызов
findFirstVisibleItem()
вернет вторую страницу, когда это не так).t на самом деле видимый. - Скорее всего, связан с пунктом выше: я могу перемещаться по странице, и поскольку менеджер по расположению не понимает, что теперь отображается другое представление, он не отображает его (потому что он все ещесчитает, что представление скрыто от просмотра и поэтому оптимизирует его, не отображая его.)