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

问题

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值