一,准备知识:
1,View的绘制流程。
该文将从View的绘制流程:onMesure() --> onLayout() -->onDraw()。这一流程分析。
扩展阅读:Android中View绘制流程
2,requestLayout()方法。
会导致调用measure()过程 和 layout()过程 。说明:只是对View树重新布局layout过程包括measure()和layout()过程,不会调用draw()过程,但不会重新绘制任何视图包括该调用者本身。
3,invalidate()方法。
请求重绘View树,即draw()过程,假如视图发生大小没有变化就不会调用layout()过程,并且只绘制那些“需要重绘的”视图,即谁(View的话,只绘制该View ;ViewGroup,则绘制整个ViewGroup)请求invalidate()方法,就绘制该视图。
4,AbsListView类。
ExtendableListView继承自AbsListView,该类重写了draw(),和dispatchDraw()方法,所以ExtendableListView只需重写onMesure()和onLayout()即可。
二,ExtendableListView类
核心类,该类继承自AbsListView。重写了AbsListView类的onMesure()和onLayout()方法,
1,ExtendableListView()构造方法。
- public ExtendableListView(final Context context, final AttributeSet attrs, final int defStyle) {
- super(context, attrs, defStyle);
- // setting up to be a scrollable view group
- setWillNotDraw(false);
- setClipToPadding(false);
- setFocusableInTouchMode(false);
- final ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
- mTouchSlop = viewConfiguration.getScaledTouchSlop();
- mMaximumVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
- mFlingVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
- mRecycleBin = new RecycleBin();
- mObserver = new AdapterDataSetObserver();
- mHeaderViewInfos = new ArrayList<FixedViewInfo>();
- mFooterViewInfos = new ArrayList<FixedViewInfo>();
- // start our layout mode drawing from the top
- mLayoutMode = LAYOUT_NORMAL;
- }
1.1 setWillNotDraw(false)
调用这句话的方法的作用是防止我们重写的onDraw()方法不被调用,可以看官方的注释
If this view doesn't do any drawing on its own, set this flag to allow further optimizations. By default, this flag is not set on View, but could be set on some View subclasses such as ViewGroup.Typically, if you override {@link #onDraw(android.graphics.Canvas)}you should clear this flag.
中文意思是:如果没有在View上画任何东西,则需要设置这个标示以可以进一步的优化绘画。默认情况下,在View上是不会设置这个标示的,但是可以在View的子类上设置
如ViewGroup。通常情况下,如果你重写了onDraw这个方法,你需要清楚这个标示。
1.2 setClipToChilren(false)
用来定义ViewGroup是否允许在padding中绘制。默认情况下,cliptopadding被设置为ture, 也就是把padding中的值都进行裁切了
扩展阅读:用android:clipChildren来实现边界绘制
1.3 RecycleBin类
item缓存类,这个和AbsListView 中的RecycleBin 一样,只是少了RecyclerListener,
The data set used to store unused views that should be reused during the next layout to avoid creating new ones
大概意思是:这个数据集合是用来存储没有使用的views的,是为了避免重复创建这些新的views,这样在下一次布局的时候这些些views可以被重用。
The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of
storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the
start of a layout. By construction, they are displaying current information. At the end of
layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that
could potentially be used by the adapter to avoid allocating views unnecessarily.
大概意思是:这个类是用来帮助在滑动布局时重用View的,这个RecyleBin 有两个级别的存储分别是ActiveViews和ScrapViews,mActiveViews是一个View类型的数组,存储的是那些显示在屏幕上的views。ScrapViews是一个ArrayList<View>类型的数组,存储的是那些已经废弃的不是显示在屏幕上的views,这些views都有可能被adapter使用避免分配失败。在布局结束的时候,mActiveViews存储的views都降级为ScrapViews。
扩展阅读:
Android AdapterView View的复用机制 分析
2,onAttachedToWindow()和onDetachedFromWindow()方法。
<span style="font-size:14px;">@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mAdapter != null) {
// Data may have changed while we were detached. Refresh.
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
}
mIsAttached = true;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Detach any view left in the scrap heap
mRecycleBin.clear();
if (mFlingRunnable != null) {
removeCallbacks(mFlingRunnable);
}
mIsAttached = false;
}</span>
扩展阅读:
Android重写view时onAttachedToWindow () 和 onDetachedFromWindow ()
3,setAdapter()方法
@Override
public void setAdapter(final ListAdapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
}
// use a wrapper list adapter if we have a header or footer
if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
}
else {
mAdapter = adapter;
}
mDataChanged = true;
mItemCount = adapter != null ? adapter.getCount() : 0;
if (adapter != null) {
adapter.registerDataSetObserver(mObserver);
mRecycleBin.setViewTypeCount(adapter.getViewTypeCount());
}
requestLayout();
}