Android Widget源码分析系列文章之AbsListView
AbsListView的源码剖析
这是一个基本的类,可以被用来实现虚拟化的列表。一个列表没有一个空间的定义在这里。例如,这个类的子类展示了列表的内容以九宫格、旋转木马或者是堆栈。
继承的类
AdapterView
实现的接口
- TextWatcher ,监听字符的变化
- ViewTreeObserver.OnGlobalLayoutListener,OnGlobalLayoutListener 是ViewTreeObserver的内部类,当一个视图树的布局发生改变时,可以被ViewTreeObserver监听到,这是一个注册监听视图树的观察者(observer),在视图树的全局事件改变时得到通知。ViewTreeObserver不能直接实例化,而是通过getViewTreeObserver()获得。
- Filter.FilterListener,用一个过滤的模式,约束输入的字符的内容,内部的函数是通知过滤操作的结束。
- ViewTreeObserver.OnTouchModeChangeListener,注册一个观察者来监听视图树,当视图树的布局、视图树的焦点、视图树将要绘制、视图树滚动等发生改变时,ViewTreeObserver都会收到通知,ViewTreeObserver不能被实例化,可以调用View.getViewTreeObserver()来获得。
- RemoteViewAdapter.RemoteAdapterConnectionCallback,一个接口针对RemoteAdapter 去通知其他的类当这个Adapters被真正的连接到他们真实的服务,或者是真实的解除连接。
相关的成员变量
逐一的对这个类中的定义的成员变量进行定义,基本意思以及功能作用。
- TRANSCRIPT_MODE_DISABLED, 这是一个public类型修饰的常量。表面的意思是禁止文字记录的模式,实际上的意思是不允许自动滚动到用户指定的位置。
- TRANSCRIPT_MODE_NORMAL,这是public类型修饰的常量。这个列表将会自动滚动到底部,当一个数据集合改变的通知被收到,并且只有这个最后一个条目在屏幕上是真实可见的时候。
- TRANSCRIPT_MODE_ALWAYS_SCROLL,这是public类型修饰的常量。这个列表将会自动滚动到底部,不论当前屏幕上可见的条目是什么。
- TOUCH_MODE_REST,预测我们并不是处于手指触摸的中间。
- TOUCH_MODE_DONE_WAITING,预测我们已经等待每一件我们能够等待的事情。但是这个用户的手指始终是出于按下的状态。
- TOUCH_MODE_SCROLL,预测用户的手指是处于滚动的状态。
- TOUCH_MODE_FLING,预测当前的视图是处于被翻动的状态。
- TOUCH_MODE_OVERSCROLL,预测这个手势是过度的滚动,是一种滚动超过了开始或者是结束。
- TOUCH_MODE_OVERFLING,达到了边缘,并且绘制回弹的效果。
- LAYOUT_NORMAL,普通的布局,经常一个来自于视图系统的没有请求的布局。
- LAYOUT_FORCE_TOP,显示第一个条目。
- LAYOUT_SET_SELECTION ,强制选中的条目到屏幕指定的位置。
- LAYOUT_FORCE_BOTTOM,显示最后一个条目。
- LAYOUT_SPECIFIC,创建一个选中的条目,呈现在一个指定的位置,并且构建这个视图的剩余的部分从这里开始。这个顶部是被特殊的指定。
- LAYOUT_SYNC,布局与数据的改变同步发生了变化,恢复同步的位置,去让他的顶部在他指定的位置。
- LAYOUT_MOVE_SELECTION,布局作为使用航海的钥匙的结果。
- CHOICE_MODE_NONE,普通的列表,没有预测的选择。
- CHOICE_MODE_SINGLE,列表支持一个选择。
- CHOICE_MODE_MULTIPLE,列表支持多个选择。
- CHOICE_MODE_MULTIPLE_MODAL,这个列表支持多个选择在一个模态的选择模式。
- mOwnerThread,对应的是视图被创建的线程。
- mChoiceMode,控制是否/怎样这个用户也许选择/检测在列表中的条目。
- mCheckedItemCount,当前有多少列表的条目被选中。
- mDrawSelectorOnTop,预测是否这个列表的选择器应该绘制在子节点顶部还是底部。
- mSelector,图片用来绘制选择器。
- mSelectorPosition,当前被选中的条目在列表中的位置。
- mRecycler,这个数据集合用来存储没有被使用的视图,这些视图在接下来的布局中可能被用到,避免创建新的视图的对象。
- mVelocityTracker,决定了滚动的速度。
- mScrollingCacheEnabled,当设置位true, 这个列表将会自动丢弃子视图的缓存,当滚动的时候。
- mSmoothScrollbarEnabled,判断是基于像素的滚动,还是基于条目的滚动。
- mFastScroll,帮助类的对象绘制和控制快速滚动的滑块。
内部定义的接口
OnScrollListener
- SCROLL_STATE_IDLE,视图当前处于静止的状态。
- SCROLL_STATE_TOUCH_SCROLL,用户通过触摸滚动视图,并且用户当前的手指还是处于屏幕上。
- SCROLL_STATE_FLING,用户之前已经通过触摸,操作了一次滑动,当前处于滑动状态,即将停止。
- onScrollStateChanged,回调方法将会被触发,当列表视图或者是九宫格的视图被滚动。这个方法将会被调用当滚动的视图的下一个数据帧将会被绘制。
- onScroll,当滚动行为结束后被调用。
SelectionBoundsAdjuster
- adjustListItemSelectionBounds,允许列表的条目去调整他被选中的矩形的边界。
构造函数
- initAbsListView, 初始化列表的相关的组件。
- mOwnerThread = Thread.currentThread(),创建当前UI操作所在的线程。
- setVerticalScrollBarEnabled(true),设置允许显示垂直的滚动条。
- initializeScrollbarsInternal,初始化垂直的滚动条的内部的业务逻辑。
成员函数
initAbsListView
- 代码片段
// Setting focusable in touch mode will set the focusable property to true
setClickable(true);
setFocusableInTouchMode(true);
setWillNotDraw(false);
setAlwaysDrawnWithCacheEnabled(false);
setScrollingCacheEnabled(true);
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
mOverscrollDistance = configuration.getScaledOverscrollDistance();
mOverflingDistance = configuration.getScaledOverflingDistance();
mDensityScale = getContext().getResources().getDisplayMetrics().density;
- setClickable(true),设置当前的UI是可以被点击的
- setFocusableInTouchMode(true),设置当前的UI在触摸的模式下是可以获取焦点的。
- setWillNotDraw,如果这个View控件在他自己的内部没有做任何的绘制,设置这个标志位允许以后的优化。
- setAlwaysDrawnWithCacheEnabled,预测是否这个ViewGroup是否将会总是尝试绘制它的子节点使用它们自己的缓存。这个属性可以被设置位true,当这个缓存的渲染略微不同于子节点的正常的渲染。渲染是可以不同的,比如,当这个缓存的品质被设置为低。当设置属性是被禁用,这个ViewGroup将会使用它的子节点的绘制的缓存,仅仅当被询问的时候。这个是它的子类的任务去告诉ViewGroup什么时候开始使用这个绘制的缓存,以及什么时候停止使用。
- 剩下的几个属性的初始化,包括触摸的阈值、最小以及最大的速度、滑动的最大的区间以及分辨率的初始化。
setOverScrollMode
在这个函数中,判断是否允许用户滑动超过边界,这也就决定了mEdgeGlowTop以及mEdgeGlowBottom是否进行初始化。
performItemClick
contentFits
返回true,如果列表的内容当前完全是在视图的边界内。
setFastScrollAlwaysVisible
设置是否这个快速的缓动应该被展示,而不是标准的滑动块。这将决定了是否允许使用快速滑动。
if (isOwnerThread()) {
setFastScrollerAlwaysVisibleUiThread(alwaysShow);
} else {
post(new Runnable() {
@Override
public void run() {
setFastScrollerAlwaysVisibleUiThread(alwaysShow);
}
});
}
逻辑上的线程切换,值得代码的借鉴。
pointToPosition
将一个坐标点转换位一个列表的条目的索引。
public int pointToPosition(int x, int y) {
Rect frame = mTouchFrame;
if (frame == null) {
mTouchFrame = new Rect();
frame = mTouchFrame;
}
final int count = getChildCount();
for (int i = count - 1; i >= 0; i--) {
final View child = getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
child.getHitRect(frame);
if (frame.contains(x, y)) {
return mFirstPosition + i;
}
}
}
return INVALID_POSITION;
}