Listview源码分析(1)
public ListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);//TypedArray实例是个属性的容器,context.obtainStyledAttributes()方法返回得到final TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ListView, defStyleAttr, defStyleRes);//从属性处初始化值CharSequence[] entries = a.getTextArray(com.android.internal.R.styleable.ListView_entries);//如果值不为null,shezhi moren de buju fangshiif (entries != null) {setAdapter(new ArrayAdapter<CharSequence>(context,com.android.internal.R.layout.simple_list_item_1, entries));}//系统自带的风格线final Drawable d = a.getDrawable(com.android.internal.R.styleable.ListView_divider);if (d != null) {// If a divider is specified use its intrinsic height for divider heightsetDivider(d);}//设置listview头部final Drawable osHeader = a.getDrawable(com.android.internal.R.styleable.ListView_overScrollHeader);if (osHeader != null) {setOverscrollHeader(osHeader);}//设置listview底部final Drawable osFooter = a.getDrawable(com.android.internal.R.styleable.ListView_overScrollFooter);if (osFooter != null) {setOverscrollFooter(osFooter);}//设置listview Item的间距final int dividerHeight = a.getDimensionPixelSize(com.android.internal.R.styleable.ListView_dividerHeight, 0);if (dividerHeight != 0) {setDividerHeight(dividerHeight);}mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);a.recycle();}
public int getMaxScrollAmount() {return (int) (MAX_SCROLL_FACTOR * (mBottom - mTop));}
private void adjustViewsUpOrDown() {final int childCount = getChildCount();int delta;if (childCount > 0) {View child;if (!mStackFromBottom) {// Uh-oh -- we came up short. Slide all views up to make them// align with the topchild = getChildAt(0);delta = child.getTop() - mListPadding.top;if (mFirstPosition != 0) {// It's OK to have some space above the first item if it is// part of the vertical spacingdelta -= mDividerHeight;}if (delta < 0) {// We only are looking to see if we are too low, not too highdelta = 0;}} else {// we are too high, slide all views down to align with bottomchild = getChildAt(childCount - 1);delta = child.getBottom() - (getHeight() - mListPadding.bottom);if (mFirstPosition + childCount < mItemCount) {// It's OK to have some space below the last item if it is// part of the vertical spacingdelta += mDividerHeight;}if (delta > 0) {delta = 0;}}if (delta != 0) {offsetChildrenTopAndBottom(-delta);}}}接下来是添加头部的方法;为ListView顶部添加一个固定的View,如果HeaderView多于一个,会按照添加的顺序进行排列:public void addHeaderView(View v, Object data, boolean isSelectable) {final FixedViewInfo info = new FixedViewInfo();info.view = v;info.data = data;info.isSelectable = isSelectable;mHeaderViewInfos.add(info);mAreAllItemsSelectable &= isSelectable;// Wrap the adapter if it wasn't already wrapped.if (mAdapter != null) {if (!(mAdapter instanceof HeaderViewListAdapter)) {mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);}// In the case of re-adding a header view, or adding one later on,// we need to notify the observer.if (mDataSetObserver != null) {mDataSetObserver.onChanged();}}}
public void addHeaderView(View v) {addHeaderView(v, null, true);}@Overridepublic int getHeaderViewsCount() {return mHeaderViewInfos.size();}
public boolean removeHeaderView(View v) {//如果头部信息的list>0,并且Adapter不为null,删除头部信息,并进行回调if (mHeaderViewInfos.size() > 0) {boolean result = false;if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeHeader(v)) {if (mDataSetObserver != null) {mDataSetObserver.onChanged();}result = true;}//调用下面删除指定view的操作removeFixedViewInfo(v, mHeaderViewInfos);return result;}return false;}这是找到对应的view进行删除操作:
private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) { int len = where.size(); for (int i = 0; i < len; ++i) { FixedViewInfo info = where.get(i); if (info.view == v) { where.remove(i); break; } } }/** * Add a fixed view to appear at the bottom of the list. If addFooterView is * called more than once, the views will appear in the order they were * added. Views added using this call can take focus if they want. * <p> * NOTE: Call this before calling setAdapter. This is so ListView can wrap * the supplied cursor with one that will also account for header and footer * views. * * @param v The view to add. * @param data Data to associate with this view * @param isSelectable true if the footer view can be selected */ public void addFooterView(View v, Object data, boolean isSelectable) { // NOTE: do not enforce the adapter being null here, since unlike in // addHeaderView, it was never enforced here, and so existing apps are // relying on being able to add a footer and then calling setAdapter to // force creation of the HeaderViewListAdapter wrapper FixedViewInfo info = new FixedViewInfo(); info.view = v; info.data = data; info.isSelectable = isSelectable; mFooterViewInfos.add(info); // in the case of re-adding a footer view, or adding one later on, // we need to notify the observer if (mAdapter != null && mDataSetObserver != null) { mDataSetObserver.onChanged(); } } /** * Add a fixed view to appear at the bottom of the list. If addFooterView is called more * than once, the views will appear in the order they were added. Views added using * this call can take focus if they want. * <p>NOTE: Call this before calling setAdapter. This is so ListView can wrap the supplied * cursor with one that will also account for header and footer views. * * * @param v The view to add. */ public void addFooterView(View v) { addFooterView(v, null, true); }@Override public int getFooterViewsCount() { return mFooterViewInfos.size(); }/** * Removes a previously-added footer view. * * @param v The view to remove * @return * true if the view was removed, false if the view was not a footer view */ public boolean removeFooterView(View v) { if (mFooterViewInfos.size() > 0) { boolean result = false; if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeFooter(v)) { if (mDataSetObserver != null) { mDataSetObserver.onChanged(); } result = true; } removeFixedViewInfo(v, mFooterViewInfos); return result; } return false; } /** * Returns the adapter currently in use in this ListView. The returned adapter * might not be the same adapter passed to {@link #setAdapter(ListAdapter)} but * might be a {@link WrapperListAdapter}. *返回listview当前正在使用的Adapter,adapter不一定是通过setAdapter方法传入的adapter,有可能是一个WrapperListAdapter * @return The adapter currently used to display data in this ListView. * * @see #setAdapter(ListAdapter) */ @Override public ListAdapter getAdapter() { return mAdapter; }/** * Sets the data behind this ListView. * * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter}, * depending on the ListView features currently in use. For instance, adding * headers and/or footers will cause the adapter to be wrapped. * 通过setAdapter方法添加的adapter根据当前ListView的使用情况可能被装饰为一个WrapperListAdapter,比如说添加一个HeaderView或者FooterView。
在该方法中,先把以前的数据和观察者去掉,然后再重新设置各种参数
* @param adapter The ListAdapter which is responsible for maintaining the * data backing this list and for producing a view to represent an * item in that data set. * * @see #getAdapter() */ @Override public void setAdapter(ListAdapter adapter) { if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } resetList(); mRecycler.clear(); if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; // AbsListView#setAdapter will update choice mode states. super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver); mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); int position; if (mStackFromBottom) { position = lookForSelectablePosition(mItemCount - 1, false); } else { position = lookForSelectablePosition(0, true); } setSelectedPositionInt(position); setNextSelectedPositionInt(position); if (mItemCount == 0) { // Nothing selected checkSelectionChanged(); } } else { mAreAllItemsSelectable = true; checkFocus(); // Nothing selected checkSelectionChanged(); } requestLayout(); }/** * The list is empty. Clear everything out. * */ @Override void resetList() { // The parent's resetList() will remove all views from the layout so we need to // cleanup the state of our footers and headers clearRecycledState(mHeaderViewInfos); clearRecycledState(mFooterViewInfos); super.resetList(); mLayoutMode = LAYOUT_NORMAL; }private void clearRecycledState(ArrayList<FixedViewInfo> infos) { if (infos != null) { final int count = infos.size(); for (int i = 0; i < count; i++) { final View child = infos.get(i).view; final LayoutParams p = (LayoutParams) child.getLayoutParams(); if (p != null) { p.recycledHeaderFooter = false; } } } }Listview源码分析(1)的更多相关文章
- Volley源码分析(2)----ImageLoader
一:imageLoader 先来看看如何使用imageloader: public void showImg(View view){ ImageView imageView = (ImageView) ...
- [Android实例] Scroll原理-附ScrollView源码分析
想象一下你拿着放大镜贴很近的看一副巨大的清明上河图, 那放大镜里可以看到的内容是很有限的, 而随着放大镜的上下左右移动,就可以看到不同的内容了 android中手机屏幕就相当于这个放大镜, 而看到的内 ...
- Appium Android Bootstrap源码分析之启动运行
通过前面的两篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>和<Appium Android Bootstrap源码分析之命令解析 ...
- Appium Android Bootstrap源码分析之控件AndroidElement
通过上一篇文章<Appium Android Bootstrap源码分析之简介>我们对bootstrap的定义以及其在appium和uiautomator处于一个什么样的位置有了一个初步的 ...
- Robotium源码分析之运行原理
从上一章<Robotium源码分析之Instrumentation进阶>中我们了解到了Robotium所基于的Instrumentation的一些进阶基础,比如它注入事件的原理等,但Rob ...
- documentsUI源码分析
documentsUI源码分析 本文基于Android 6.0的源码,来分析documentsUI模块. 原本基于7.1源码看了两天,但是Android 7.1与6.0中documentsUI模块差异 ...
- Android base-adapter-helper 源码分析与扩展
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/44014941,本文出自:[张鸿洋的博客] 本篇博客是我加入Android 开源项 ...
- ViewPager 源码分析(一) —— setAdapter() 与 populate()
写在前面 做安卓也有一定时间了,虽然常用控件都已大致掌握,然而随着 Android N 的发布,不自觉的愈发焦虑起来.说来惭愧,Android L 的 Material Design 库里的许多控件都 ...
- Android事件分发机制源码分析
Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ...
随机推荐
- 接口post +json +bean
public ReturnBean<DealBean> getMember(String tagtype, String tag) { try { String requestUrl = ...
- EclEmma单元测试覆盖率统计插件
EclEmma是Eclipse里的一个插件,安装简单,覆盖率显示直观.安装EclEmma.打开Eclipse,点击Help → Intall New SofaWare → Work with 输入 h ...
- KVM 命令行启动第一台虚拟机
KVM创建第一台虚拟机 1 创建一个镜像 [root@kvm ~]# qemu-img create -f raw /opt/CentOS6.-x86_64.raw 5G Formatting [ro ...
- java使用url和tns两种方式连接数据库执行存储过程
1.url方式(连接数据库并执行一个查询): public static void main(String[] args) throws ClassNotFoundException, SQLExce ...
- 十五、oracle 约束
一.维护数据的完整性数据的完整性用于确保数据库数据遵从一定的商业和逻辑规则,在oracle中,数据完整性可以使用约束.触发器.应用程序(过程.函数)三种方法来实现,在这三种方法中,因为约束易于维护,并 ...
- POJ 3548 Restoring the digits
暴力搜索.注意题目说每个字母对应的数字不同,这句话表明最多只有10个字母,所以暴力DFS绝对不会TLE. #include<cstdio> #include<cstring> ...
- Linux系统监控实用工具Glances
Linux系统监控实用工具Glances Glances安装 Glances安装要求:python >= 2.6 和 psutil >= 0.4.1 1.第一步,安装了python-> ...
- 面向对象的特性-利用prototype为类创建静态成员
—————————————————————————— <script type="text/javascript"> //用function模拟一 ...
- gerrit review 设置
$ git config remote.review.pushurl "ssh://someone@ip:29418/the_project" $ git config remot ...
- nefu 446 今年暑假不AC(贪心)
Description “今年暑假不AC?” “是的.” “那你干什么呢?” “看世界杯呀,笨蛋!” “@#$%^&*%...” 确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会 ...