ListView的测量
onMeasure
1 | /** |
measureHeightofChildren
1 | /** |
ListView的生成
一般流程
1 | abslistView:onLayout-> |
onLayout
1 | /** |
layoutChildren
1 | /** |
fillFromTop
1 | /** |
fillDown
1 | /** |
makeAndAddView
1 | /** |
setupChild
1 | /** |
addViewInLayout
1 | /** |
回收机制
RecycleBin
背景
1 | The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of |
关键参数
1 | /** |
关键方法
1 |
|
recycle模型
onTouchEvent事件的处理
一般流程
1 | AbsListView: |
trackMotionScroll
1 | /** |
fillGap
1 | /** |
velocityTracker
背景
1 | 手势速度判断的工具类。 |
obtain
1 | private static final SynchronizedPool<VelocityTracker> sPool = |
computerCureentVelocity
1 | /** |
GestureDetector
背景
1 | MotionEevent分析工具类 |
NestedScrolling
背景
1 | 痛点:如果子view获得处理touch事件机会的时候,父view就再也没有机会去处理这个touch事件了,直到下一次手指再按下 |
关于ListView的处理
1 | View (rolePlayer as children) |
google的再次抽象
1 | NestedScrollingParent 父容器实现接口 |
Interpolator
背景
1 | matlab里有一个插值的概念,而在手机app中有很多加速或者减速的运动,需要再相同的时间间隔内获取不同的间距 |
getInterpolation
1 |
|
ListView点击事件
为什么点击失效了
WHAT
在Listview的Item里面有一个Button,那么这个item的点击事件往往不会被触发到
HOW
在Item的根布局上增加,android:descendantFocusability=”blocksDescendants”
WHY
Descendant
焦点管理
1
2
3requestFocus ->
requestFocusNoSearch ->
handleFocusGainInternal -> (dispatchOnGlobalFocusChange,onFocusChanged,refreshDrawableState)requestFocusNoSearch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
// need to be focusable
if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE ||
(mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
// need to be focusable in touch mode if in touch mode
if (isInTouchMode() &&
(FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
return false;
}
//the xml tag works here
// need to not have any parents blocking us
if (hasAncestorThatBlocksDescendantFocus()) {
return false;
}
handleFocusGainInternal(direction, previouslyFocusedRect);
return true;
}handleFocusGainInternal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41/**
*Three things to do
* 1.onFocusChange
* 2.dispatchFocusChange
* 3.refreshDrawableState
* Give this view focus. This will cause
* {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called.
*
* Note: this does not check whether this {@link View} should get focus, it just
* gives it focus no matter what. It should only be called internally by framework
* code that knows what it is doing, namely {@link #requestFocus(int, Rect)}.
*
* @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
* {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which
* focus moved when requestFocus() is called. It may not always
* apply, in which case use the default View.FOCUS_DOWN.
* @param previouslyFocusedRect The rectangle of the view that had focus
* prior in this View's coordinate system.
*/
void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) {
if (DBG) {
System.out.println(this + " requestFocus()");
}
if ((mPrivateFlags & PFLAG_FOCUSED) == 0) {
mPrivateFlags |= PFLAG_FOCUSED;
View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null;
if (mParent != null) {
mParent.requestChildFocus(this, this);
}
if (mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);
}
onFocusChanged(true, direction, previouslyFocusedRect);
refreshDrawableState();
}
}
ItemOnClick事件
处理流程
1
2
3abslistView:onTouchEvent()
->onTouchUp()
->PerformClick.run()onTouchUp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22private void onTouchUp(MotionEvent ev) {
switch (mTouchMode) {
case TOUCH_MODE_DOWN:
case TOUCH_MODE_TAP:
case TOUCH_MODE_DONE_WAITING:
final int motionPosition = mMotionPosition;
final View child = getChildAt(motionPosition - mFirstPosition);
if (child != null) {
if (mTouchMode != TOUCH_MODE_DOWN) {
child.setPressed(false);
}
final float x = ev.getX();
final boolean inList = x > mListPadding.left && x < getWidth() - mListPadding.right;
// here to decide to invoke which child
if (inList && !child.hasFocusable()) {
//.......
}
break;
case TOUCH_MODE_SCROLL:
//......
}
扩展功能
阻尼效果
背景
1 | ios 在系统层面上实现了触碰边缘的阻尼回弹效果,通知用户已经到达了边界。但是由于专利的问题,android在无法在系统层面上使用统一的效果,但是通过了一个渐变的颜色来告知用户已经到达了边界状态 |
How to Invoke
1 | AbsListView:onTouchEvent-> |
overScrollBy
1 | /** |
Android的原生阻尼
1 | /** |
EdgeEeffect
1 | /** |
SwipeRefreshLayout下拉刷新/上拉加载更多
how to create
contruction
1 | /** |
onMeasure
1 | /** |
onLayout
1 | /** |
touchEvent&&stateChange
onInterceptTouchEvent
1 | /** |
onTouchEvent
1 |
|
add header and footer yourself
用progressView一样的方式去添加
construction
1 | public SwipeRefreshLayout(Context context, AttributeSet attrs) { |
onMeasure
1 |
|
onLayout
1 |
|
notify pull and push Action
如何判断到顶部或者底部
1 |
|
add secondFloor
abstract the headerView
you can add other three states in the headerView .eg:readyEnter,startEnter,endEnter.
And use the headerView to manager all the states.
pull Action can be separated into two states
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18private boolean handlePullTouchEvent(MotionEvent ev, int action) {
......
case MotionEvent.ACTION_MOVE: {
......
if(mIsBeingDragged) {
distance = (int) (distance * mDragRate);
......
if (distance < mTotalDragDistance) {
// do refresh action
} else {
//do second floor action
}
break;
}
......
}
}