滚动ListView时,为什么在ListView中没有调用onLayout方法?

时间:2017-04-19 09:49:35

标签: android listview

编写自定义ListView,如:

public class MyListView extends ListView {
    public MyListView(Context context) {
        super(context);
    }

    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        Log.d("onLayout","onLayout=====");
    }
}

据我所知,当视图的布局属性发生变化时,为了应用更改(invalide()或requestLayout()),应调用其父级的onLayout方法并布置其子级。

因此,当我滚动ListView时,其子视图的布局属性已更改,但onLayout根本没有调用。为什么呢?

1 个答案:

答案 0 :(得分:0)

最后我意识到重新启动ViewGroup不需要总是调用onLayout()/ layout()方法。有很多方法可以在ViewGroup中更改视图位置,但每种方式都必须调用onDraw()来在FrameBuffer中写入更改的位置为了在屏幕上显示它。(请告诉我这是否错了) 在ListView中,我调试了源代码,当滚动ListView时,堆栈跟踪是: `

trackMotionScroll:5023, AbsListView (android.widget) 
scrollIfNeeded:3424, AbsListView (android.widget) 
startScrollIfNeeded:3352, AbsListView (android.widget) 
onTouchMove:3793, AbsListView (android.widget) 
onTouchEvent:3651, AbsListView (android.widget) 
dispatchTouchEvent:9294, View (android.view)

在trackMotionScroll中,它将调用ViewGroup#offsetChildrenTopAndBottom(incrementalDeltaY)

public void offsetChildrenTopAndBottom(int offset) {
    final int count = mChildrenCount;
    final View[] children = mChildren;
    boolean invalidate = false;

    for (int i = 0; i < count; i++) {
        final View v = children[i];
        v.mTop += offset;
        v.mBottom += offset;
        if (v.mRenderNode != null) {
            invalidate = true;
            v.mRenderNode.offsetTopAndBottom(offset);
        }
    }

    if (invalidate) {
        invalidateViewProperty(false, false);
    }
    notifySubtreeAccessibilityStateChangedIfNeeded();
}

这将导致ListView的重新映射。 所以我得出一个结论,你不需要服从框架的measure() - layout() - draw()程序,但只改变视图的布局属性并使其无效,它也会改变视图的布局。 而且我猜ListView在滚动时会省去layout()以提高效率