ScrollView嵌套ListView滑动冲突处理
2021-10-23 本文已影响0人
loby
需求:
实现一个页面上整体内容可以上下滚动,页面的上半部分是一些固定内容,下半部分是一个固定高度的列表。
这种布局页面底部使用ListView,外层使用ScrollView包裹就可以实现页面内容整体上下滚动。但是当ScrollView嵌套ListView的时候会产生滑动冲突,会导致ListView滑动不了。
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
//上半部分固定内容
<TextView
android:layout_width="match_parent"
android:layout_height="500dp"
android:gravity="center"
android:textSize="15sp"
android:textColor="@color/color_font_333333"
android:text="上半部分固定内容"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="400dp">
<com.student.MyListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#00000000"
android:dividerHeight="10dp"
android:listSelector="@android:color/transparent"
android:scrollbars="none" />
<include layout="@layout/view_empty" />
</FrameLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</ScrollView>
解决方法:
MainActivity
MainActivity对ListView进行赋值,ListView保留ScrollView的引用。
package com.student;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ScrollView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.student.R;
import com.student.MyListView;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.list_view)
MyListView mListView;
@BindView(R.id.scroll_view)
ScrollView mScrollView;
private List<String> mData;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initView();
}
private void initView() {
mData = new ArrayList<>();
for (int i = 'A'; i <= 'Z'; i++) {
mData.add((char) i + "");
}
mListView.setAdapter(new ArrayAdapter<String>(this, R.layout.word_item));
mListView.setScrollView(mScrollView);
}
}
R.layout.word_item
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="A"/>
MyListView
package com.student;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.ScrollView;
public class MyListView extends ListView {
private boolean mIsScrolledToTop = true;
private boolean mIsScrolledToBottom = true;
private int mDownY, mMoveY;
private ScrollView mScrollView;
public MyListView(Context context) {
super(context);
init();
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//分别判断是否已经滑动到了顶部和底部
//当Item无法填充满ListView高度的时候,滑动到了顶部和底部都是成立的
mIsScrolledToTop = false;
mIsScrolledToBottom = false;
if (firstVisibleItem == 0) {
View firstVisibleItemView = MyListView.this.getChildAt(0);
if (firstVisibleItemView != null && firstVisibleItemView.getTop() == 0) {
mIsScrolledToTop = true;
}
}
if ((firstVisibleItem + visibleItemCount) == totalItemCount) {
View lastVisibleItemView = MyListView.this.getChildAt(MyListView.this.getChildCount() - 1);
//需要考虑Item无法填充满ListView高度的情况,所以使用<=
if (lastVisibleItemView != null && lastVisibleItemView.getBottom() <= MyListView.this.getHeight()) {
mIsScrolledToBottom = true;
}
}
}
});
}
public void setScrollView(ScrollView scrollView) {
mScrollView = scrollView;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if (MyListView.this.getAdapter() == null || MyListView.this.getAdapter().getCount() <= 0) {
//空数据时,ListView不需要滑动事件
this.mScrollView.requestDisallowInterceptTouchEvent(false);
} else {
mMoveY = (int) ev.getY();
if (mMoveY > mDownY) {
Log.e("MyListView", "向下滑动");
//向下滑动
//证明ListView已经滑动了顶部,这时候的滑动事件就应该交给ScrollView了,允许ScrollView对事件进行拦截访问
if (mIsScrolledToTop) {
this.mScrollView.requestDisallowInterceptTouchEvent(false);
} else {
this.mScrollView.requestDisallowInterceptTouchEvent(true);
}
} else {
Log.e("MyListView", "向上滑动");
//向上滑动
//证明ListView已经滑动了底部,这时候的滑动事件就应该交给ScrollView了,允许ScrollView对事件进行拦截访问
if (mIsScrolledToBottom) {
this.mScrollView.requestDisallowInterceptTouchEvent(false);
} else {
this.mScrollView.requestDisallowInterceptTouchEvent(true);
}
}
}
break;
case MotionEvent.ACTION_UP:
this.mScrollView.requestDisallowInterceptTouchEvent(false);
break;
}
return super.dispatchTouchEvent(ev);
}
}
QQ群:445224732