Android开发Android知识Android技术知识

Android-同向滑动冲突

2016-10-17  本文已影响479人  c37d344afd22

惯例上图

好久没写文章了,最近弄了一个小需求,就是ScrollView里嵌套ListView,当然ListView是固定高度并且要求能上下滑动,而且在滑动到顶部或者底部的时候由ScrollView来拦截滑动事件。这也就是我们说的同向滑动冲突。

什么时候拦截?

上面我们已经说了,滑动到顶部或者底部的时候拦截

如何判断已经滑动到了顶部或者底部?

我们知道无论是ListView还是RecyclerView都是复用机制,啥是复用机制都不知道那我推荐你看看关于这类的文章。由于是复用,那么我们就不能直接用ListView.getChildAt(X)来获取,所以我们要根据系统提供给我们的方法来获取顶部和底部的View,然后通过这两个View来判断是否达到了顶部或者底部

获取顶部和底部的View

    lv.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {


        }


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

            /**
             * 从这里获取最后一个item的View和第一个item的View
             */
            lastView = view.getChildAt(totalItemCount - firstVisibleItem - 1);
            firstView = view.getChildAt(firstVisibleItem);


        }
    });

判断是否达到顶端或者底端

int action = motionEvent.getAction();
if (action == MotionEvent.ACTION_DOWN) {
    lastY = (int) motionEvent.getY();
} else if (action == MotionEvent.ACTION_MOVE) {
    /**
     * 这里判断是向下还是向上滑动
     */
    if (lastY > motionEvent.getY()) {
        isDown = true;
        isUp = false;
    } else {
        isDown = false;
        isUp = true;
    }
}

if (lv != null) {
    if (firstView != null && isUp) {
        /**
         * 如果ListView已经初始化并且firstView不为空
         * 而且不是第一次加载视图(因为第一次加载视图getTop肯定为0)并且向上滑动
         *
         */
        if (firstView.getTop() == 0) {
            flag = true;
        } else {
            flag = false;
        }
    }
    if (lastView != null && isDown) {
        /**
         * 这里判断坐标,如果lastView的Bottom等于这个ListView的高度并且是往下滑
         * 则把flag设置为true,当然这里还有一个坑,因为ListView是固定高度,所以所有的item高度之和都没有达到ListView的高度,那么这个也需要判断一下
         */

        int childHeight = lv.getChildAt(0).getHeight();
        int childCount = lv.getChildCount();
        int totalChildHeight = childHeight * childCount;

        if ((lastView.getBottom()) == view.getHeight() || totalChildHeight < view.getHeight()) {
            flag = true;
        } else {
            flag = false;
        }
        isFirst = false;
    }
}

这里我们还需要判断一下手势,达到了顶端并且是往上滑,达到了底部并且往下滑。

当然这里还有一个坑,那就是我们刚家在布局的时候getTop()是肯定等于0的,所以我们要判断一下是否是第一次加载

最后我们通过flag来判断一下是否让ScrollView来拦截事件

/**
 * flag 为 true的时候 ScrollView开始获得事件
 */
if (flag && !isFirst) {
    sv.requestDisallowInterceptTouchEvent(false);
} else {
    sv.requestDisallowInterceptTouchEvent(true);
}

这样一来也就结束了,放上全部代码

public class MainActivity extends AppCompatActivity {

    List<String> mData;
    ListView lv;
    ArrayAdapter<String> adapter;
    ScrollView sv;
    boolean flag, isFirst = true;
    boolean isUp, isDown;
    int lastY;
    View lastView, firstView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mData = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            mData.add("ad " + i);
        }

        tv1 = (TextView) findViewById(R.id.tv1);
        sv = (ScrollView) findViewById(R.id.sv);
        lv = (ListView) findViewById(R.id.lv);
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, mData);
        lv.setAdapter(adapter);

        lv.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                sv.requestDisallowInterceptTouchEvent(true);

            int action = motionEvent.getAction();
            if (action == MotionEvent.ACTION_DOWN) {
                lastY = (int) motionEvent.getY();
            } else if (action == MotionEvent.ACTION_MOVE) {
                /**
                 * 这里判断是向下还是向上滑动
                 */
                if (lastY > motionEvent.getY()) {
                    isDown = true;
                    isUp = false;
                } else {
                    isDown = false;
                    isUp = true;
                }
            }
    
            if (lv != null) {
                if (firstView != null && isUp) {
                    /**
                     * 如果ListView已经初始化并且firstView不为空
                     * 而且不是第一次加载视图(因为第一次加载视图getTop肯定为0)并且向上滑动
                     *
                     */
                    if (firstView.getTop() == 0) {
                        flag = true;
                    } else {
                        flag = false;
                    }
                }
                if (lastView != null && isDown) {
                    /**
                     * 这里判断坐标,如果lastView的Bottom等于这个ListView的高度并且是往下滑
                     * 则把flag设置为true
                     */
    
                    int childHeight = lv.getChildAt(0).getHeight();
                    int childCount = lv.getChildCount();
                    int totalChildHeight = childHeight * childCount;
    
                    if ((lastView.getBottom()) == view.getHeight() || totalChildHeight < view.getHeight()) {
                        flag = true;
                    } else {
                        flag = false;
                    }
                    isFirst = false;
                }
            }


                /**
                 * flag 为 true的时候 ScrollView开始获得事件
                 */
                if (flag && !isFirst) {
                    sv.requestDisallowInterceptTouchEvent(false);
                } else {
                    sv.requestDisallowInterceptTouchEvent(true);
                }


                return false;
            }
        });

        lv.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {


            }


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

                /**
                 * 从这里获取最后一个item的View和第一个item的View
                 */
                lastView = view.getChildAt(totalItemCount - firstVisibleItem - 1);
                firstView = view.getChildAt(firstVisibleItem);


            }
        });
    }
}

最后

爱小丽,爱Android

上一篇 下一篇

猜你喜欢

热点阅读