From ecfc0ea84478710176aef8d286eddb74ac966a68 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 15 Feb 2020 22:12:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/read/page/delegate/TestDelegate.kt | 863 ++++++++++++++++++ .../main/res/layout/dialog_read_padding.xml | 64 ++ .../main/res/layout/view_detail_seek_bar.xml | 5 +- app/src/main/res/values/strings.xml | 8 + 4 files changed, 938 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/book/read/page/delegate/TestDelegate.kt diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/TestDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/TestDelegate.kt new file mode 100644 index 000000000..771be510c --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/TestDelegate.kt @@ -0,0 +1,863 @@ +package io.legado.app.ui.book.read.page.delegate + +import android.graphics.* +import android.graphics.drawable.GradientDrawable +import android.os.Trace +import android.view.MotionEvent +import io.legado.app.ui.book.read.page.PageView +import io.legado.app.utils.screenshot +import kotlin.math.hypot + +class TestDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { + private var pointPaint //绘制各标识点的画笔 + : Paint? = null + private var bgPaint //背景画笔 + : Paint? = null + private var pathAPaint //绘制A区域画笔 + : Paint? = null + private var pathBPaint //绘制B区域画笔 + : Paint? = null + private var pathCPaint //绘制C区域画笔 + : Paint? = null + private var textPaint //绘制文字画笔 + : Paint? = null + private var pathCContentPaint //绘制C区域内容画笔 + : Paint? = null + private var a: MyPoint? = null + private var f: MyPoint? = null + private var g: MyPoint? = null + private var e: MyPoint? = null + private var h: MyPoint? = null + private var c: MyPoint? = null + private var j: MyPoint? = null + private var b: MyPoint? = null + private var k: MyPoint? = null + private var d: MyPoint? = null + private var i: MyPoint? = null + private var pathA: Path? = null + private var pathB: Path? = null + private var pathC: Path? = null + private var defaultWidth = 0 //默认宽度 = 0 + private var defaultHeight = 0 //默认高度 = 0 + var lPathAShadowDis = 0f //A区域左阴影矩形短边长度参考值 + var rPathAShadowDis = 0f //A区域右阴影矩形短边长度参考值 + private val mMatrixArray = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 1.0f) + private var mMatrix: Matrix? = null + private var style: String? = null + private var drawableLeftTopRight: GradientDrawable? = null + private var drawableLeftLowerRight: GradientDrawable? = null + private var drawableRightTopRight: GradientDrawable? = null + private var drawableRightLowerRight: GradientDrawable? = null + private var drawableHorizontalLowerRight: GradientDrawable? = null + private var drawableBTopRight: GradientDrawable? = null + private var drawableBLowerRight: GradientDrawable? = null + private var drawableCTopRight: GradientDrawable? = null + private var drawableCLowerRight: GradientDrawable? = null + private val pathAContentBitmap + get() = pageView.prevPage?.screenshot() + private val pathBContentBitmap //B区域内容Bitmap + get() = pageView.curPage?.screenshot() + private val pathCContentBitmap //C区域内容Bitmap + get() = pageView.nextPage?.screenshot() + + init { + defaultWidth = 600 + defaultHeight = 1000 + a = MyPoint() + f = MyPoint() + g = MyPoint() + e = MyPoint() + h = MyPoint() + c = MyPoint() + j = MyPoint() + b = MyPoint() + k = MyPoint() + d = MyPoint() + i = MyPoint() + pointPaint = Paint() + pointPaint!!.color = Color.RED + pointPaint!!.textSize = 25f + pointPaint!!.style = Paint.Style.STROKE + bgPaint = Paint() + bgPaint!!.color = Color.GREEN + pathAPaint = Paint() + pathAPaint!!.color = Color.GREEN + pathAPaint!!.isAntiAlias = true //设置抗锯齿 + pathBPaint = Paint() + pathBPaint!!.color = Color.GREEN + pathBPaint!!.isAntiAlias = true //设置抗锯齿 + // pathBPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));我们不需要单独绘制path了,记得注释掉 + pathCPaint = Paint() + pathCPaint!!.color = Color.YELLOW + pathCPaint!!.isAntiAlias = true //设置抗锯齿 + // pathCPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)); +// pathCPaint.setStyle(Paint.Style.STROKE); + pathCContentPaint = Paint() + pathCContentPaint!!.color = Color.YELLOW + pathCContentPaint!!.isAntiAlias = true //设置抗锯齿 + textPaint = Paint() + textPaint!!.color = Color.BLACK + textPaint!!.textAlign = Paint.Align.CENTER + textPaint!!.isSubpixelText = true //设置自像素。如果该项为true,将有助于文本在LCD屏幕上的显示效果。 + textPaint!!.textSize = 30f + pathA = Path() + pathB = Path() + pathC = Path() + style = STYLE_LOWER_RIGHT + mMatrix = Matrix() + createGradientDrawable() + } + + private fun drawPathAContentBitmap( + bitmap: Bitmap?, + pathPaint: Paint? + ) { + val mCanvas = Canvas(bitmap!!) + //下面开始绘制区域内的内容... + mCanvas.drawPath(pathDefault!!, pathPaint!!) + mCanvas.drawText( + "这是在A区域的内容...AAAA", + viewWidth - 260.toFloat(), + viewHeight - 100.toFloat(), + textPaint!! + ) + //结束绘制区域内的内容... + } + + private fun drawPathBContentBitmap( + bitmap: Bitmap?, + pathPaint: Paint? + ) { + val mCanvas = Canvas(bitmap!!) + //下面开始绘制区域内的内容... + mCanvas.drawPath(pathDefault!!, pathPaint!!) + mCanvas.drawText( + "这是在B区域的内容...BBBB", + viewWidth - 260.toFloat(), + viewHeight - 100.toFloat(), + textPaint!! + ) + //结束绘制区域内的内容... + } + + + override fun onDraw(canvas: Canvas) { + canvas.drawColor(Color.YELLOW) + if (a!!.x == -1f && a!!.y == -1f) { + drawPathAContent(canvas, pathDefault) + } else { + if (f!!.x == viewWidth.toFloat() && f!!.y == 0f) { + drawPathAContent(canvas, pathAFromTopRight) + drawPathCContent(canvas, pathAFromTopRight) + drawPathBContent(canvas, pathAFromTopRight) + } else if (f!!.x == viewWidth.toFloat() && f!!.y == viewHeight.toFloat()) { + beginTrace("drawPathA") + drawPathAContent(canvas, pathAFromLowerRight) + endTrace() + beginTrace("drawPathC") + drawPathCContent(canvas, pathAFromLowerRight) + endTrace() + beginTrace("drawPathB") + drawPathBContent(canvas, pathAFromLowerRight) + endTrace() + } + } + } + + private fun beginTrace(tag: String) { + Trace.beginSection(tag) + } + + private fun endTrace() { + Trace.endSection() + } + + override fun onScroll() { + if (style == STYLE_TOP_RIGHT) { + setTouchPoint(touchX, touchY, STYLE_TOP_RIGHT) + } else { + setTouchPoint(touchX, touchY, STYLE_LOWER_RIGHT) + } + } + + override fun onTouch(event: MotionEvent): Boolean { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + val x: Float = event.x + val y: Float = event.y + if (x <= viewWidth / 3) { //左 + style = STYLE_LEFT + setTouchPoint(x, y, style) + } else if (x > viewWidth / 3 && y <= viewHeight / 3) { //上 + style = STYLE_TOP_RIGHT + setTouchPoint(x, y, style) + } else if (x > viewWidth * 2 / 3 && y > viewHeight / 3 && y <= viewHeight * 2 / 3) { //右 + style = STYLE_RIGHT + setTouchPoint(x, y, style) + } else if (x > viewWidth / 3 && y > viewHeight * 2 / 3) { //下 + style = STYLE_LOWER_RIGHT + setTouchPoint(x, y, style) + } else if (x > viewWidth / 3 && x < viewWidth * 2 / 3 && y > viewHeight / 3 && y < viewHeight * 2 / 3) { //中 + style = STYLE_MIDDLE + } + } + MotionEvent.ACTION_MOVE -> setTouchPoint(event.x, event.y, style) + MotionEvent.ACTION_UP -> startCancelAnim() + } + return super.onTouch(event) + } + + /** + * 取消翻页动画,计算滑动位置与时间 + */ + fun startCancelAnim() { + val dx: Int + val dy: Int + //让a滑动到f点所在位置,留出1像素是为了防止当a和f重叠时出现View闪烁的情况 + if (style == STYLE_TOP_RIGHT) { + dx = (viewWidth - 1 - a!!.x).toInt() + dy = (1 - a!!.y).toInt() + } else { + dx = (viewWidth - 1 - a!!.x).toInt() + dy = (viewHeight - 1 - a!!.y).toInt() + } + } + + override fun onScrollStart() { + val distanceX: Float + when (direction) { + Direction.NEXT -> distanceX = + if (isCancel) { + var dis = viewWidth - startX + touchX + if (dis > viewWidth) { + dis = viewWidth.toFloat() + } + viewWidth - dis + } else { + -(touchX + (viewWidth - startX)) + } + else -> distanceX = + if (isCancel) { + -(touchX - startX) + } else { + viewWidth - (touchX - startX) + } + } + + startScroll(touchX.toInt(), 0, distanceX.toInt(), 0) + } + + override fun onScrollStop() { + + } + + /** + * 设置触摸点 + * @param x + * @param y + * @param style + */ + fun setTouchPoint(x: Float, y: Float, style: String?) { + val touchPoint: MyPoint + a!!.x = x + a!!.y = y + this.style = style + when (style) { + STYLE_TOP_RIGHT -> { + f!!.x = viewWidth.toFloat() + f!!.y = 0f + calcPointsXY(a, f) + touchPoint = MyPoint(x, y) + if (calcPointCX(touchPoint, f) < 0) { //如果c点x坐标小于0则重新测量a点坐标 + calcPointAByTouchPoint() + calcPointsXY(a, f) + } + pageView.postInvalidate() + } + STYLE_LEFT, STYLE_RIGHT -> { + a!!.y = viewHeight - 1.toFloat() + f!!.x = viewWidth.toFloat() + f!!.y = viewHeight.toFloat() + calcPointsXY(a, f) + pageView.postInvalidate() + } + STYLE_LOWER_RIGHT -> { + f!!.x = viewWidth.toFloat() + f!!.y = viewHeight.toFloat() + calcPointsXY(a, f) + touchPoint = MyPoint(x, y) + if (calcPointCX(touchPoint, f) < 0) { //如果c点x坐标小于0则重新测量a点坐标 + calcPointAByTouchPoint() + calcPointsXY(a, f) + } + pageView.postInvalidate() + } + else -> { + } + } + } + + /** + * 如果c点x坐标小于0,根据触摸点重新测量a点坐标 + */ + private fun calcPointAByTouchPoint() { + val w0 = viewWidth - c!!.x + val w1 = Math.abs(f!!.x - a!!.x) + val w2 = viewWidth * w1 / w0 + a!!.x = Math.abs(f!!.x - w2) + val h1 = Math.abs(f!!.y - a!!.y) + val h2 = w2 * h1 / w1 + a!!.y = Math.abs(f!!.y - h2) + } + + /** + * 回到默认状态 + */ + fun setDefaultPath() { + a!!.x = -1f + a!!.y = -1f + pageView.postInvalidate() + } + + /** + * 初始化各区域阴影GradientDrawable + */ + private fun createGradientDrawable() { + var deepColor = 0x33333333 + var lightColor = 0x01333333 + var gradientColors = intArrayOf(lightColor, deepColor) //渐变颜色数组 + drawableLeftTopRight = + GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, gradientColors) + drawableLeftTopRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT + drawableLeftLowerRight = + GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, gradientColors) + drawableLeftLowerRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT + deepColor = 0x22333333 + lightColor = 0x01333333 + gradientColors = intArrayOf(deepColor, lightColor, lightColor) + drawableRightTopRight = + GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, gradientColors) + drawableRightTopRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT + drawableRightLowerRight = + GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, gradientColors) + drawableRightLowerRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT + deepColor = 0x44333333 + lightColor = 0x01333333 + gradientColors = intArrayOf(lightColor, deepColor) //渐变颜色数组 + drawableHorizontalLowerRight = + GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, gradientColors) + drawableHorizontalLowerRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT + deepColor = 0x55111111 + lightColor = 0x00111111 + gradientColors = intArrayOf(deepColor, lightColor) //渐变颜色数组 + drawableBTopRight = + GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, gradientColors) + drawableBTopRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT //线性渐变 + drawableBLowerRight = + GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, gradientColors) + drawableBLowerRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT + deepColor = 0x55333333 + lightColor = 0x00333333 + gradientColors = intArrayOf(lightColor, deepColor) //渐变颜色数组 + drawableCTopRight = + GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, gradientColors) + drawableCTopRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT + drawableCLowerRight = + GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, gradientColors) + drawableCLowerRight!!.gradientType = GradientDrawable.LINEAR_GRADIENT + } + + /** + * 绘制A区域内容 + * @param canvas + * @param pathA + */ + private fun drawPathAContent( + canvas: Canvas, + pathA: Path? + ) { + canvas.save() + canvas.clipPath(pathA!!, Region.Op.INTERSECT) //对绘制内容进行裁剪,取和A区域的交集 + canvas.drawBitmap(pathAContentBitmap!!, 0f, 0f, null) + if (style == STYLE_LEFT || style == STYLE_RIGHT) { + drawPathAHorizontalShadow(canvas, pathA) + } else { + drawPathALeftShadow(canvas, pathA) + drawPathARightShadow(canvas, pathA) + } + canvas.restore() + } + + /** + * 绘制A区域左阴影 + * @param canvas + */ + private fun drawPathALeftShadow( + canvas: Canvas, + pathA: Path? + ) { + canvas.restore() + canvas.save() + val left: Int + val right: Int + val top = e!!.y.toInt() + val bottom = (e!!.y + viewHeight).toInt() + val gradientDrawable: GradientDrawable? + if (style == STYLE_TOP_RIGHT) { + gradientDrawable = drawableLeftTopRight + left = (e!!.x - lPathAShadowDis / 2).toInt() + right = e!!.x.toInt() + } else { + gradientDrawable = drawableLeftLowerRight + left = e!!.x.toInt() + right = (e!!.x + lPathAShadowDis / 2).toInt() + } + val mPath = Path() + mPath.moveTo(a!!.x - Math.max(rPathAShadowDis, lPathAShadowDis) / 2, a!!.y) + mPath.lineTo(d!!.x, d!!.y) + mPath.lineTo(e!!.x, e!!.y) + mPath.lineTo(a!!.x, a!!.y) + mPath.close() + canvas.clipPath(pathA!!) + canvas.clipPath(mPath, Region.Op.INTERSECT) + val mDegrees = Math.toDegrees( + Math.atan2( + e!!.x - a!!.x.toDouble(), + a!!.y - e!!.y.toDouble() + ) + ).toFloat() + canvas.rotate(mDegrees, e!!.x, e!!.y) + gradientDrawable!!.setBounds(left, top, right, bottom) + gradientDrawable.draw(canvas) + } + + /** + * 绘制A区域右阴影 + * @param canvas + */ + private fun drawPathARightShadow( + canvas: Canvas, + pathA: Path? + ) { + canvas.restore() + canvas.save() + val viewDiagonalLength = Math.hypot( + viewWidth.toDouble(), + viewHeight.toDouble() + ).toFloat() //view对角线长度 + val left = h!!.x.toInt() + val right = (h!!.x + viewDiagonalLength * 10).toInt() //需要足够长的长度 + val top: Int + val bottom: Int + val gradientDrawable: GradientDrawable? + if (style == STYLE_TOP_RIGHT) { + gradientDrawable = drawableRightTopRight + top = (h!!.y - rPathAShadowDis / 2).toInt() + bottom = h!!.y.toInt() + } else { + gradientDrawable = drawableRightLowerRight + top = h!!.y.toInt() + bottom = (h!!.y + rPathAShadowDis / 2).toInt() + } + gradientDrawable!!.setBounds(left, top, right, bottom) + val mPath = Path() + mPath.moveTo(a!!.x - Math.max(rPathAShadowDis, lPathAShadowDis) / 2, a!!.y) + // mPath.lineTo(i.x,i.y); + mPath.lineTo(h!!.x, h!!.y) + mPath.lineTo(a!!.x, a!!.y) + mPath.close() + canvas.clipPath(pathA!!) + canvas.clipPath(mPath, Region.Op.INTERSECT) + val mDegrees = Math.toDegrees( + Math.atan2( + a!!.y - h!!.y.toDouble(), + a!!.x - h!!.x.toDouble() + ) + ).toFloat() + canvas.rotate(mDegrees, h!!.x, h!!.y) + gradientDrawable.draw(canvas) + } + + /** + * 绘制A区域水平翻页阴影 + * @param canvas + */ + private fun drawPathAHorizontalShadow( + canvas: Canvas, + pathA: Path? + ) { + canvas.restore() + canvas.save() + canvas.clipPath(pathA!!, Region.Op.INTERSECT) + val maxShadowWidth = 30 //阴影矩形最大的宽度 + val left = + (a!!.x - Math.min(maxShadowWidth.toFloat(), rPathAShadowDis / 2)).toInt() + val right = a!!.x.toInt() + val top = 0 + val bottom = viewHeight + val gradientDrawable = drawableHorizontalLowerRight + gradientDrawable!!.setBounds(left, top, right, bottom) + val mDegrees = Math.toDegrees( + Math.atan2( + f!!.x - a!!.x.toDouble(), + f!!.y - h!!.y.toDouble() + ) + ).toFloat() + canvas.rotate(mDegrees, a!!.x, a!!.y) + gradientDrawable.draw(canvas) + } + + /** + * 绘制默认的界面 + * @return + */ + private val pathDefault: Path? + private get() { + pathA!!.reset() + pathA!!.lineTo(0f, viewHeight.toFloat()) + pathA!!.lineTo(viewWidth.toFloat(), viewHeight.toFloat()) + pathA!!.lineTo(viewWidth.toFloat(), 0f) + pathA!!.close() + return pathA + }//移动到c点 + //从c到b画贝塞尔曲线,控制点为e + //移动到a点 + //移动到k点 + //从k到j画贝塞尔曲线,控制点为h + //移动到右下角 + //移动到左下角 + + /** + * 获取f点在右上角的pathA + * @return + */ + private val pathAFromTopRight: Path? + private get() { + pathA!!.reset() + pathA!!.lineTo(c!!.x, c!!.y) //移动到c点 + pathA!!.quadTo(e!!.x, e!!.y, b!!.x, b!!.y) //从c到b画贝塞尔曲线,控制点为e + pathA!!.lineTo(a!!.x, a!!.y) //移动到a点 + pathA!!.lineTo(k!!.x, k!!.y) //移动到k点 + pathA!!.quadTo(h!!.x, h!!.y, j!!.x, j!!.y) //从k到j画贝塞尔曲线,控制点为h + pathA!!.lineTo(viewWidth.toFloat(), viewHeight.toFloat()) //移动到右下角 + pathA!!.lineTo(0f, viewHeight.toFloat()) //移动到左下角 + pathA!!.close() + return pathA + }//移动到左下角 + //移动到c点 + //从c到b画贝塞尔曲线,控制点为e + //移动到a点 + //移动到k点 + //从k到j画贝塞尔曲线,控制点为h + //移动到右上角 + //闭合区域 + + /** + * 获取f点在右下角的pathA + * @return + */ + private val pathAFromLowerRight: Path? + private get() { + pathA!!.reset() + pathA!!.lineTo(0f, viewHeight.toFloat()) //移动到左下角 + pathA!!.lineTo(c!!.x, c!!.y) //移动到c点 + pathA!!.quadTo(e!!.x, e!!.y, b!!.x, b!!.y) //从c到b画贝塞尔曲线,控制点为e + pathA!!.lineTo(a!!.x, a!!.y) //移动到a点 + pathA!!.lineTo(k!!.x, k!!.y) //移动到k点 + pathA!!.quadTo(h!!.x, h!!.y, j!!.x, j!!.y) //从k到j画贝塞尔曲线,控制点为h + pathA!!.lineTo(viewWidth.toFloat(), 0f) //移动到右上角 + pathA!!.close() //闭合区域 + return pathA + } + + /** + * 绘制B区域内容 + * @param canvas + * @param pathA + */ + private fun drawPathBContent( + canvas: Canvas, + pathA: Path? + ) { + canvas.save() + canvas.clipPath(pathA!!) //裁剪出A区域 + canvas.clipPath(getPathC()!!, Region.Op.INTERSECT) //裁剪出A和C区域的全集 + canvas.clipPath( + getPathB()!!, + Region.Op.DIFFERENCE + ) //裁剪出B区域中不同于与AC区域的部分 + canvas.drawBitmap(pathBContentBitmap!!, 0f, 0f, null) + drawPathBShadow(canvas) + canvas.restore() + } + + /** + * 绘制B区域阴影,阴影左深右浅 + * @param canvas + */ + private fun drawPathBShadow(canvas: Canvas) { + val deepOffset = 0 //深色端的偏移值 + val lightOffset = 0 //浅色端的偏移值 + val aTof = Math.hypot( + (a!!.x - f!!.x).toDouble(), + (a!!.y - f!!.y).toDouble() + ).toFloat() //a到f的距离 + val viewDiagonalLength = Math.hypot( + viewWidth.toDouble(), + viewHeight.toDouble() + ).toFloat() //对角线长度 + val left: Int + val right: Int + val top = c!!.y.toInt() + val bottom = (viewDiagonalLength + c!!.y).toInt() + val gradientDrawable: GradientDrawable? + if (style == STYLE_TOP_RIGHT) { //f点在右上角 +//从左向右线性渐变 + gradientDrawable = drawableBTopRight + left = (c!!.x - deepOffset).toInt() //c点位于左上角 + right = (c!!.x + aTof / 4 + lightOffset).toInt() + } else { //从右向左线性渐变 + gradientDrawable = drawableBLowerRight + left = (c!!.x - aTof / 4 - lightOffset).toInt() //c点位于左下角 + right = (c!!.x + deepOffset).toInt() + } + gradientDrawable!!.setBounds(left, top, right, bottom) //设置阴影矩形 + val rotateDegrees = Math.toDegrees( + Math.atan2( + e!!.x - f!!.x.toDouble(), + h!!.y - f!!.y.toDouble() + ) + ).toFloat() //旋转角度 + canvas.rotate(rotateDegrees, c!!.x, c!!.y) //以c为中心点旋转 + gradientDrawable.draw(canvas) + } + + /** + * 绘制区域B + * @return + */ + private fun getPathB(): Path? { + pathB!!.reset() + pathB!!.lineTo(0f, viewHeight.toFloat()) //移动到左下角 + pathB!!.lineTo(viewWidth.toFloat(), viewHeight.toFloat()) //移动到右下角 + pathB!!.lineTo(viewWidth.toFloat(), 0f) //移动到右上角 + pathB!!.close() //闭合区域 + return pathB + } + + /** + * 绘制C区域内容 + * @param canvas + * @param pathA + */ + private fun drawPathCContent( + canvas: Canvas, + pathA: Path? + ) { + canvas.save() + canvas.clipPath(pathA!!) + canvas.clipPath(getPathC()!!, Region.Op.DIFFERENCE) //裁剪出C区域不同于A区域的部分 + // canvas.drawPath(getPathC(),pathCPaint); + val eh = + hypot(f!!.x - e!!.x.toDouble(), h!!.y - f!!.y.toDouble()).toFloat() + val sin0 = (f!!.x - e!!.x) / eh + val cos0 = (h!!.y - f!!.y) / eh + //设置翻转和旋转矩阵 + mMatrixArray[0] = -(1 - 2 * sin0 * sin0) + mMatrixArray[1] = 2 * sin0 * cos0 + mMatrixArray[3] = 2 * sin0 * cos0 + mMatrixArray[4] = 1 - 2 * sin0 * sin0 + mMatrix!!.reset() + mMatrix!!.setValues(mMatrixArray) //翻转和旋转 + mMatrix!!.preTranslate(-e!!.x, -e!!.y) //沿当前XY轴负方向位移得到 矩形A₃B₃C₃D₃ + mMatrix!!.postTranslate(e!!.x, e!!.y) //沿原XY轴方向位移得到 矩形A4 B4 C4 D4 + canvas.drawBitmap(pathCContentBitmap!!, mMatrix!!, null) + drawPathCShadow(canvas) + canvas.restore() + } + + /** + * 绘制C区域阴影,阴影左浅右深 + * @param canvas + */ + private fun drawPathCShadow(canvas: Canvas) { + val deepOffset = 1 //深色端的偏移值 + val lightOffset = -30 //浅色端的偏移值 + val viewDiagonalLength = Math.hypot( + viewWidth.toDouble(), + viewHeight.toDouble() + ).toFloat() //view对角线长度 + val midpoint_ce = (c!!.x + e!!.x).toInt() / 2 //ce中点 + val midpoint_jh = (j!!.y + h!!.y).toInt() / 2 //jh中点 + val minDisToControlPoint = Math.min( + Math.abs(midpoint_ce - e!!.x), + Math.abs(midpoint_jh - h!!.y) + ) //中点到控制点的最小值 + val left: Int + val right: Int + val top = c!!.y.toInt() + val bottom = (viewDiagonalLength + c!!.y).toInt() + val gradientDrawable: GradientDrawable? + if (style == STYLE_TOP_RIGHT) { + gradientDrawable = drawableCTopRight + left = (c!!.x - lightOffset).toInt() + right = (c!!.x + minDisToControlPoint + deepOffset).toInt() + } else { + gradientDrawable = drawableCLowerRight + left = (c!!.x - minDisToControlPoint - deepOffset).toInt() + right = (c!!.x + lightOffset).toInt() + } + gradientDrawable!!.setBounds(left, top, right, bottom) + val mDegrees = Math.toDegrees( + Math.atan2( + e!!.x - f!!.x.toDouble(), + h!!.y - f!!.y.toDouble() + ) + ).toFloat() + canvas.rotate(mDegrees, c!!.x, c!!.y) + gradientDrawable.draw(canvas) + } + + /** + * 绘制区域C + * @return + */ + private fun getPathC(): Path? { + pathC!!.reset() + pathC!!.moveTo(i!!.x, i!!.y) //移动到i点 + pathC!!.lineTo(d!!.x, d!!.y) //移动到d点 + pathC!!.lineTo(b!!.x, b!!.y) //移动到b点 + pathC!!.lineTo(a!!.x, a!!.y) //移动到a点 + pathC!!.lineTo(k!!.x, k!!.y) //移动到k点 + pathC!!.close() //闭合区域 + return pathC + } + + /** + * 计算各点坐标 + * @param a + * @param f + */ + private fun calcPointsXY(a: MyPoint?, f: MyPoint?) { + g!!.x = (a!!.x + f!!.x) / 2 + g!!.y = (a.y + f.y) / 2 + e!!.x = g!!.x - (f.y - g!!.y) * (f.y - g!!.y) / (f.x - g!!.x) + e!!.y = f.y + h!!.x = f.x + h!!.y = g!!.y - (f.x - g!!.x) * (f.x - g!!.x) / (f.y - g!!.y) + c!!.x = e!!.x - (f.x - e!!.x) / 2 + c!!.y = f.y + j!!.x = f.x + j!!.y = h!!.y - (f.y - h!!.y) / 2 + b = getIntersectionPoint(a, e, c, j) + k = getIntersectionPoint(a, h, c, j) + d!!.x = (c!!.x + 2 * e!!.x + b!!.x) / 4 + d!!.y = (2 * e!!.y + c!!.y + b!!.y) / 4 + i!!.x = (j!!.x + 2 * h!!.x + k!!.x) / 4 + i!!.y = (2 * h!!.y + j!!.y + k!!.y) / 4 + //计算d点到ae的距离 + val lA = a.y - e!!.y + val lB = e!!.x - a.x + val lC = a.x * e!!.y - e!!.x * a.y + lPathAShadowDis = Math.abs( + (lA * d!!.x + lB * d!!.y + lC) / Math.hypot( + lA.toDouble(), + lB.toDouble() + ).toFloat() + ) + //计算i点到ah的距离 + val rA = a.y - h!!.y + val rB = h!!.x - a.x + val rC = a.x * h!!.y - h!!.x * a.y + rPathAShadowDis = Math.abs( + (rA * i!!.x + rB * i!!.y + rC) / Math.hypot( + rA.toDouble(), + rB.toDouble() + ).toFloat() + ) + } + + /** + * 计算两线段相交点坐标 + * @param lineOne_My_pointOne + * @param lineOne_My_pointTwo + * @param lineTwo_My_pointOne + * @param lineTwo_My_pointTwo + * @return 返回该点 + */ + private fun getIntersectionPoint( + lineOne_My_pointOne: MyPoint?, + lineOne_My_pointTwo: MyPoint?, + lineTwo_My_pointOne: MyPoint?, + lineTwo_My_pointTwo: MyPoint? + ): MyPoint { + val x1: Float + val y1: Float + val x2: Float + val y2: Float + val x3: Float + val y3: Float + val x4: Float + val y4: Float + x1 = lineOne_My_pointOne!!.x + y1 = lineOne_My_pointOne.y + x2 = lineOne_My_pointTwo!!.x + y2 = lineOne_My_pointTwo.y + x3 = lineTwo_My_pointOne!!.x + y3 = lineTwo_My_pointOne.y + x4 = lineTwo_My_pointTwo!!.x + y4 = lineTwo_My_pointTwo.y + val pointX = + (((x1 - x2) * (x3 * y4 - x4 * y3) - (x3 - x4) * (x1 * y2 - x2 * y1)) + / ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4))) + val pointY = + (((y1 - y2) * (x3 * y4 - x4 * y3) - (x1 * y2 - x2 * y1) * (y3 - y4)) + / ((y1 - y2) * (x3 - x4) - (x1 - x2) * (y3 - y4))) + return MyPoint(pointX, pointY) + } + + /** + * 计算C点的X值 + * @param a + * @param f + * @return + */ + private fun calcPointCX(a: MyPoint, f: MyPoint?): Float { + val g: MyPoint + val e: MyPoint + g = MyPoint() + e = MyPoint() + g.x = (a.x + f!!.x) / 2 + g.y = (a.y + f.y) / 2 + e.x = g.x - (f.y - g.y) * (f.y - g.y) / (f.x - g.x) + e.y = f.y + return e.x - (f.x - e.x) / 2 + } + + fun getViewWidth(): Float { + return viewWidth.toFloat() + } + + fun getViewHeight(): Float { + return viewHeight.toFloat() + } + + internal inner class MyPoint { + var x = 0f + var y = 0f + + constructor() {} + constructor(x: Float, y: Float) { + this.x = x + this.y = y + } + } + + companion object { + const val STYLE_LEFT = "STYLE_LEFT" //点击左边区域 + const val STYLE_RIGHT = "STYLE_RIGHT" //点击右边区域 + const val STYLE_MIDDLE = "STYLE_MIDDLE" //点击中间区域 + const val STYLE_TOP_RIGHT = "STYLE_TOP_RIGHT" //f点在右上角 + const val STYLE_LOWER_RIGHT = "STYLE_LOWER_RIGHT" //f点在右下角 + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_padding.xml b/app/src/main/res/layout/dialog_read_padding.xml index 10f2cd8aa..a127e6520 100644 --- a/app/src/main/res/layout/dialog_read_padding.xml +++ b/app/src/main/res/layout/dialog_read_padding.xml @@ -35,4 +35,68 @@ app:title="@string/padding_right" app:max="100" /> + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_detail_seek_bar.xml b/app/src/main/res/layout/view_detail_seek_bar.xml index 8b04a9265..12aa4f45f 100644 --- a/app/src/main/res/layout/view_detail_seek_bar.xml +++ b/app/src/main/res/layout/view_detail_seek_bar.xml @@ -1,8 +1,8 @@ @@ -43,6 +43,7 @@ android:layout_height="wrap_content" android:gravity="right" android:singleLine="true" - tools:ignore="RtlHardcoded" /> + android:text="0" + tools:ignore="HardcodedText,RtlHardcoded" /> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2bfe28e42..18cc9ef42 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -284,6 +284,14 @@ 下边距 左边距 右边距 + 页眉上 + 页眉下 + 页眉左 + 页眉右 + 页脚上 + 页脚下 + 页脚左 + 页脚右 校验书源 校验所选 进度 %d/%d