VerticalScrollTextView:超过最大高度时支持滚动并且解决滑动冲突的TextView
正如标题所说,这个自定义TextView在它的行数超过最大行数或是高度超过最大高度限制时,会将TextView设置为可纵向滑动的状态,如果没有超过限制,它还是跟普通的TextView保存一致。当滚动到边界时,自动将滑动事件归还给父布局。
效果图
XML布局
当TextView的外层是一些滚动布局时,直接让TextView简单地支持滑动是解决不了问题的,因为这时就会有滑动冲突的问题。
这时VerticalScrollTextView就派上用场了,我们在ScrollView的内部添加一个VerticalScrollTextView,布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#666600"/>
<View
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#660000"/>
<com.hbh.swipecaptchademo.VerticalScrollTextView
android:id="@+id/test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="123\n\n\n\n154\n\n5484\n\n\n12\n8484\n\n121\n\niailll "
android:textSize="16sp"
android:textColor="@color/black"
android:maxLines="6"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<View
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#660000"/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#666600"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
源码如下:
VerticalScrollTextView代码解释 :
实现了默认的3个构造方法;
内部有一个 isNeedScroll 方法,用于判断是否需要滚动。如果最大行数大于0且小于实际行数,或者最大高度大于0且小于等于实际高度,则需要滚动;
有3个全局参数:mNeedScrollFlag、mLastScrollFlag、mLastY。
同时重写了 onTouchEvent 方法,对用户的屏幕操作进行处理:
- 当动作为 MotionEvent.ACTION_DOWN 时,会调用isNeedScroll方法,如果需要滚动,则设置 mNeedScrollFlag 为 true,并设置滚动方法和垂直滚动条,同时记录Y轴坐标。
- 当动作为 MotionEvent.ACTION_MOVE 时,如果需要滚动并且触摸点的纵坐标发生了变化,则计算滚动方向并检查是否可以垂直滚动。如果可以垂直滚动的状态发生了变化,则更新状态并请求父视图不拦截触摸事件;当TextView滚动到边界的时候,就会通知父视图,触摸事件重新由它处理,这时也会将mNeedScrollFlag设置为false,代表此次的触摸事件将不再滑动TextView。
- 当动作为 MotionEvent.ACTION_UP 时,重置标志位。
class VerticalScrollTextView : AppCompatTextView {
private var mNeedScrollFlag = false
private var mLastScrollFlag = false
private var mLastY = 0F
constructor(context : Context) : super(context)
constructor(context : Context, attrs : AttributeSet?) : super(context, attrs)
constructor(context : Context, attrs : AttributeSet?, defStyleAttr : Int) : super(context, attrs, defStyleAttr)
override fun onTouchEvent(event: MotionEvent?): Boolean {
event?.run {
when (action) {
MotionEvent.ACTION_DOWN -> {
if (isNeedScroll()) {
mNeedScrollFlag = true
movementMethod = ScrollingMovementMethod.getInstance()
isVerticalScrollBarEnabled = true
mLastY = rawY
}
}
MotionEvent.ACTION_MOVE -> {
if (mNeedScrollFlag and (rawY != mLastY)) {
val orientation = if (rawY - mLastY > 0) -1 else 1
val scrollFlag = canScrollVertically(orientation)
if (scrollFlag != mLastScrollFlag) {
parent.requestDisallowInterceptTouchEvent(scrollFlag)
mLastScrollFlag = scrollFlag
if (!scrollFlag) mNeedScrollFlag = false
}
mLastY = rawY
}
}
MotionEvent.ACTION_UP -> {
mNeedScrollFlag = false
mLastScrollFlag = false
}
}
}
return super.onTouchEvent(event)
}
private fun isNeedScroll() : Boolean {
return ((maxLines > 0) and (maxLines < lineCount)) or ((maxHeight > 0) and (maxHeight <= height))
}
}
总结
对自己写的自定义View做一个记录,方便以后的使用,也希望可以帮助大家解决类似的情况。创作不易,觉得不错的话,就来个一键三连吧,感谢大家!
未经许可,请勿转载!
本文链接:[https://blog.csdn.net/weixin_44337681/article/details/130864426]