NestedScrollView嵌套recyclerview, 列表第一次点击事件失效问题;

10 阅读3分钟
package com.eeepay.eeepay_v2.ui.view;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.OverScroller;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.NestedScrollView;

import java.lang.reflect.Field;
/*
 * ================================================
 * 描述:NestedScrollView嵌套recyclerview, 列表第一次点击事件失效问题;

原文链接:https://blog.csdn.net/weixin_37459943/article/details/109195926
 * 作者:zhuangzeqin
 * 时间: 2024/10/16 20:25
 * 邮箱:zzq@eeepay.cn
 * 备注:
 * ----------------------------------------------------------------
 * You never know what you can do until you try !
 *      _              _           _     _   ____  _             _ _
 *     / \   _ __   __| |_ __ ___ (_) __| | / ___|| |_ _   _  __| (_) ___
 *    / _ \ | '_ \ / _` | '__/ _ | |/ _` | ___ | __| | | |/ _` | |/ _ \
 *   / ___ | | | | (_| | | | (_) | | (_| |  ___) | |_| |_| | (_| | | (_) |
 *  /_/   __| |_|__,_|_|  ___/|_|__,_| |____/ __|__,_|__,_|_|___/
 *
 * 签名:最痛苦的事不是我失败了,而是我本可以.--zzq
 * ----------------------------------------------------------------
 * ================================================
 */

public class MyNestedScrollView extends NestedScrollView {
    private final Handler handler = new Handler();
//    private int downY; // 记录下拉开始位置的 Y 坐标
//    private int mTouchSlop; // 记录下拉开始位置的 Y 坐标
//    private ScrollInterface scrollInterface; // 自定义的滚动监听器接口
    public MyNestedScrollView(Context context) {
        super(context);
//        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); // 获取触摸阈值
    }

    public MyNestedScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
//        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); // 获取触摸阈值
    }

    public MyNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
//        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); // 获取触摸阈值
    }
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean result = super.onTouchEvent(ev); // 调用父类的 onTouchEvent 方法
        // 当触摸事件为 ACTION_CANCEL 或 ACTION_UP 时,调用 requestEndScroll() 方法
        if (ev != null && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP)) {
            requestEndScroll();
        }
        return result;
    }

    // 解决 ScrollView 滚动结束但是 scroll 仍然没有 finish 导致的无法点击的问题
    private void requestEndScroll() {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                try {
                    // 获取 NestedScrollView 的私有成员变量 mScroller
                    Field scrollerField = NestedScrollView.class.getDeclaredField("mScroller");
                    scrollerField.setAccessible(true);
                    // 获取 mScroller 对象
                    OverScroller scroller = (OverScroller) scrollerField.get(MyNestedScrollView.this);
                    scrollerField.setAccessible(false);
                    // 如果滚动动画尚未结束,就强制取消滚动动画
                    if (!scroller.isFinished()) {
                        scroller.abortAnimation();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 240); // 延迟 240 毫秒后执行
    }


//    @Override // 重写 interceptTouchEvent 方法
//    public boolean onInterceptTouchEvent(MotionEvent e) {
//        int action = e.getAction();
//        switch (action) {
//            case MotionEvent.ACTION_DOWN:
//                downY = (int) e.getRawY(); // 记录下拉开始位置的 Y 坐标
//                break;
//            case MotionEvent.ACTION_MOVE:
//                int moveY = (int) e.getRawY();
//                if (Math.abs(moveY - downY) > mTouchSlop) { // 判断滑动距离大于触摸阈值
//                    return true; // 返回 true 表示拦截触摸事件
//                }
//        }
//        return super.onInterceptTouchEvent(e); // 将事件传递给父类处理
//    }
//
//    // 定义滚动监听器接口
//    public interface ScrollInterface {
//        void onScrollChange(int scrollX, int scrollY, int oldScrollX, int oldScrollY);
//    }
//
//    @Override // 重写 onScrollChanged 方法
//    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
//        if (scrollInterface != null) {
//            scrollInterface.onScrollChange(l, t, oldl, oldt); // 调用监听器方法
//        }
//        super.onScrollChanged(l, t, oldl, oldt);
//    }
//
//    public void setOnScrollChangeListener(ScrollInterface t) {
//        this.scrollInterface = t; // 设置滚动监听器
//    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:minHeight="630dp"
    android:orientation="vertical">
    <!-- 头部按钮测试  -->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/size_60"
        android:layout_gravity="center_horizontal"
        android:background="@color/white"
        android:gravity="center"
        android:minHeight="@dimen/size_60">

        <TextView
            android:id="@+id/tvClose"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentStart="true"
            android:gravity="center"
            android:paddingLeft="@dimen/size_20"
            android:paddingRight="@dimen/size_20"
            android:text="取消"
            android:textColor="@color/color_999999"
            android:textSize="@dimen/text_size_14" />

        <TextView
            android:id="@+id/tvSubmit"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentEnd="true"
            android:gravity="center"
            android:paddingLeft="@dimen/size_20"
            android:paddingRight="@dimen/size_20"
            android:text="确定"
            android:textColor="@color/color_BA8B40"
            android:textSize="@dimen/text_size_14" />

    </RelativeLayout>

    <com.eeepay.eeepay_v2.ui.view.MyNestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fillViewport="true"
        android:overScrollMode="never">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <!--1级菜单-->
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rvMccTypeList"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:overScrollMode="never"
                app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                tools:itemCount="10"
                tools:listitem="@layout/item_mcctype" />

            <RelativeLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="2"
                >
                <!--2级菜单 如果没有三级菜单则不显示箭头-->
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rvSubMccTypeTwoList"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="@dimen/size_20"
                    android:nestedScrollingEnabled="false"
                    android:overScrollMode="never"
                    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                    tools:itemCount="5"
                    tools:listitem="@layout/item_submcctype" />
            </RelativeLayout>

        </LinearLayout>
    </com.eeepay.eeepay_v2.ui.view.MyNestedScrollView>
</LinearLayout>