parent
b4eb0d0958
commit
8b3d956e7e
@ -1,39 +0,0 @@ |
||||
package io.legado.app.ui.widget.page |
||||
|
||||
import android.widget.Scroller |
||||
import androidx.interpolator.view.animation.FastOutLinearInInterpolator |
||||
|
||||
abstract class PageAnimDelegate(protected val pageView: PageView) { |
||||
|
||||
protected val scroller: Scroller = Scroller(pageView.context, FastOutLinearInInterpolator()) |
||||
|
||||
//起始点 |
||||
protected var startX: Float = 0.toFloat() |
||||
protected var startY: Float = 0.toFloat() |
||||
//触碰点 |
||||
protected var touchX: Float = 0.toFloat() |
||||
protected var touchY: Float = 0.toFloat() |
||||
//上一个触碰点 |
||||
protected var lastX: Float = 0.toFloat() |
||||
protected var lastY: Float = 0.toFloat() |
||||
|
||||
protected var isRunning = false |
||||
protected var isStarted = false |
||||
|
||||
|
||||
fun setStartPoint(x: Float, y: Float) { |
||||
startX = x |
||||
startY = y |
||||
|
||||
lastX = startX |
||||
lastY = startY |
||||
} |
||||
|
||||
fun setTouchPoint(x: Float, y: Float) { |
||||
lastX = touchX |
||||
lastY = touchY |
||||
|
||||
touchX = x |
||||
touchY = y |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
package io.legado.app.ui.widget.page.delegate |
||||
|
||||
import android.graphics.Canvas |
||||
import android.graphics.Matrix |
||||
import android.graphics.drawable.GradientDrawable |
||||
import io.legado.app.ui.widget.page.PageView |
||||
|
||||
class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { |
||||
|
||||
private val shadowDrawableR: GradientDrawable |
||||
private val shadowDrawableL: GradientDrawable |
||||
private val bitmapMatrix = Matrix() |
||||
|
||||
init { |
||||
val shadowColors = intArrayOf(0x66111111, 0x00000000) |
||||
shadowDrawableR = GradientDrawable( |
||||
GradientDrawable.Orientation.LEFT_RIGHT, shadowColors |
||||
) |
||||
shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT |
||||
|
||||
shadowDrawableL = GradientDrawable( |
||||
GradientDrawable.Orientation.RIGHT_LEFT, shadowColors |
||||
) |
||||
shadowDrawableL.gradientType = GradientDrawable.LINEAR_GRADIENT |
||||
} |
||||
|
||||
override fun onStart() { |
||||
val distanceX: Float |
||||
when (direction) { |
||||
Direction.NEXT -> if (isCancel) { |
||||
var dis = viewWidth - startX + touchX |
||||
if (dis > viewWidth) { |
||||
dis = viewWidth.toFloat() |
||||
} |
||||
distanceX = viewWidth - dis |
||||
} else { |
||||
distanceX = -(touchX + (viewWidth - startX)) |
||||
} |
||||
else -> distanceX = if (isCancel) { |
||||
-(touchX - startX) |
||||
} else { |
||||
viewWidth - (touchX - startX) |
||||
} |
||||
} |
||||
|
||||
scroller.startScroll(touchX.toInt(), 0, distanceX.toInt(), 0, getDuration(distanceX)) |
||||
start() |
||||
} |
||||
|
||||
override fun onPerform(canvas: Canvas) { |
||||
val offsetX = touchX - startX |
||||
|
||||
if(offsetX == 0.toFloat()) return |
||||
|
||||
val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth |
||||
bitmap?.let { |
||||
bitmapMatrix.setTranslate(distanceX, 0.toFloat()) |
||||
canvas.drawBitmap(it, bitmapMatrix, null) |
||||
|
||||
addShadow(distanceX.toInt(), canvas) |
||||
} |
||||
} |
||||
|
||||
private fun addShadow(left: Int, canvas: Canvas?) { |
||||
canvas?.let { |
||||
if (left < 0) { |
||||
shadowDrawableR.setBounds(left + viewWidth, 0, left+ viewWidth + 30, viewHeight) |
||||
shadowDrawableR.draw(it) |
||||
} else { |
||||
shadowDrawableL.setBounds(left - 30, 0, left, viewHeight) |
||||
shadowDrawableL.draw(it) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,247 @@ |
||||
package io.legado.app.ui.widget.page.delegate |
||||
|
||||
import android.graphics.Bitmap |
||||
import android.graphics.Canvas |
||||
import android.view.GestureDetector |
||||
import android.view.MotionEvent |
||||
import android.view.View |
||||
import android.widget.Scroller |
||||
import androidx.interpolator.view.animation.FastOutLinearInInterpolator |
||||
import io.legado.app.ui.widget.page.PageView |
||||
import io.legado.app.utils.screenshot |
||||
import kotlinx.android.synthetic.main.view_book_page.view.* |
||||
import kotlin.math.abs |
||||
|
||||
abstract class PageDelegate(private val pageView: PageView) { |
||||
|
||||
//起始点 |
||||
protected var startX: Float = 0.toFloat() |
||||
protected var startY: Float = 0.toFloat() |
||||
//触碰点 |
||||
protected var touchX: Float = 0.toFloat() |
||||
protected var touchY: Float = 0.toFloat() |
||||
|
||||
protected val view: View |
||||
get() = pageView.page_panel |
||||
|
||||
protected var bitmap: Bitmap? = null |
||||
|
||||
protected var viewWidth: Int = pageView.width |
||||
protected var viewHeight: Int = pageView.height |
||||
|
||||
protected val scroller: Scroller by lazy { Scroller(pageView.context, FastOutLinearInInterpolator()) } |
||||
|
||||
private val detector: GestureDetector by lazy { GestureDetector(pageView.context, GestureListener()) } |
||||
|
||||
private var isMoved = false |
||||
private var noNext = true |
||||
|
||||
//移动方向 |
||||
var direction = Direction.NONE |
||||
var isCancel = false |
||||
var isRunning = false |
||||
var isStarted = false |
||||
|
||||
protected fun setStartPoint(x: Float, y: Float, invalidate: Boolean = true) { |
||||
startX = x |
||||
startY = y |
||||
|
||||
if (invalidate) { |
||||
invalidate() |
||||
} |
||||
} |
||||
|
||||
protected fun setTouchPoint(x: Float, y: Float, invalidate: Boolean = true) { |
||||
touchX = x |
||||
touchY = y |
||||
|
||||
if (invalidate) { |
||||
invalidate() |
||||
} |
||||
} |
||||
|
||||
fun setViewSize(width: Int, height: Int) { |
||||
viewWidth = width |
||||
viewHeight = height |
||||
invalidate() |
||||
} |
||||
|
||||
fun invalidate() { |
||||
pageView.invalidate() |
||||
} |
||||
|
||||
fun start() { |
||||
isRunning = true |
||||
isStarted = true |
||||
invalidate() |
||||
} |
||||
|
||||
fun stop() { |
||||
isRunning = false |
||||
isStarted = false |
||||
bitmap = null |
||||
invalidate() |
||||
} |
||||
|
||||
fun scroll() { |
||||
if (scroller.computeScrollOffset()) { |
||||
setTouchPoint(scroller.currX.toFloat(), scroller.currY.toFloat()) |
||||
} else if(isStarted){ |
||||
setTouchPoint(scroller.finalX.toFloat(), scroller.finalY.toFloat(), false) |
||||
stop() |
||||
} |
||||
} |
||||
|
||||
fun abort() { |
||||
if (!scroller.isFinished) { |
||||
scroller.abortAnimation() |
||||
} |
||||
} |
||||
|
||||
fun start(direction: Direction) { |
||||
if (isStarted) return |
||||
this.direction = direction |
||||
if (direction === Direction.NEXT) { |
||||
val x = viewWidth.toFloat() |
||||
val y = viewHeight.toFloat() |
||||
//初始化动画 |
||||
setStartPoint(x, y, false) |
||||
//设置点击点 |
||||
setTouchPoint(x, y, false) |
||||
//设置方向 |
||||
val hasNext = pageView.hasNext() |
||||
if (!hasNext) { |
||||
return |
||||
} |
||||
} else { |
||||
val x = 0.toFloat() |
||||
val y = viewHeight.toFloat() |
||||
//初始化动画 |
||||
setStartPoint(x, y, false) |
||||
//设置点击点 |
||||
setTouchPoint(x, y, false) |
||||
//设置方向方向 |
||||
val hashPrev = pageView.hasPrev() |
||||
if (!hashPrev) { |
||||
return |
||||
} |
||||
} |
||||
onStart() |
||||
} |
||||
|
||||
fun onTouch(event: MotionEvent): Boolean { |
||||
if (isMoved && event.action == MotionEvent.ACTION_UP) { |
||||
// 开启翻页效果 |
||||
if (!noNext) { |
||||
onStart() |
||||
} |
||||
return true |
||||
} |
||||
return detector.onTouchEvent(event) |
||||
} |
||||
|
||||
fun getDuration(distance: Float): Int { |
||||
val duration = 300 * abs(distance) / viewWidth |
||||
return duration.toInt() |
||||
} |
||||
|
||||
abstract fun onStart() |
||||
|
||||
abstract fun onPerform(canvas: Canvas) |
||||
|
||||
enum class Direction { |
||||
NONE, PREV, NEXT |
||||
} |
||||
|
||||
private inner class GestureListener : GestureDetector.OnGestureListener { |
||||
|
||||
override fun onDown(e: MotionEvent): Boolean { |
||||
abort() |
||||
//是否移动 |
||||
isMoved = false |
||||
//是否存在下一章 |
||||
noNext = false |
||||
//是否正在执行动画 |
||||
isRunning = false |
||||
//取消 |
||||
isCancel = false |
||||
//是下一章还是前一章 |
||||
direction = Direction.NONE |
||||
//设置起始位置的触摸点 |
||||
setStartPoint(e.x, e.y) |
||||
return true |
||||
} |
||||
|
||||
override fun onShowPress(e: MotionEvent) {} |
||||
|
||||
override fun onSingleTapUp(e: MotionEvent): Boolean { |
||||
val x = e.x |
||||
val y = e.y |
||||
direction = if (x > viewWidth / 2) Direction.NEXT else Direction.PREV |
||||
if (direction == Direction.NEXT) { |
||||
//判断是否下一页存在 |
||||
val hasNext = pageView.hasNext() |
||||
//设置动画方向 |
||||
if (!hasNext) { |
||||
return true |
||||
} |
||||
} else { |
||||
val hasPrev = pageView.hasPrev() |
||||
if (!hasPrev) { |
||||
return true |
||||
} |
||||
} |
||||
setTouchPoint(x, y) |
||||
return true |
||||
} |
||||
|
||||
override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { |
||||
if (!isMoved && abs(distanceX) > abs(distanceY)) { |
||||
//上一页或下一页截图,还未处理 |
||||
bitmap = pageView.screenshot() |
||||
if (distanceX < 0) { |
||||
//上一页的参数配置 |
||||
direction = Direction.PREV |
||||
//判断是否上一页存在 |
||||
val hasPrev = pageView.hasPrev() |
||||
//如果上一页不存在 |
||||
if (!hasPrev) { |
||||
noNext = true |
||||
return true |
||||
} |
||||
} else { |
||||
//进行下一页的配置 |
||||
direction = Direction.NEXT |
||||
//判断是否下一页存在 |
||||
val hasNext = pageView.hasNext() |
||||
//如果不存在表示没有下一页了 |
||||
if (!hasNext) { |
||||
noNext = true |
||||
return true |
||||
} |
||||
} |
||||
isMoved = true |
||||
} |
||||
if (isMoved) { |
||||
isCancel = if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 |
||||
isRunning = true |
||||
//设置触摸点 |
||||
setTouchPoint(e2.x, e2.y) |
||||
} |
||||
return isMoved |
||||
} |
||||
|
||||
override fun onLongPress(e: MotionEvent) { |
||||
|
||||
} |
||||
|
||||
override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { |
||||
return false |
||||
} |
||||
} |
||||
|
||||
interface PageInterface { |
||||
fun hasNext(): Boolean |
||||
fun hasPrev(): Boolean |
||||
} |
||||
} |
Loading…
Reference in new issue