Scrollview和listview滑动冲突

当Scrollview嵌套listview的时候,listview的高度就不能自适应,而是要自定义一个固定的高度,否则listview无法复用item,高度就会只有一个item的高度。此其一,其二也是本文的重点,解决滑动冲突。网上的资料一大堆,就不在此累赘。

思路是:当listview处于底部的时候,判断Scrollview是否滑动到底部,如果滑动到底部,则可以滑动listview,如果没滑到底部,则listview禁止滑动。

代码如下:

public class MainActivity extends AppCompatActivity {

    /**
     * viewpager横向滑动的阈值
     */
    private static final int THRESHOLD_X_VIEW_PAGER = 60;
    /**
     * listview竖向滑动的阈值
     */
    private static final int THRESHOLD_Y_LIST_VIEW = 20;

    /**
     * 下拉刷新控件
     */
    private SwipeRefreshLayout mRefreshLayout;
    private BottomScrollView mScrollView;
    private ViewPager mViewPager;
    private ListView mListView;

    private ViewPagerAdapter mViewPagerAdapter;
    private ListViewAdapter mListViewAdapter;

    private boolean isSvToBottom = false;

    private float mLastX;
    private float mLastY;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initAction();
        fixSlideConflict();
    }

    private void initView() {
        mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.main_refresh_layout);
        mScrollView = (BottomScrollView) findViewById(R.id.main_scroll_view);
        mViewPager = (ViewPager) findViewById(R.id.main_viewpager);
        mListView = (ListView) findViewById(R.id.main_list_view);

        mListViewAdapter = new ListViewAdapter(this, getListViewData());
        mListView.setAdapter(mListViewAdapter);

        mViewPagerAdapter = new ViewPagerAdapter(this, getViewPagerData());
        mViewPager.setAdapter(mViewPagerAdapter);

    }

    private List<String> getListViewData() {
        List<String> data = new ArrayList<>();
        for(int i = 1; i <= 20; i ++) {
            data.add(i + " item");
        }

        return data;
    }

    private List<String> getViewPagerData() {
        List<String> data = new ArrayList<>();
        for(int i = 1; i <= 5; i ++) {
            data.add("page " + i);
        }

        return data;
    }

    private void initAction() {
        //模拟下拉刷新,0.5秒后,下拉刷新状态视图消失
        mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                mRefreshLayout.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mRefreshLayout.setRefreshing(false);
                    }
                }, 500);
            }
        });

        mScrollView.setScrollToBottomListener(new BottomScrollView.OnScrollToBottomListener() {
            @Override
            public void onScrollToBottom() {
                isSvToBottom = true;
            }

            @Override
            public void onNotScrollToBottom() {
                isSvToBottom = false;
            }
        });
    }

    private void fixSlideConflict() {
        // ViewPager滑动冲突解决
        mViewPager.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();

                if(action == MotionEvent.ACTION_DOWN) {
                    // 记录点击到ViewPager时候,手指的X坐标
                    mLastX = event.getX();
                }
                if(action == MotionEvent.ACTION_MOVE) {
                    // 超过阈值,禁止SwipeRefreshLayout下拉刷新,禁止ScrollView截断点击事件
                    if(Math.abs(event.getX() - mLastX) > THRESHOLD_X_VIEW_PAGER) {
                        mRefreshLayout.setEnabled(false);
                        mScrollView.requestDisallowInterceptTouchEvent(true);
                    }
                }
                // 用户抬起手指,恢复父布局状态
                if(action == MotionEvent.ACTION_UP) {
                    mRefreshLayout.setEnabled(true);
                    mScrollView.requestDisallowInterceptTouchEvent(false);
                }
                return false;
            }
        });

        // ListView滑动冲突解决
        mListView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();


                if(action == MotionEvent.ACTION_DOWN) {
                    mLastY = event.getY();
                }
                if(action == MotionEvent.ACTION_MOVE) {
                    int top = mListView.getChildAt(0).getTop();
                    float nowY = event.getY();
                    if(!isSvToBottom) {
                        // 允许scrollview拦截点击事件, scrollView滑动
                        mScrollView.requestDisallowInterceptTouchEvent(false);
                    } else if(top == 0 && nowY - mLastY > THRESHOLD_Y_LIST_VIEW) {
                        // 允许scrollview拦截点击事件, scrollView滑动
                        mScrollView.requestDisallowInterceptTouchEvent(false);
                    } else {
                        // 不允许scrollview拦截点击事件, listView滑动
                        mScrollView.requestDisallowInterceptTouchEvent(true);
                    }
                }
                return false;
            }
        });
    }
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.demo.svslide.MainActivity">
    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/main_refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.demo.svslide.view.BottomScrollView
            android:id="@+id/main_scroll_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
                <android.support.v4.view.ViewPager
                    android:id="@+id/main_viewpager"
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/vp_height">

                </android.support.v4.view.ViewPager>
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/tv_height"
                    android:gravity="center"
                    android:background="@color/bg_tv"
                    android:textColor="@color/text_color_white"
                    android:text="@string/tv_text"/>
                <ListView
                    android:id="@+id/main_list_view"
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/lv_height"
                    android:divider="@color/colorPrimaryDark"
                    android:dividerHeight="@dimen/lv_divider_height">
                </ListView>
            </LinearLayout>
        </com.demo.svslide.view.BottomScrollView>
    </android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>

字号

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>

    <dimen name="vp_height">320dp</dimen>
    <dimen name="tv_height">140dp</dimen>
    <dimen name="lv_height">200dp</dimen>
    <dimen name="lv_divider_height">1dp</dimen>

    <dimen name="list_item_height">55dp</dimen>
</resources>
<resources>
    <string name="app_name">SvSlideDemo</string>
    <string name="tv_text">This is a TextView</string>
</resources>

用到的一个类

public class BottomScrollView extends ScrollView {

    private OnScrollToBottomListener mOnScrollToBottomListener;

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

    public BottomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BottomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public BottomScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt){
        super.onScrollChanged(l,t,oldl,oldt);
        // 滑动的距离加上本身的高度与子View的高度对比
        if(t + getHeight() >=  getChildAt(0).getMeasuredHeight()){
            // ScrollView滑动到底部
            if(mOnScrollToBottomListener != null) {
                mOnScrollToBottomListener.onScrollToBottom();
            }
        } else {
            if(mOnScrollToBottomListener != null) {
                mOnScrollToBottomListener.onNotScrollToBottom();
            }
        }
    }

    public void setScrollToBottomListener(OnScrollToBottomListener listener) {
        this.mOnScrollToBottomListener = listener;
    }

    public interface OnScrollToBottomListener {
        void onScrollToBottom();
        void onNotScrollToBottom();
    }
}
发布了95 篇原创文章 · 获赞 17 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_30299243/article/details/90812628