TextView处理滑动冲突复盘

本文介绍了如何在不使用ScrollView的情况下,处理TextView内容过多导致的滑动冲突问题。通过自定义ScrollingMovementMethod的子类并检测是否滑动到底部,实现了TextView的滑动功能,并在dispatchTouchEvent中处理滑动冲突。这种方法避免了ScrollView的额外嵌套,但仍可能不及ScrollView的滑动体验。

平常在ViewGroup中放一个textView组件,无可避免会出现textView内容过多而需要解决滑动冲突的问题.

大多数的做法就是再嵌套一个ScrollView来处理滑动冲突,而之所以用ScrollView的考虑无非就是处理是否滑动到边界,这么想想感觉不值得!

网上有很多介绍如何让TextView加载多内容时可滑动的文章,但是很少有解决其滑动冲突的文章.

今天就不说怎么支持滑动了,因为只是加一句

textView.setMovementMethod(ScrollingMovementMethod.getInstance());

既然支持了滑动,想必肯定也能在其中发现一二吧,于是翻开这个ScrollingMovementMethod类来,一眼就发现了这个方法

    @Override
    protected boolean bottom(TextView widget, Spannable buffer) {
        return scrollBottom(widget, buffer);
    }

继续跟踪看一眼,在BaseMovementMethod中就会发现结果

    /**执行滚动到底部动作。滚动到文档底部
     * Performs a scroll to bottom action.
     * Scrolls to the bottom of the document.
     *
     * @param widget The text view.
     * @param buffer The text buffer.
     * @return True if the event was handled.
     * @hide
     */
    protected boolean scrollBottom(TextView widget, Spannable buffer) {
        final Layout layout = widget.getLayout();
        final int lineCount = layout.getLineCount();//文本有多少行
        if (getBottomLine(widget) <= lineCount - 1) {//还没有到底部,则滚动到底部
            Touch.scrollTo(widget, layout, widget.getScrollX(),
                    layout.getLineTop(lineCount) - getInnerHeight(widget));
            return true;
        }
        return false;
    }

这里我们只需要知道是否滚动到底部,所以只需要

getBottomLine(TextView widget)方法即可,但发现是private修饰,所以写一个子类继承一下,于是就有了

import android.text.Layout;
import android.text.method.MovementMethod;
import android.text.method.ScrollingMovementMethod;
import android.widget.TextView;

public class SimpleScrollingMoveMethod extends ScrollingMovementMethod {

    public boolean isBottom(TextView widget){
        final Layout layout = widget.getLayout();
        final int lineCount = layout.getLineCount();
        return getBottomLine(widget) >= lineCount - 1;
    }

    public boolean isTop(TextView widget){
        return getTopLine(widget) == 0;
    }

    private int getTopLine(TextView widget) {
        return widget.getLayout().getLineForVertical(widget.getScrollY());
    }

    private int getBottomLine(TextView widget) {
        return widget.getLayout().getLineForVertical(widget.getScrollY() + getInnerHeight(widget));
    }

    private int getInnerHeight(TextView widget) {
        return widget.getHeight() - widget.getTotalPaddingTop() - widget.getTotalPaddingBottom();
    }

    public static MovementMethod getInstance() {
        if (sInstance == null)
            sInstance = new SimpleScrollingMoveMethod();

        return sInstance;
    }

    private static SimpleScrollingMoveMethod sInstance;
}

现在已经知道了是否滑动到底部了,接下来就是解决滑动冲突的问题了.网上还是有很多文章讲这个的,就不多说,上一段代码好了

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class ScrollTextView extends android.support.v7.widget.AppCompatTextView {

    public ScrollTextView(Context context) {
        super(context);
    }

    public ScrollTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setMovementMethod(SimpleScrollingMoveMethod.getInstance());
    }

    float mLastY;
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mLastY = event.getY();
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
                case MotionEvent.ACTION_MOVE:
                    float scrollY = event.getY() - mLastY;
                    SimpleScrollingMoveMethod movementMethod = (SimpleScrollingMoveMethod) getMovementMethod();
                    if (scrollY < 0 && movementMethod.isBottom(this)){
                        getParent().requestDisallowInterceptTouchEvent(false);
                    }else if (scrollY > 0 && movementMethod.isTop(this)){
                        getParent().requestDisallowInterceptTouchEvent(false);
                    }else {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }
                    break;
        }
        return super.dispatchTouchEvent(event);
    }

}

完整的调用流程截图走一下好了.

到此结束了,仅处理textView如何处理底部事件滑动冲突,至于滑动的其他处理就类似了!不过没有ScrollView丝滑,哈哈!
补充一下,ScrollView与TextView判断到底或者到顶的方式不一样,ScrollView是View高度判断,而TextView则是文字行数判断,所以还是ScrollView处理的精确一些

在 Android 开发中,为 TextView 设置滑动功能有以下几种常见方法: ### 方法一:通过设置 TextView 属性实现垂直滚动 在 XML 布局文件中,为 TextView 配置相关属性以启用垂直滚动。示例代码如下: ```xml <TextView android:id="@+id/scrollableTextView" android:layout_width="match_parent" android:layout_height="200dp" android:text="这里是一段很长的文本,用于测试 TextView 的滚动功能。这里是一段很长的文本,用于测试 TextView 的滚动功能。这里是一段很长的文本,用于测试 TextView 的滚动功能。" android:scrollbars="vertical" android:maxLines="5" android:overScrollMode="always" /> ``` 在 Java 代码中,需要调用 `setMovementMethod()` 方法来真正启用滚动: ```java import android.os.Bundle; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import android.text.method.ScrollingMovementMethod; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = findViewById(R.id.scrollableTextView); textView.setMovementMethod(new ScrollingMovementMethod()); } } ``` 通过上述操作,TextView 就具备了垂直滚动的功能。其中,`android:scrollbars="vertical"` 用于显示垂直滚动条,`android:maxLines` 限制了显示的最大行数,`android:overScrollMode` 定义了滚动边界的行为,`setMovementMethod(new ScrollingMovementMethod())` 则是启用滚动的关键代码[^1]。 ### 方法二:使用 ScrollView 或 NestedScrollView 包裹 TextViewTextView 放置在 ScrollView 或 NestedScrollView 中,也能实现滚动效果。示例代码如下: ```xml <ScrollView android:layout_width="match_parent" android:layout_height="200dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="这里是一段很长的文本,用于测试 ScrollView 包裹 TextView 的滚动功能。这里是一段很长的文本,用于测试 ScrollView 包裹 TextView 的滚动功能。这里是一段很长的文本,用于测试 ScrollView 包裹 TextView 的滚动功能。" /> </ScrollView> ``` 使用 ScrollView 或 NestedScrollView 包裹 TextView 时,ScrollView 会处理滚动事件,使得 TextView 内容可以滚动显示。这种方式适用于需要更复杂滚动效果的场景,例如与其他视图一起滚动等[^1]。 ### 方法三:自定义滑动条样式 可以通过设置 `android:scrollbarThumbVertical` 和 `android:scrollbarTrackVertical` 来自定义滑动条的滑块和滑道图片,示例代码如下: ```xml <TextView android:layout_width="match_parent" android:layout_height="200dp" android:text="这里是一段很长的文本,用于测试自定义滑动条样式。这里是一段很长的文本,用于测试自定义滑动条样式。这里是一段很长的文本,用于测试自定义滑动条样式。" android:scrollbars="vertical" android:scrollbarThumbVertical="@drawable/ic_launcher" android:scrollbarTrackVertical="@drawable/ic_launcher" /> ``` 上述代码中,`android:scrollbarThumbVertical` 用于设置滑块的图片,`android:scrollbarTrackVertical` 用于设置滑道的图片[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值