ScrollView与Listview嵌套使用时的滑动冲突问题

滑动冲突解决方案

在我们的布局中有可能使用Scrollview嵌套Listview的情况,这时候如果不加任何的处理,就会发生滑动冲突问题,即Listview没有完全显示,也不能滑动,触摸事件被Scrollview拦截而使只有Scrollview在滑动。根据Android开发ViewGroup及View事件分发总结,我们可以用以下的方案来解决:

根据对捕获到的事件,我们可以对事件作出判断(处理或不处理),我们可以采用设置监听的方式setOnTouchListener(),也可以继承View而复写OnTouchEvent()的方式。但在ViewGroup中要判断是否拦截事件的时候则只能复写disPatchTouchEvent()方法。在本例中采用继承Scrollview和设置Listview监听器的方式。

先看Activity中的代码:

package com.zyxr.www.huadongchongtu;

import android.content.Intent;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.ScrollView;

import com.zyxr.www.R;

public class HuaDongActivity extends AppCompatActivity {
    private ListView mListView;
    private ScrollView mScroView;
    boolean isTopOrBottom = false;//判断是否滑到了顶部或底部
    private boolean hasChange = false;//判断listview滑动状态是否改变的标记
    private int mListViewHeight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hua_dong);
        mListView = (ListView) findViewById(R.id.huadong_list);
        mScroView = (ScrollView) findViewById(R.id.huadong_scro);

        mListView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {

                if(motionEvent.getAction()!=MotionEvent.ACTION_UP){
                    mScroView.requestDisallowInterceptTouchEvent(true);//不允许ScrollView拦截事件
                }else {
                    mScroView.requestDisallowInterceptTouchEvent(false);//允许ScrollView拦截事件
                }

                return false;
            }
        });
        mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView absListView, int i) {
                hasChange = true;
            }

            @Override
            public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                if(hasChange){
                    if ((visibleItemCount > 0) && (firstVisibleItem == 0)) {
                        if (absListView.getChildAt(0).getTop() >= 0) {  //判断listview是否滑动到了顶部
                            isTopOrBottom = true;
                            Intent intent = new Intent("com.zyxr.www");
                            sendBroadcast(intent);//以广播的形式通知scrollview需要拦截事件
                        }
                    }
                    else if ((firstVisibleItem + visibleItemCount) == totalItemCount){
                        View lastVisibleItemView = mListView.getChildAt(mListView.getChildCount() - 1);

                        if(lastVisibleItemView != null && lastVisibleItemView.getBottom() == mListViewHeight){ //判断listview是否滑动到了底部
                            isTopOrBottom = true;
                            Intent intent = new Intent("com.zyxr.www");
                            sendBroadcast(intent);//以广播的形式通知scrollview需要拦截事件
                        }
                    }
                }
            }
        });

        mListView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mListViewHeight = mListView.getHeight();//获取listview的高度

                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
                    mListView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                } else {
                    mListView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }
            }
        });

    }
}

布局中加几张大的图片以使Scrollview和LIstview都能滑动,以下是Activity加载的布局:

<?xml version="1.0" encoding="utf-8"?>
<com.zyxr.www.huadongchongtu.MScrollView
    android:id="@+id/huadong_scro"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<LinearLayout
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.zyxr.www.huadongchongtu.HuaDongActivity">
    <ImageView
        android:layout_width="wrap_content"
        android:src="@drawable/p1"
        android:scaleType="fitXY"
        android:layout_height="200dp"/>
    <ImageView
        android:layout_width="wrap_content"
        android:scaleType="fitXY"
        android:layout_height="200dp"
        android:src="@drawable/p2"/>
    <ListView
        android:id="@+id/huadong_list"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:entries="@array/ceshi">

    </ListView>

    <ImageView
        android:layout_width="wrap_content"
        android:scaleType="fitXY"
        android:layout_height="200dp"
        android:src="@drawable/p3"/>

</LinearLayout>
</com.zyxr.www.huadongchongtu.MScrollView>

在资源文件Strings中加入:

 <string-array name="ceshi">
        <item>南山区</item>
        <item>福田区</item>
        <item>光明新区</item>
        <item>龙华新区</item>
        <item>罗湖区</item>
        <item>宝安区</item>
    </string-array>

下面是继承Scrollview并复写其中的方法:


package com.zyxr.www.huadongchongtu;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;

/**
 * Created by Administrator on 2016/7/28.
 */
public class MScrollView extends ScrollView{
    Context context ;
    private boolean isTopOrBottom = false;
    public MScrollView(Context context) {

        super(context);
        this.context = context;
        init();
    }

    private void init() {
        BroadcastReceiver receiver = new MBroadCast();
        IntentFilter filter = new IntentFilter("com.zyxr.www");
        context.registerReceiver(receiver,filter);//注册广播

    }

    public MScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public MScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        if(isTopOrBottom){
            return true;//将后续事件拦截了,后续事件该方法也不会执行
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        if(ev.getAction() == MotionEvent.ACTION_UP){
            isTopOrBottom = false; //释放手时保证下次触摸scrollview不会拦截事件
        }
        return super.onTouchEvent(ev);
    }

    public class MBroadCast extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            isTopOrBottom = true;//到达了listview顶部
            requestDisallowInterceptTouchEvent(false);//告诉自己可以拦截事件,即会执行onInterceptTouchEvent方法
        }
    }

}

代码很简单,其中也有不足的地方,其实只要把原理及结论都弄清楚了,一切问题都迎刃而解,解决的方案也会多种多样,嗯,就这样!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值