首先Listview继承关系:
ListView  --extends-->  AbsListview  --extends-->  AdapterView  --extends-->  ViewGroup  --extends-->  View 
ListView的构造方法:
此时初始化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 fangshi
    if (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 height
    setDivider(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();
    }
     
在往下看:
 
响应箭头事件时,列表视图可以滚动的最大值. 
  1. public int getMaxScrollAmount() {
    return (int) (MAX_SCROLL_FACTOR * (mBottom - mTop));
    }
     
在往下看:
确保Listview触及顶部或底部边缘 调整在ListView顶部或底部的view以适应我们的视觉感应;
  1. 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 top
    child = 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 spacing
    delta -= mDividerHeight;
    }
    if (delta < 0) {
    // We only are looking to see if we are too low, not too high
    delta = 0;
    }
    } else {
    // we are too high, slide all views down to align with bottom
    child = 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 spacing
    delta += 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();
    }
    }
    }
     
接下来 添加 头部view的方法和获取头部view的数目:
  1. public void addHeaderView(View v) {
    addHeaderView(v, null, true);
    }
    @Override
    public int getHeaderViewsCount() {
    return mHeaderViewInfos.size();
    }
     
删除头部的方法;如果头部信息的list>0,并且Adapter不为null,删除头部信息,并进行回调:
  1. 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;
}
}
}
添加Listview底部布局:
/**
* 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;
}
获取listview使用的Adapter:
/**
* 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;
}
 
为listview添加数据setAdapter 实现原理:
 
/**
* 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);
}
//重置list 
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();
}
在20行调用了 ,清空listview的头部,也清空底部,删除layout中所有的view:
/**
* 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;
}
8,9行调用clearRecycledState
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)的更多相关文章

  1. Volley源码分析(2)----ImageLoader

    一:imageLoader 先来看看如何使用imageloader: public void showImg(View view){ ImageView imageView = (ImageView) ...

  2. [Android实例] Scroll原理-附ScrollView源码分析

    想象一下你拿着放大镜贴很近的看一副巨大的清明上河图, 那放大镜里可以看到的内容是很有限的, 而随着放大镜的上下左右移动,就可以看到不同的内容了 android中手机屏幕就相当于这个放大镜, 而看到的内 ...

  3. Appium Android Bootstrap源码分析之启动运行

    通过前面的两篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>和<Appium Android Bootstrap源码分析之命令解析 ...

  4. Appium Android Bootstrap源码分析之控件AndroidElement

    通过上一篇文章<Appium Android Bootstrap源码分析之简介>我们对bootstrap的定义以及其在appium和uiautomator处于一个什么样的位置有了一个初步的 ...

  5. Robotium源码分析之运行原理

    从上一章<Robotium源码分析之Instrumentation进阶>中我们了解到了Robotium所基于的Instrumentation的一些进阶基础,比如它注入事件的原理等,但Rob ...

  6. documentsUI源码分析

    documentsUI源码分析 本文基于Android 6.0的源码,来分析documentsUI模块. 原本基于7.1源码看了两天,但是Android 7.1与6.0中documentsUI模块差异 ...

  7. Android base-adapter-helper 源码分析与扩展

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/44014941,本文出自:[张鸿洋的博客] 本篇博客是我加入Android 开源项 ...

  8. ViewPager 源码分析(一) —— setAdapter() 与 populate()

    写在前面 做安卓也有一定时间了,虽然常用控件都已大致掌握,然而随着 Android N 的发布,不自觉的愈发焦虑起来.说来惭愧,Android L 的 Material Design 库里的许多控件都 ...

  9. Android事件分发机制源码分析

    Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ...

随机推荐

  1. ios 将图片变成圆形

    #pragma mark - 将图片转换成圆形 -(UIImage*) circleImage:(UIImage*) image withParam:(CGFloat) inset { UIGraph ...

  2. Github 修正上传时“this exceeds GitHub’s file size limit of 100 MB”错误

    自己的项目的版本控制用的是Git,代码仓库在github托管.项目里用到了IJKMediaFramework 想把代码push到github上,结果出错了,被拒绝,具体信息是: Total 324 ( ...

  3. Alyona and a tree

    Alyona and a tree time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  4. sha加密算法

    密钥生成 公钥(e,n)  私钥(d,n) 找两个互质的大素数p和q, 计算n=p*p, f(n)=(p-1)*(q-1) 选择随机整数e(e和f(n)互质) de=f(n)mod 1 利用公钥加密 ...

  5. javaWeb知识的回顾

    16年7月毕业,现在工作也有3个多月了.一直是在做一些增删改查,技术上没有太大的突破,自己总结下原因,还是原理理解的不够透彻,地基没打好就盖不成高楼. 在51cto上找到了佟刚老师的视频,快进游览一遍 ...

  6. iosNSMutableAttributedString 简单操作

    // 打印系统中所有字体的类型名字    NSArray *familyNames = [UIFont familyNames];    for(NSString *familyName in fam ...

  7. 定义django admin的站点头,标题等

    admin.py from django.contrib import admin from app.models import Product # Register your models here ...

  8. linux脚本Shell之九九乘法表

    说到9*9乘法表,许多朋友在想这是小学二年级就会的东西,不错,确实是这样,那么在linux下,使用shell打印出99乘法表应该如何编写脚本的? 笔者的文档今天就写下来,有需要的朋友可以参考下 代码: ...

  9. python 输出重定向

    使print既打印到终端,又写入文件 class Tee(object): def __init__(self,*files): self.files = files def write(self,o ...

  10. process lasso 优化原理

    <星际争霸2:虚空之遗>很多玩家的CPU性能并不低,但是在星际2中的表现就总会出现掉帧的情况,那么应该如何提升CPU的性能就成了玩家关注的话题,下面小编就为大家带来星际争霸2虚空之遗cpu ...