博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
StaggeredGridView 实现分析--滑动处理(一)滑动位移
阅读量:5944 次
发布时间:2019-06-19

本文共 5640 字,大约阅读时间需要 18 分钟。

hot3.png

StaggeredGridView继承自ExtendableListView,同时ExtendableListView直接继承了AbsListView, 也就说它自己完成了item view的创建、销毁、更新、回收复用等环节。

ExtendableListView主要完成了一下功能逻辑:

滑动时更新可见view的layout(主要是x、y)动态回收由可见变为不可见的view, 填补空白区域, 

为了理解代码的逻辑,需要对一些变量做简单解释:

//记录变量意义, 一般item指adapter中的数据项, itemView指listview中的child view//第0个itemView对应的item的位置int mFirstPosition//当前点击的item位置int mMotionPosition//TouchDown事件发生时的y轴位置int mMotionY// 滑动距离纠正值,一般为0. // 在检测到touchTap(两个touchdown)但是还没有处理之前,或者在发生了TouchDown但是尚未检测到touchLong事件前, // 如果发生了移动(touchmove)事件并且移动的距离大于mTouchSlop,那么mMotionCorrection的值就等于sTouchSlop,// 同时这个touchmove会被当做scroll动作处理,scroll的距离等于实际距离(touchmove 与touchdown发生时的距离)减去这个纠正值int mMotionCorrection// 处理多手指触摸的情况,表示当前有效的pointer id。 // 假如当前屏幕有一个手指A,那么A的id就是mActivePointerId,后来又有另一个手指B按下了屏幕(发生ACTION_POINTER_DOWN事件)// 这时mActivePointerId更新为B的id, 此时A的滑动是无效的, 这是AbsListView的默认处理逻辑int mActivePointerId// 发生Action_Down时的y值。发生pointer_down、 pointer_up后会根据情况更新int mLastY

ExtendableListView对touch event做了过滤,可以响应tap等动作,具体过程可以参考其 ontouchEvent、onInterceptTouchEvent等方法。

我们从onTouchMove 开始看:

private boolean onTouchMove(final MotionEvent event) {        final int index = MotionEventCompat.findPointerIndex(event, mActivePointerId);        if (index < 0) {            ...            return false;        }        final int y = (int) MotionEventCompat.getY(event, index);        // our data's changed so we need to do a layout before moving any further        if (mDataChanged) {            layoutChildren();        }        switch (mTouchMode) {            case TOUCH_MODE_DOWN:            case TOUCH_MODE_TAP:            case TOUCH_MODE_DONE_WAITING:                // Check if we have moved far enough that it looks more like a                // scroll than a tap                startScrollIfNeeded(y);                break;            case TOUCH_MODE_SCROLLING:            //case TOUCH_MODE_OVERSCROLL:                scrollIfNeeded(y);                break;        }        return true;    }

TOUCH_MODE_XXX这些状态是在touch down 和 touch move事件处理逻辑中更新的,我们这里只关注滑动这一情景,

所以我们直接看TOUCH_MODE_SCROLLING就可以,但是在TOUCH_MODE_DONE_WATING情况下又进行了检测,

有可能从TOUCH_MODE_DONE_WATING状态转化为TOUCH_MODE_SCROLLING,

该过程可以从startScrollIfNeeded( final int y )中找到答案:

/**     * Starts a scroll that moves the difference between y and our last motions y     * if it's a movement that represents a big enough scroll.     */    private boolean startScrollIfNeeded(final int y) {        final int deltaY = y - mMotionY;        final int distance = Math.abs(deltaY);        // TODO : Overscroll?        // final boolean overscroll = mScrollY != 0;        final boolean overscroll = false;               // 如果移动了足够多的距离就把状态改为TOUCH_MODE_SCROLLING , 让scrollIfNeeded(final int y) 方法来处理        if (overscroll || distance > mTouchSlop) {            if (overscroll) {                mMotionCorrection = 0;            }            else {                mTouchMode = TOUCH_MODE_SCROLLING;                mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop;            }            final Handler handler = getHandler();            if (handler != null) {                handler.removeCallbacks(mPendingCheckForLongPress);            }            setPressed(false);            View motionView = getChildAt(mMotionPosition - mFirstPosition);            if (motionView != null) {                motionView.setPressed(false);            }            final ViewParent parent = getParent();            if (parent != null) {                parent.requestDisallowInterceptTouchEvent(true);            }            scrollIfNeeded(y);            return true;        }        return false;    }

最终TOUCH_MODE_SCROLLING状态是由 scrollIfNeeded(final int y) 方法处理的,其中的纠正值的意义已经在开始时解释过。

//响应 TOUCH_MODE_SCROLLING 状态private void scrollIfNeeded(final int y) {        final int rawDeltaY = y - mMotionY;        // 实际滑动距离减去纠正值        final int deltaY = rawDeltaY - mMotionCorrection;        int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;        if (mTouchMode == TOUCH_MODE_SCROLLING) {            if (DBG) Log.d(TAG, "scrollIfNeeded TOUCH_MODE_SCROLLING");            if (y != mLastY) {                // stop our parent                if (Math.abs(rawDeltaY) > mTouchSlop) {                    final ViewParent parent = getParent();                    if (parent != null) {                        parent.requestDisallowInterceptTouchEvent(true);                    }                }                final int motionIndex;                if (mMotionPosition >= 0) {                    motionIndex = mMotionPosition - mFirstPosition;                }                else {                    // If we don't have a motion position that we can reliably track,                    // pick something in the middle to make a best guess at things below.                    motionIndex = getChildCount() / 2;                }                // No need to do all this work if we're not going to move anyway                boolean atEdge = false;                if (incrementalDeltaY != 0) {                    atEdge = moveTheChildren(deltaY, incrementalDeltaY);                }                // Check to see if we have bumped into the scroll limit                View motionView = this.getChildAt(motionIndex);                if (motionView != null) {                    if (atEdge) {                        // TODO : edge effect & overscroll                    }                    mMotionY = y;                }                mLastY = y;            }        }        // TODO : ELSE SUPPORT OVERSCROLL!    }

scrollIfNeeded方法中调用了一个非常核心的方法 moveTheChildren, 该方法完成了动态更新子view的逻辑。

下一篇分析moveTheChildren 。

转载于:https://my.oschina.net/u/255456/blog/343575

你可能感兴趣的文章
关于缓存命中率的几个关键问题!
查看>>
oracle中create table with as和insert into with as语句
查看>>
kafka连接异常
查看>>
11g废弃的Hint - BYPASS_UJVC
查看>>
为什么工业控制系统需要安全防护?
查看>>
Mongodb部署记录[3]-主从搭建
查看>>
hive sql操作
查看>>
tomcat 深度优化
查看>>
127 - "Accordian" Patience
查看>>
阿里云CentOS7安装Oracle11GR2
查看>>
nginc+memcache
查看>>
php正则匹配utf-8编码的中文汉字
查看>>
MemCache在Windows环境下的搭建及启动
查看>>
linux下crontab实现定时服务详解
查看>>
返回顶部JS
查看>>
Numpy中的random模块中的seed方法的作用
查看>>
史上最全的数据库面试题,不看绝对后悔
查看>>
用java数组模拟登录和注册功能
查看>>
javaScript实现归并排序
查看>>
关于jsb中js与c++的相互调用
查看>>