当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(); } }