先从setSelection(int)方法开始讲吧
@Override
public void setSelection(int position) {
// 很简单,就调用了setSelectionFromTop方法
setSelectionFromTop(position, 0);
}
接着看看AbsListView.setSelectionFromTop(int, int)方法:
// position:所选item在数据源中的索引
// y:指定所选item距离AbsListView顶部的距离。最终item与顶部的距离还会在y的基础上将padding值计算进去
public void setSelectionFromTop(int position, int y) {
if (mAdapter == null) {
// mAdapter为null,直接返回吧。。
return;
}
// isInTouchMode()方法返回true表示用户正在操作屏幕
if (!isInTouchMode()) {
// 由于并不是所有的item都是可选的,以及考虑到adapter有可能为null,position的合理性,因此调用lookForSelectablePosition来寻找可选的position
position = lookForSelectablePosition(position, true);
if (position >= 0) {
// 设置mNextSelectedPosition和mNextSelectedRowId
// setNextSelectedPositionInt(int)方法中其实还有mSyncPosition和mSyncRowId需要注意
// 不过由于mNeedSync只有在数据源改变,或者onRestoreInstanceState方法中使能,因此暂时不去理会
setNextSelectedPositionInt(position);
}
} else {
// reconcileSelectedPosition和resurrectSelection方法中使用到
mResurrectToPosition = position;
}
if (position >= 0) {
// 在layout中会因不同mLayoutMode值,布局方式有所区别
mLayoutMode = LAYOUT_SPECIFIC;
// mSpecificTop记录position对应的item与AbsListView顶部之间的距离,该变量在layout的时候会用到
mSpecificTop = mListPadding.top + y;
// 暂时不理会
if (mNeedSync) {
mSyncPosition = position;
mSyncRowId = mAdapter.getItemId(position);
}
// mPositionScroller是一个AbsPositionScroller抽象类的实例,负责AbsListView的position之间的平滑滚动过度,AbsListView.smoothScrollToXXX系列方法就是通过该工具类实现的。在设置selection的时候先停止该滚动事件。
if (mPositionScroller != null) {
mPositionScroller.stop();
}
// 请求重新布局
requestLayout();
}
}
稍微了解下ListView.lookForSelectablePosition(int,boolean)方法:
@Override
int lookForSelectablePosition(int position, boolean lookDown) {
final ListAdapter adapter = mAdapter;
if (adapter == null || isInTouchMode()) {
// INVALID_POSITION的值为-1
return INVALID_POSITION;
}
final int count = adapter.getCount();
// mAreAllItemsSelectable默认为true,不过会根据header、footer以及Adapter.areAllItemsEnabled()方法来重新设置
if (!mAreAllItemsSelectable) {
if (lookDown) {
// 向下找,positon累加
position = Math.max(0, position);
while (position < count && !adapter.isEnabled(position)) {
position++;
}
} else {
// 向上找,position递减
position = Math.min(position, count - 1);
while (position >= 0 && !adapter.isEnabled(position)) {
position--;
}
}
}
if (position < 0 || position >= count) {
// 非法的position返回-1
return INVALID_POSITION;
}
return position;
}
好了,接下来看看ListView.onMeasure(int,int)方法吧:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(int,int)方法主要是添加Selector的padding值到mListPadding中,mListPadding是一个Rect类记录了ListView个个方向的padding值
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获取宽高的mode和size
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMe