安卓学习之解决ScrollView嵌套自定义上拉加载的Listview事件冲突

来源:互联网 发布:沈阳专业seo公司 编辑:程序博客网 时间:2024/04/28 17:27

问题

ScrollView和ListView都具有滑动的功能,如果在ScrollView中嵌套ListView,就会出现滑动时间冲突,那如果非要在ScrollVIew中嵌套ListView,又该怎么做呢?下文将提出一种解决方案,在ScrollView中嵌套上拉加载的ListView。

解决思路

既然我们知道在ScrollView中嵌套ListView会出现滑动事件冲突,所以解决的办法就是对事件的分发拦截等进行处理。
首先我们先自定义一个上拉加载的DropLoadListView,代码如下:

import android.content.Context;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.widget.AbsListView;import android.widget.ListView;import com.example.mahui.stop.R;/** * Created by mahui on 16/12/31. * 创建上拉加载的listview */public class DropLoadListView extends ListView implements AbsListView.OnScrollListener {    private Context context;    private View footer;    private int totalItemCount;//总数量    private int lastItemCount;//最后一个    private boolean isLoading;//正在加载    private ILoadListener iLoadListener;    public DropLoadListView(Context context) {        super(context);        this.context = context;        initVew();        initEvent();    }    /**     * 事件监听     */    private void initEvent() {        this.setOnScrollListener(this);    }    public DropLoadListView(Context context, AttributeSet attrs) {        super(context, attrs);        this.context = context;        initVew();        initEvent();    }    public DropLoadListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        this.context = context;        initVew();        initEvent();    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()){            case MotionEvent.ACTION_MOVE:                if(!isLoading){                    //上拉                    this.requestDisallowInterceptTouchEvent(false);                    this.getParent().getParent().requestDisallowInterceptTouchEvent(true);                }else{                    //下滑                    this.requestDisallowInterceptTouchEvent(true);                    this.getParent().getParent().requestDisallowInterceptTouchEvent(false);                }                break;        }        return super.onTouchEvent(ev);    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        if(this.getAdapter().getCount()>1){            if (totalItemCount == lastItemCount && scrollState == SCROLL_STATE_IDLE) {                if (!isLoading) {                    isLoading = true;                    footer.findViewById(R.id.id_load_progressbar).setVisibility(View.VISIBLE);                    footer.findViewById(R.id.id_load_text).setVisibility(View.VISIBLE);                    iLoadListener.onLoad();                    //加载更多数据                }            }        }    }    /**     * @param view     * @param firstVisibleItem 当前屏幕上显示的第一个item的位置,初始为0     * @param visibleItemCount 当前屏幕上显示的item数     * @param totalItemCount   总共的item数     */    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {        this.lastItemCount = firstVisibleItem + visibleItemCount;        this.totalItemCount = totalItemCount;    }    /**     * 初始化     */    private void initVew() {        LayoutInflater layoutInflater = LayoutInflater.from(context);        footer = layoutInflater.inflate(R.layout.load, null);        //一开始隐藏        footer.findViewById(R.id.id_load_progressbar).setVisibility(View.GONE);        this.addFooterView(footer);    }    public void setInterface(ILoadListener iLoadListener){        this.iLoadListener=iLoadListener;    }    /**     * 加载更多数据的回调接口     */    public interface ILoadListener{        public void onLoad();    }    // 加载完成通知隐藏    public void loadComplete() {        isLoading = false;        footer.findViewById(R.id.id_load_progressbar).setVisibility(View.GONE);        footer.findViewById(R.id.id_load_text).setVisibility(View.GONE);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,                MeasureSpec.AT_MOST);        super.onMeasure(widthMeasureSpec, expandSpec);    }}

首先我们得先会自定义上拉加载的ListView,在这里我们不做过多的讲解,我们主要看如下方法:

public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()){            case MotionEvent.ACTION_MOVE:                if(!isLoading){                    //上拉                    this.requestDisallowInterceptTouchEvent(false);                    this.getParent().getParent().requestDisallowInterceptTouchEvent(true);                }else{                    //下滑                    this.requestDisallowInterceptTouchEvent(true);                    this.getParent().getParent().requestDisallowInterceptTouchEvent(false);                }                break;        }        return super.onTouchEvent(ev);    }

该方法是处理触摸事件的,我们通过判断此刻是否是上拉加载,然后进行事件分发处理。在此ListView中,我通过判断totalItemCount == lastItemCount && scrollState == SCROLL_STATE_IDLE是否满足条件,满足则代表我是上拉加载,此时设置isLoading=true,表示要加载,然后在触摸事件中判断是否要加载,如果是,则让当前view对该事件进行拦截,并让ScrollView不要拦截,让当前view消费此事件;如果不是上拉加载,即表示我要滑动整个ScrollView,让当前ListView不拦截,让ScrollView进行拦截,已达到此目的,在该模块处理时,最重要的方法就是requestDisallowInterceptTouchEvent(true),不允许拦截;requestDisallowInterceptTouchEvent(flase),允许拦截;;

效果

这里写图片描述
这里写图片描述

0 0