diff --git a/app/src/main/java/io/legado/app/ui/widget/code/CodeView.kt b/app/src/main/java/io/legado/app/ui/widget/code/CodeView.kt index c07a0d56f..fea3b0a2b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/code/CodeView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/code/CodeView.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.widget.code +import android.annotation.SuppressLint import android.content.Context import android.graphics.Canvas import android.graphics.Paint @@ -12,6 +13,7 @@ import android.text.style.BackgroundColorSpan import android.text.style.ForegroundColorSpan import android.text.style.ReplacementSpan import android.util.AttributeSet +import android.view.MotionEvent import androidx.annotation.ColorInt import androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView import java.util.* @@ -37,6 +39,12 @@ class CodeView @JvmOverloads constructor(context: Context, attrs: AttributeSet? private val mSyntaxPatternMap: MutableMap = HashMap() private var mIndentCharacterList = mutableListOf('{', '+', '-', '*', '/', '=') + //滑动距离的最大边界 + private var mOffsetHeight = 0 + + //是否到顶或者到底的标志 + private var mBottomFlag = false + private val mUpdateRunnable = Runnable { val source = text highlightWithoutChange(source) @@ -102,6 +110,83 @@ class CodeView @JvmOverloads constructor(context: Context, attrs: AttributeSet? addTextChangedListener(mEditorTextWatcher) } + 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 (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 + } + } + + override fun showDropDown() { + val screenPoint = IntArray(2) + getLocationOnScreen(screenPoint) + val displayFrame = Rect() + getWindowVisibleDisplayFrame(displayFrame) + val position = selectionStart + val layout = layout + val line = layout.getLineForOffset(position) + val verticalDistanceInDp = (750 + 140 * line) / displayDensity + dropDownVerticalOffset = verticalDistanceInDp.toInt() + val horizontalDistanceInDp = layout.getPrimaryHorizontal(position) / displayDensity + dropDownHorizontalOffset = horizontalDistanceInDp.toInt() + super.showDropDown() + } + + 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 autoIndent( source: CharSequence, dest: Spanned, @@ -365,21 +450,6 @@ class CodeView @JvmOverloads constructor(context: Context, attrs: AttributeSet? highlightWhileTextChanging = updateWhileTextChanging } - override fun showDropDown() { - val screenPoint = IntArray(2) - getLocationOnScreen(screenPoint) - val displayFrame = Rect() - getWindowVisibleDisplayFrame(displayFrame) - val position = selectionStart - val layout = layout - val line = layout.getLineForOffset(position) - val verticalDistanceInDp = (750 + 140 * line) / displayDensity - dropDownVerticalOffset = verticalDistanceInDp.toInt() - val horizontalDistanceInDp = layout.getPrimaryHorizontal(position) / displayDensity - dropDownHorizontalOffset = horizontalDistanceInDp.toInt() - super.showDropDown() - } - private inner class TabWidthSpan : ReplacementSpan() { override fun getSize( paint: Paint, diff --git a/app/src/main/res/layout/item_source_edit.xml b/app/src/main/res/layout/item_source_edit.xml index cd14a6fe4..6f05121f0 100644 --- a/app/src/main/res/layout/item_source_edit.xml +++ b/app/src/main/res/layout/item_source_edit.xml @@ -9,6 +9,7 @@ android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" - android:inputType="textMultiLine" /> + android:inputType="textMultiLine" + android:maxLines="12" /> \ No newline at end of file