kunfei vor 4 Jahren
Ursprung
Commit
2413ed4876

+ 2 - 2
app/src/main/java/io/legado/app/ui/widget/code/CodeView.kt

@@ -13,7 +13,7 @@ import android.text.style.ForegroundColorSpan
 import android.text.style.ReplacementSpan
 import android.text.style.ReplacementSpan
 import android.util.AttributeSet
 import android.util.AttributeSet
 import androidx.annotation.ColorInt
 import androidx.annotation.ColorInt
-import io.legado.app.ui.widget.text.NestScrollMultiAutoCompleteTextView
+import io.legado.app.ui.widget.text.ScrollMultiAutoCompleteTextView
 import java.util.*
 import java.util.*
 import java.util.regex.Matcher
 import java.util.regex.Matcher
 import java.util.regex.Pattern
 import java.util.regex.Pattern
@@ -21,7 +21,7 @@ import kotlin.math.roundToInt
 
 
 @Suppress("unused")
 @Suppress("unused")
 class CodeView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
 class CodeView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
-    NestScrollMultiAutoCompleteTextView(context, attrs) {
+    ScrollMultiAutoCompleteTextView(context, attrs) {
 
 
     private var tabWidth = 0
     private var tabWidth = 0
     private var tabWidthInCharacters = 0
     private var tabWidthInCharacters = 0

+ 0 - 105
app/src/main/java/io/legado/app/ui/widget/text/NestScrollMultiAutoCompleteTextView.kt

@@ -1,105 +0,0 @@
-package io.legado.app.ui.widget.text
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.util.AttributeSet
-import android.view.GestureDetector
-import android.view.MotionEvent
-import androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView
-
-/**
- * 嵌套滚动 MultiAutoCompleteTextView
- */
-open class NestScrollMultiAutoCompleteTextView @JvmOverloads constructor(
-    context: Context,
-    attrs: AttributeSet? = null
-) : AppCompatMultiAutoCompleteTextView(context, attrs) {
-
-    //是否到顶或者到底的标志
-    private var disallowIntercept = true
-
-    //滑动距离的最大边界
-    private var mOffsetHeight = 0
-
-    private val gestureDetector = GestureDetector(context,
-        object : GestureDetector.SimpleOnGestureListener() {
-
-            override fun onDown(e: MotionEvent): Boolean {
-                disallowIntercept = true
-                return super.onDown(e)
-            }
-
-            override fun onScroll(
-                e1: MotionEvent,
-                e2: MotionEvent,
-                distanceX: Float,
-                distanceY: Float
-            ): Boolean {
-                val y = scrollY + distanceY
-                if (y < 0 || y > mOffsetHeight) {
-                    disallowIntercept = false
-                    //这里触发父布局或祖父布局的滑动事件
-                    parent.requestDisallowInterceptTouchEvent(false)
-                } else {
-                    disallowIntercept = true
-                }
-                return true
-            }
-
-        })
-
-    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
-        initOffsetHeight()
-    }
-
-    override fun onTextChanged(
-        text: CharSequence,
-        start: Int,
-        lengthBefore: Int,
-        lengthAfter: Int
-    ) {
-        super.onTextChanged(text, start, lengthBefore, lengthAfter)
-        initOffsetHeight()
-    }
-
-    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
-        if (lineCount > maxLines) {
-            gestureDetector.onTouchEvent(event)
-        }
-        return super.dispatchTouchEvent(event)
-    }
-
-    @SuppressLint("ClickableViewAccessibility")
-    override fun onTouchEvent(event: MotionEvent): Boolean {
-        val result = super.onTouchEvent(event)
-        //如果是需要拦截,则再拦截,这个方法会在onScrollChanged方法之后再调用一次
-        if (disallowIntercept && lineCount > maxLines) {
-            parent.requestDisallowInterceptTouchEvent(true)
-        }
-        return result
-    }
-
-    private fun initOffsetHeight() {
-        val mLayoutHeight: Int
-
-        //获得内容面板
-        val mLayout = layout ?: return
-        //获得内容面板的高度
-        mLayoutHeight = mLayout.height
-        //获取上内边距
-        val paddingTop: Int = totalPaddingTop
-        //获取下内边距
-        val paddingBottom: Int = totalPaddingBottom
-
-        //获得控件的实际高度
-        val mHeight: Int = measuredHeight
-
-        //计算滑动距离的边界
-        mOffsetHeight = mLayoutHeight + paddingTop + paddingBottom - mHeight
-        if (mOffsetHeight <= 0) {
-            scrollTo(0, 0)
-        }
-    }
-
-}

+ 0 - 82
app/src/main/java/io/legado/app/ui/widget/text/NestScrollTextView.kt

@@ -1,82 +0,0 @@
-package io.legado.app.ui.widget.text
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.util.AttributeSet
-import android.view.MotionEvent
-import androidx.appcompat.widget.AppCompatTextView
-
-
-/**
- * 嵌套滚动 TextView
- */
-class NestScrollTextView(context: Context, attrs: AttributeSet?) :
-    AppCompatTextView(context, attrs) {
-    //滑动距离的最大边界
-    private var mOffsetHeight = 0
-
-    //是否到顶或者到底的标志
-    private var mBottomFlag = false
-
-    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
-        initOffsetHeight()
-    }
-
-    override fun onTextChanged(
-        text: CharSequence,
-        start: Int,
-        lengthBefore: Int,
-        lengthAfter: Int
-    ) {
-        super.onTextChanged(text, start, lengthBefore, lengthAfter)
-        initOffsetHeight()
-    }
-
-    private fun initOffsetHeight() {
-        val mLayoutHeight: Int
-
-        //获得内容面板
-        val mLayout = layout ?: return
-        //获得内容面板的高度
-        mLayoutHeight = mLayout.height
-        //获取上内边距
-        val paddingTop: Int = totalPaddingTop
-        //获取下内边距
-        val paddingBottom: Int = totalPaddingBottom
-
-        //获得控件的实际高度
-        val mHeight: Int = measuredHeight
-
-        //计算滑动距离的边界
-        mOffsetHeight = mLayoutHeight + paddingTop + paddingBottom - mHeight
-        if (mOffsetHeight <= 0) {
-            scrollTo(0, 0)
-        }
-    }
-
-    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
-        if (event.action == MotionEvent.ACTION_DOWN) {
-            //如果是新的按下事件,则对mBottomFlag重新初始化
-            mBottomFlag = mOffsetHeight <= 0
-        }
-        return super.dispatchTouchEvent(event)
-    }
-
-    @SuppressLint("ClickableViewAccessibility")
-    override fun onTouchEvent(event: MotionEvent): Boolean {
-        val result = super.onTouchEvent(event)
-        //如果是需要拦截,则再拦截,这个方法会在onScrollChanged方法之后再调用一次
-        if (!mBottomFlag) parent.requestDisallowInterceptTouchEvent(true)
-        return result
-    }
-
-    override fun onScrollChanged(horiz: Int, vert: Int, oldHoriz: Int, oldVert: Int) {
-        super.onScrollChanged(horiz, vert, oldHoriz, oldVert)
-        if (vert == mOffsetHeight || vert == 0) {
-            //这里触发父布局或祖父布局的滑动事件
-            parent.requestDisallowInterceptTouchEvent(false)
-            mBottomFlag = true
-        }
-    }
-}

+ 272 - 0
app/src/main/java/io/legado/app/ui/widget/text/ScrollMultiAutoCompleteTextView.kt

@@ -0,0 +1,272 @@
+package io.legado.app.ui.widget.text
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.text.method.LinkMovementMethod
+import android.util.AttributeSet
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.view.VelocityTracker
+import android.view.ViewConfiguration
+import android.view.animation.Interpolator
+import android.widget.OverScroller
+import androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView
+import androidx.core.view.ViewCompat
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * 嵌套滚动 MultiAutoCompleteTextView
+ */
+open class ScrollMultiAutoCompleteTextView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null
+) : AppCompatMultiAutoCompleteTextView(context, attrs) {
+
+    //是否到顶或者到底的标志
+    private var disallowIntercept = true
+
+    private val scrollStateIdle = 0
+    private val scrollStateDragging = 1
+    val scrollStateSettling = 2
+
+    private val mViewFling: ViewFling by lazy { ViewFling() }
+    private val velocityTracker: VelocityTracker by lazy { VelocityTracker.obtain() }
+    private var mScrollState = scrollStateIdle
+    private var mLastTouchY: Int = 0
+    private var mTouchSlop: Int = 0
+    private var mMinFlingVelocity: Int = 0
+    private var mMaxFlingVelocity: Int = 0
+
+    //滑动距离的最大边界
+    private var mOffsetHeight: Int = 0
+
+    //f(x) = (x-1)^5 + 1
+    private val sQuinticInterpolator = Interpolator {
+        var t = it
+        t -= 1.0f
+        t * t * t * t * t + 1.0f
+    }
+
+    private val gestureDetector = GestureDetector(context,
+        object : GestureDetector.SimpleOnGestureListener() {
+
+            override fun onDown(e: MotionEvent): Boolean {
+                disallowIntercept = true
+                return super.onDown(e)
+            }
+
+            override fun onScroll(
+                e1: MotionEvent,
+                e2: MotionEvent,
+                distanceX: Float,
+                distanceY: Float
+            ): Boolean {
+                val y = scrollY + distanceY
+                if (y < 0 || y > mOffsetHeight) {
+                    disallowIntercept = false
+                    //这里触发父布局或祖父布局的滑动事件
+                    parent.requestDisallowInterceptTouchEvent(false)
+                } else {
+                    disallowIntercept = true
+                }
+                return true
+            }
+
+        })
+
+    init {
+        val vc = ViewConfiguration.get(context)
+        mTouchSlop = vc.scaledTouchSlop
+        mMinFlingVelocity = vc.scaledMinimumFlingVelocity
+        mMaxFlingVelocity = vc.scaledMaximumFlingVelocity
+        movementMethod = LinkMovementMethod.getInstance()
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        initOffsetHeight()
+    }
+
+    override fun onTextChanged(
+        text: CharSequence,
+        start: Int,
+        lengthBefore: Int,
+        lengthAfter: Int
+    ) {
+        super.onTextChanged(text, start, lengthBefore, lengthAfter)
+        initOffsetHeight()
+    }
+
+    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
+        if (lineCount > maxLines) {
+            gestureDetector.onTouchEvent(event)
+        }
+        velocityTracker.addMovement(event)
+        when (event.action) {
+            MotionEvent.ACTION_DOWN -> {
+                setScrollState(scrollStateIdle)
+                mLastTouchY = (event.y + 0.5f).toInt()
+            }
+            MotionEvent.ACTION_MOVE -> {
+                val y = (event.y + 0.5f).toInt()
+                var dy = mLastTouchY - y
+                if (mScrollState != scrollStateDragging) {
+                    var startScroll = false
+
+                    if (abs(dy) > mTouchSlop) {
+                        if (dy > 0) {
+                            dy -= mTouchSlop
+                        } else {
+                            dy += mTouchSlop
+                        }
+                        startScroll = true
+                    }
+                    if (startScroll) {
+                        setScrollState(scrollStateDragging)
+                    }
+                }
+                if (mScrollState == scrollStateDragging) {
+                    mLastTouchY = y
+                }
+            }
+            MotionEvent.ACTION_UP -> {
+                velocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity.toFloat())
+                val yVelocity = velocityTracker.yVelocity
+                if (abs(yVelocity) > mMinFlingVelocity) {
+                    mViewFling.fling(-yVelocity.toInt())
+                } else {
+                    setScrollState(scrollStateIdle)
+                }
+                resetTouch()
+            }
+            MotionEvent.ACTION_CANCEL -> {
+                resetTouch()
+            }
+        }
+        return super.dispatchTouchEvent(event)
+    }
+
+    @SuppressLint("ClickableViewAccessibility")
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        val result = super.onTouchEvent(event)
+        //如果是需要拦截,则再拦截,这个方法会在onScrollChanged方法之后再调用一次
+        if (disallowIntercept && lineCount > maxLines) {
+            parent.requestDisallowInterceptTouchEvent(true)
+        }
+
+        return result
+    }
+
+    override fun scrollTo(x: Int, y: Int) {
+        super.scrollTo(x, min(y, mOffsetHeight))
+    }
+
+    private fun initOffsetHeight() {
+        val mLayoutHeight: Int
+
+        //获得内容面板
+        val mLayout = layout ?: return
+        //获得内容面板的高度
+        mLayoutHeight = mLayout.height
+        //获取上内边距
+        val paddingTop: Int = totalPaddingTop
+        //获取下内边距
+        val paddingBottom: Int = totalPaddingBottom
+
+        //获得控件的实际高度
+        val mHeight: Int = measuredHeight
+
+        //计算滑动距离的边界
+        mOffsetHeight = mLayoutHeight + paddingTop + paddingBottom - mHeight
+        if (mOffsetHeight <= 0) {
+            scrollTo(0, 0)
+        }
+    }
+
+    private fun resetTouch() {
+        velocityTracker.clear()
+    }
+
+    private fun setScrollState(state: Int) {
+        if (state == mScrollState) {
+            return
+        }
+        mScrollState = state
+        if (state != scrollStateSettling) {
+            mViewFling.stop()
+        }
+    }
+
+    /**
+     * 惯性滚动
+     */
+    private inner class ViewFling : Runnable {
+
+        private var mLastFlingY = 0
+        private val mScroller: OverScroller = OverScroller(context, sQuinticInterpolator)
+        private var mEatRunOnAnimationRequest = false
+        private var mReSchedulePostAnimationCallback = false
+
+        override fun run() {
+            disableRunOnAnimationRequests()
+            val scroller = mScroller
+            if (scroller.computeScrollOffset()) {
+                val y = scroller.currY
+                val dy = y - mLastFlingY
+                mLastFlingY = y
+                if (dy < 0 && scrollY > 0) {
+                    scrollBy(0, max(dy, -scrollY))
+                } else if (dy > 0 && scrollY < mOffsetHeight) {
+                    scrollBy(0, min(dy, mOffsetHeight - scrollY))
+                }
+                postOnAnimation()
+            }
+            enableRunOnAnimationRequests()
+        }
+
+        fun fling(velocityY: Int) {
+            mLastFlingY = 0
+            setScrollState(scrollStateSettling)
+            mScroller.fling(
+                0,
+                0,
+                0,
+                velocityY,
+                Integer.MIN_VALUE,
+                Integer.MAX_VALUE,
+                Integer.MIN_VALUE,
+                Integer.MAX_VALUE
+            )
+            postOnAnimation()
+        }
+
+        fun stop() {
+            removeCallbacks(this)
+            mScroller.abortAnimation()
+        }
+
+        private fun disableRunOnAnimationRequests() {
+            mReSchedulePostAnimationCallback = false
+            mEatRunOnAnimationRequest = true
+        }
+
+        private fun enableRunOnAnimationRequests() {
+            mEatRunOnAnimationRequest = false
+            if (mReSchedulePostAnimationCallback) {
+                postOnAnimation()
+            }
+        }
+
+        fun postOnAnimation() {
+            if (mEatRunOnAnimationRequest) {
+                mReSchedulePostAnimationCallback = true
+            } else {
+                removeCallbacks(this)
+                ViewCompat.postOnAnimation(this@ScrollMultiAutoCompleteTextView, this)
+            }
+        }
+    }
+
+}

+ 113 - 74
app/src/main/java/io/legado/app/ui/widget/text/InertiaScrollTextView.kt → app/src/main/java/io/legado/app/ui/widget/text/ScrollTextView.kt

@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Context
 import android.text.method.LinkMovementMethod
 import android.text.method.LinkMovementMethod
 import android.util.AttributeSet
 import android.util.AttributeSet
+import android.view.GestureDetector
 import android.view.MotionEvent
 import android.view.MotionEvent
 import android.view.VelocityTracker
 import android.view.VelocityTracker
 import android.view.ViewConfiguration
 import android.view.ViewConfiguration
@@ -15,21 +16,22 @@ import kotlin.math.abs
 import kotlin.math.max
 import kotlin.math.max
 import kotlin.math.min
 import kotlin.math.min
 
 
+
 /**
 /**
- * 惯性滚动 TextView
+ * 嵌套滚动 TextView
  */
  */
-@Suppress("unused")
-open class InertiaScrollTextView @JvmOverloads constructor(
-    context: Context,
-    attrs: AttributeSet? = null
-) : AppCompatTextView(context, attrs) {
+class ScrollTextView(context: Context, attrs: AttributeSet?) :
+    AppCompatTextView(context, attrs) {
+
+    //是否到顶或者到底的标志
+    private var disallowIntercept = true
 
 
     private val scrollStateIdle = 0
     private val scrollStateIdle = 0
     private val scrollStateDragging = 1
     private val scrollStateDragging = 1
     val scrollStateSettling = 2
     val scrollStateSettling = 2
 
 
     private val mViewFling: ViewFling by lazy { ViewFling() }
     private val mViewFling: ViewFling by lazy { ViewFling() }
-    private var velocityTracker: VelocityTracker? = null
+    private val velocityTracker: VelocityTracker by lazy { VelocityTracker.obtain() }
     private var mScrollState = scrollStateIdle
     private var mScrollState = scrollStateIdle
     private var mLastTouchY: Int = 0
     private var mLastTouchY: Int = 0
     private var mTouchSlop: Int = 0
     private var mTouchSlop: Int = 0
@@ -46,6 +48,33 @@ open class InertiaScrollTextView @JvmOverloads constructor(
         t * t * t * t * t + 1.0f
         t * t * t * t * t + 1.0f
     }
     }
 
 
+    private val gestureDetector = GestureDetector(context,
+        object : GestureDetector.SimpleOnGestureListener() {
+
+            override fun onDown(e: MotionEvent): Boolean {
+                disallowIntercept = true
+                return super.onDown(e)
+            }
+
+            override fun onScroll(
+                e1: MotionEvent,
+                e2: MotionEvent,
+                distanceX: Float,
+                distanceY: Float
+            ): Boolean {
+                val y = scrollY + distanceY
+                if (y < 0 || y > mOffsetHeight) {
+                    disallowIntercept = false
+                    //这里触发父布局或祖父布局的滑动事件
+                    parent.requestDisallowInterceptTouchEvent(false)
+                } else {
+                    disallowIntercept = true
+                }
+                return true
+            }
+
+        })
+
     init {
     init {
         val vc = ViewConfiguration.get(context)
         val vc = ViewConfiguration.get(context)
         mTouchSlop = vc.scaledTouchSlop
         mTouchSlop = vc.scaledTouchSlop
@@ -54,21 +83,13 @@ open class InertiaScrollTextView @JvmOverloads constructor(
         movementMethod = LinkMovementMethod.getInstance()
         movementMethod = LinkMovementMethod.getInstance()
     }
     }
 
 
-    fun atTop(): Boolean {
-        return scrollY <= 0
-    }
-
-    fun atBottom(): Boolean {
-        return scrollY >= mOffsetHeight
-    }
-
     override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
     override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec)
         super.onMeasure(widthMeasureSpec, heightMeasureSpec)
         initOffsetHeight()
         initOffsetHeight()
     }
     }
 
 
     override fun onTextChanged(
     override fun onTextChanged(
-        text: CharSequence?,
+        text: CharSequence,
         start: Int,
         start: Int,
         lengthBefore: Int,
         lengthBefore: Int,
         lengthAfter: Int
         lengthAfter: Int
@@ -77,6 +98,70 @@ open class InertiaScrollTextView @JvmOverloads constructor(
         initOffsetHeight()
         initOffsetHeight()
     }
     }
 
 
+    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
+        if (lineCount > maxLines) {
+            gestureDetector.onTouchEvent(event)
+        }
+        velocityTracker.addMovement(event)
+        when (event.action) {
+            MotionEvent.ACTION_DOWN -> {
+                setScrollState(scrollStateIdle)
+                mLastTouchY = (event.y + 0.5f).toInt()
+            }
+            MotionEvent.ACTION_MOVE -> {
+                val y = (event.y + 0.5f).toInt()
+                var dy = mLastTouchY - y
+                if (mScrollState != scrollStateDragging) {
+                    var startScroll = false
+
+                    if (abs(dy) > mTouchSlop) {
+                        if (dy > 0) {
+                            dy -= mTouchSlop
+                        } else {
+                            dy += mTouchSlop
+                        }
+                        startScroll = true
+                    }
+                    if (startScroll) {
+                        setScrollState(scrollStateDragging)
+                    }
+                }
+                if (mScrollState == scrollStateDragging) {
+                    mLastTouchY = y
+                }
+            }
+            MotionEvent.ACTION_UP -> {
+                velocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity.toFloat())
+                val yVelocity = velocityTracker.yVelocity
+                if (abs(yVelocity) > mMinFlingVelocity) {
+                    mViewFling.fling(-yVelocity.toInt())
+                } else {
+                    setScrollState(scrollStateIdle)
+                }
+                resetTouch()
+            }
+            MotionEvent.ACTION_CANCEL -> {
+                resetTouch()
+            }
+        }
+        return super.dispatchTouchEvent(event)
+    }
+
+    @SuppressLint("ClickableViewAccessibility")
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        val result = super.onTouchEvent(event)
+        //如果是需要拦截,则再拦截,这个方法会在onScrollChanged方法之后再调用一次
+        if (disallowIntercept && lineCount > maxLines) {
+            parent.requestDisallowInterceptTouchEvent(true)
+        }
+
+        return result
+    }
+
+    override fun scrollTo(x: Int, y: Int) {
+        super.scrollTo(x, min(y, mOffsetHeight))
+    }
+
     private fun initOffsetHeight() {
     private fun initOffsetHeight() {
         val mLayoutHeight: Int
         val mLayoutHeight: Int
 
 
@@ -84,69 +169,23 @@ open class InertiaScrollTextView @JvmOverloads constructor(
         val mLayout = layout ?: return
         val mLayout = layout ?: return
         //获得内容面板的高度
         //获得内容面板的高度
         mLayoutHeight = mLayout.height
         mLayoutHeight = mLayout.height
+        //获取上内边距
+        val paddingTop: Int = totalPaddingTop
+        //获取下内边距
+        val paddingBottom: Int = totalPaddingBottom
 
 
-        //计算滑动距离的边界
-        mOffsetHeight = mLayoutHeight + totalPaddingTop + totalPaddingBottom - measuredHeight
-    }
-
-    override fun scrollTo(x: Int, y: Int) {
-        super.scrollTo(x, min(y, mOffsetHeight))
-    }
+        //获得控件的实际高度
+        val mHeight: Int = measuredHeight
 
 
-    @SuppressLint("ClickableViewAccessibility")
-    override fun onTouchEvent(event: MotionEvent?): Boolean {
-        event?.let {
-            if (velocityTracker == null) {
-                velocityTracker = VelocityTracker.obtain()
-            }
-            velocityTracker?.addMovement(it)
-            when (event.action) {
-                MotionEvent.ACTION_DOWN -> {
-                    setScrollState(scrollStateIdle)
-                    mLastTouchY = (event.y + 0.5f).toInt()
-                }
-                MotionEvent.ACTION_MOVE -> {
-                    val y = (event.y + 0.5f).toInt()
-                    var dy = mLastTouchY - y
-                    if (mScrollState != scrollStateDragging) {
-                        var startScroll = false
-
-                        if (abs(dy) > mTouchSlop) {
-                            if (dy > 0) {
-                                dy -= mTouchSlop
-                            } else {
-                                dy += mTouchSlop
-                            }
-                            startScroll = true
-                        }
-                        if (startScroll) {
-                            setScrollState(scrollStateDragging)
-                        }
-                    }
-                    if (mScrollState == scrollStateDragging) {
-                        mLastTouchY = y
-                    }
-                }
-                MotionEvent.ACTION_UP -> {
-                    velocityTracker?.computeCurrentVelocity(1000, mMaxFlingVelocity.toFloat())
-                    val yVelocity = velocityTracker?.yVelocity ?: 0f
-                    if (abs(yVelocity) > mMinFlingVelocity) {
-                        mViewFling.fling(-yVelocity.toInt())
-                    } else {
-                        setScrollState(scrollStateIdle)
-                    }
-                    resetTouch()
-                }
-                MotionEvent.ACTION_CANCEL -> {
-                    resetTouch()
-                }
-            }
+        //计算滑动距离的边界
+        mOffsetHeight = mLayoutHeight + paddingTop + paddingBottom - mHeight
+        if (mOffsetHeight <= 0) {
+            scrollTo(0, 0)
         }
         }
-        return super.onTouchEvent(event)
     }
     }
 
 
     private fun resetTouch() {
     private fun resetTouch() {
-        velocityTracker?.clear()
+        velocityTracker.clear()
     }
     }
 
 
     private fun setScrollState(state: Int) {
     private fun setScrollState(state: Int) {
@@ -224,7 +263,7 @@ open class InertiaScrollTextView @JvmOverloads constructor(
                 mReSchedulePostAnimationCallback = true
                 mReSchedulePostAnimationCallback = true
             } else {
             } else {
                 removeCallbacks(this)
                 removeCallbacks(this)
-                ViewCompat.postOnAnimation(this@InertiaScrollTextView, this)
+                ViewCompat.postOnAnimation(this@ScrollTextView, this)
             }
             }
         }
         }
     }
     }

+ 1 - 1
app/src/main/res/layout-land/activity_book_info.xml

@@ -355,7 +355,7 @@
 
 
                     </LinearLayout>
                     </LinearLayout>
 
 
-                    <io.legado.app.ui.widget.text.NestScrollTextView
+                    <io.legado.app.ui.widget.text.ScrollTextView
                         android:id="@+id/tv_intro"
                         android:id="@+id/tv_intro"
                         android:layout_width="match_parent"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
                         android:layout_height="wrap_content"

+ 1 - 1
app/src/main/res/layout/activity_book_info.xml

@@ -331,7 +331,7 @@
 
 
                 </LinearLayout>
                 </LinearLayout>
 
 
-                <io.legado.app.ui.widget.text.NestScrollTextView
+                <io.legado.app.ui.widget.text.ScrollTextView
                     android:id="@+id/tv_intro"
                     android:id="@+id/tv_intro"
                     android:layout_width="match_parent"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_height="wrap_content"

+ 1 - 1
app/src/main/res/layout/dialog_text_view.xml

@@ -5,7 +5,7 @@
     android:layout_height="match_parent"
     android:layout_height="match_parent"
     android:background="@color/background">
     android:background="@color/background">
 
 
-    <io.legado.app.ui.widget.text.InertiaScrollTextView
+    <io.legado.app.ui.widget.text.ScrollTextView
         android:id="@+id/text_view"
         android:id="@+id/text_view"
         android:layout_width="match_parent"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_height="match_parent"

+ 1 - 1
app/src/main/res/layout/dialog_update.xml

@@ -13,7 +13,7 @@
         app:popupTheme="@style/AppTheme.PopupOverlay"
         app:popupTheme="@style/AppTheme.PopupOverlay"
         app:titleTextAppearance="@style/ToolbarTitle" />
         app:titleTextAppearance="@style/ToolbarTitle" />
 
 
-    <io.legado.app.ui.widget.text.InertiaScrollTextView
+    <io.legado.app.ui.widget.text.ScrollTextView
         android:id="@+id/text_view"
         android:id="@+id/text_view"
         android:layout_width="match_parent"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_height="match_parent"

+ 2 - 1
app/src/main/res/layout/item_source_edit.xml

@@ -9,6 +9,7 @@
         android:id="@+id/editText"
         android:id="@+id/editText"
         android:layout_width="match_parent"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_height="wrap_content"
-        android:inputType="textMultiLine" />
+        android:inputType="textMultiLine"
+        android:maxLines="12" />
 
 
 </io.legado.app.ui.widget.text.TextInputLayout>
 </io.legado.app.ui.widget.text.TextInputLayout>