您的位置:首页 > 移动开发 > Android开发

Android源码初探之ListView 的 smoothScrollByOffset()

2017-01-13 17:56 591 查看
剧情:

前几天参加了去哪儿网的泛前段的分享会,谈的大多是去哪儿网对FaceBook的ReactNative的优化。谈到ListView的优化问题,大致意思是reactnative在不知道控件高度的情况下不容易直接根据Position找到控件的位置。不嫌事大的小伙伴问了个问题:

请问原声的Android是如何根据Position找到ListView的位置的呢?

答曰:

原声是可以直接根据位置找到的。

全场:嗯嗯嗯嗯~。

宝宝第一个不服,我就不感觉原声有这么厉害。

看了下ListView的方法,大概大神们说的是这个方法。

listview.smoothScrollToPosition(int position);


第一层的smoothScrollByOffset(int offset)仅仅是super了一下父类的方法。

public void smoothScrollByOffset(int offset) {
super.smoothScrollByOffset(offset);
}


里面是什么呢?

/**
* Allows RemoteViews to scroll relatively to a position.
*/
void smoothScrollByOffset(int position) {
int index = -1;
if (position < 0) {
index = getFirstVisiblePosition();//获取第一个可见的位置
} else if (position > 0) {
index = getLastVisiblePosition();
}

if (index > -1) {
View child = getChildAt(index - getFirstVisiblePosition());
if (child != null) {
Rect visibleRect = new Rect();//声明一个矩形
if (child.getGlobalVisibleRect(visibleRect)) {
// the child is partially visible
int childRectArea = child.getWidth() * child.getHeight();
int visibleRectArea = visibleRect.width() * visibleRect.height();
float visibleArea = (visibleRectArea / (float) childRectArea);
final float visibleThreshold = 0.75f;
if ((position < 0) && (visibleArea < visibleThreshold)) {
// the top index is not perceivably visible so offset
// to account for showing that top index as well
++index;
} else if ((position > 0) && (visibleArea < visibleThreshold)) {
// the bottom index is not perceivably visible so offset
// to account for showing that bottom index as well
--index;
}
}
smoothScrollToPosition(Math.max(0, Math.min(getCount(), index + position)));
}
}
}


大致意思是让一个比较远的View滚动到一个相对的位置。这个方法还是只进行了一些判断,包括上划下滑,最后一个可见区域如果不足百分之75 就取消掉等等。在进去一层。

public void smoothScrollToPosition(int position) {
if (mPositionScroller == null) {
mPositionScroller = createPositionScroller();
}
mPositionScroller.start(position);
}


貌似终于要开始滑动了。

再进去一层。

@Override
public void start(final int position) {
stop();

if (mDataChanged) {
// Wait until we're back in a stable state to try this.
mPositionScrollAfterLayout = new Runnable() {
@Override public void run() {
start(position);
}
};
return;
}

final int childCount = getChildCount();
if (childCount == 0) {
// Can't scroll without children.
return;
}

final int firstPos = mFirstPosition;
final int lastPos = firstPos + childCount - 1;

int viewTravelCount;
int clampedPosition = Math.max(0, Math.min(getCount() - 1, position));
if (clampedPosition < firstPos) {
viewTravelCount = firstPos - clampedPosition + 1;
mMode = MOVE_UP_POS;
} else if (clampedPosition > lastPos) {
viewTravelCount = clampedPosition - lastPos + 1;
mMode = MOVE_DOWN_POS;
} else {
scrollToVisible(clampedPosition, INVALID_POSITION, SCROLL_DURATION);
return;
}

if (viewTravelCount > 0) {
mScrollDuration = SCROLL_DURATION / viewTravelCount;
} else {
mScrollDuration = SCROLL_DURATION;
}
mTargetPos = clampedPosition;
mBoundPos = INVALID_POSITION;
mLastSeenPos = INVALID_POSITION;

postOnAnimation(this);
}


结合动画的源码,大致可以看出来,绝对不是不需要计算的,在源码中计算了每此需要滑动的距离,剩余的距离,滑动一格的时间,并且递归调用,直到到了指定的位置为止。

4000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 源码