Android自定义View:超过最大高度时支持滚动并且解决滑动冲突的TextView

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个构造方法,在构造方法内部支持了TextView的滚动设置;
内部有一个 isNeedScroll 方法,用于判断是否需要滚动。如果最大行数大于0且小于实际行数,或者最大高度大于0且小于等于实际高度,则需要滚动;
有3个全局参数:mNeedScrollFlag、mLastScrollFlag、mLastY。
同时重写了 onTouchEvent 方法,对用户的屏幕操作进行处理:

  1. 当动作为 MotionEvent.ACTION_DOWN 时,会调用isNeedScroll方法,如果需要滚动,则设置 mNeedScrollFlag 为 true,并设置滚动方法和垂直滚动条,同时记录Y轴坐标。
  2. 当动作为 MotionEvent.ACTION_MOVE 时,如果需要滚动并且触摸点的纵坐标发生了变化,则计算滚动方向并检查是否可以垂直滚动。如果可以垂直滚动的状态发生了变化,则更新状态并请求父视图不拦截触摸事件;当TextView滚动到边界的时候,就会通知父视图,触摸事件重新由它处理,这时也会将mNeedScrollFlag设置为false,代表此次的触摸事件将不再滑动TextView(变量orientation是判断当前的滑动方向,canScrollVertically方法是判断当前方向是否可继续滑动)。
  3. 当动作为 MotionEvent.ACTION_UP 时,重置标志位。
class VerticalScrollTextView : AppCompatTextView {

    private var mNeedScrollFlag = false
    private var mLastScrollFlag = false
    private var mLastY = 0F
    
    constructor(context : Context) : this(context, null)
    constructor(context : Context, attrs : AttributeSet?) : this(context, attrs, 0)
    constructor(context : Context, attrs : AttributeSet?, defStyleAttr : Int) : super(context, attrs, defStyleAttr) {
        isVerticalScrollBarEnabled = true
        movementMethod = ScrollingMovementMethod.getInstance()
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        event?.run {
            when (action) {
                MotionEvent.ACTION_DOWN -> {
                    if (isNeedScroll()) {
                        mNeedScrollFlag = 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]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Android自定义View是指基于Android原生控件的一种扩展,可以根据自己的需求和设计规范来创建更加个性化和独特的控件。而歌词控件是一种针对音乐播放器或者视频播放器等应用场景中的需求,用于显示音乐或者视频的歌词的控件。 Android自定义View歌词控件的实现思路如下: 1. 首先需要自定义一个View,并继承自View或者其子类,如TextView。 2. 在自定义View中重写onDraw方法,在其中实现绘制歌词的逻辑。 3. 在onDraw方法中,使用Canvas对象进行绘制,可以使用drawText方法绘制歌词文本,也可以使用drawBitmap方法绘制图片背景等。 4. 可以通过自定义属性,如字体大小、字体颜色、歌词滚动速度等,来对歌词控件进行配置。 5. 如果需要实现歌词的滚动效果,可以使用ValueAnimator或者Scroller来实现歌词的平滑滚动。 6. 如果需要实现点击歌词跳转播放进度的功能,可以通过添加点击事件监听器,在触摸事件中判断点击位置对应的歌词行,并根据歌词的间戳跳转到指定的播放进度。 总结来说,Android自定义View歌词控件的实现需要重写onDraw方法进行绘制,可以通过Canvas对象进行绘制文本或者图像,通过自定义属性进行配置,使用动画或者滚动实现歌词的平滑滚动,通过监听触摸事件实现点击歌词跳转播放进度的功能。通过以上步骤,我们可以创建一个个性化的歌词控件,满足不同应用场景的需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白白猪

感谢兄弟的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值