• android ListView 分析(一)


    需要了解的内容
    1. listview中的getItemAtPosition与Adapter的getItem的position的区别 
            listView中的getItemAtPosition的源码实现:
     1 /**
     2 * Gets the data associated with the specified position in the list.
     3 *
     4 * @param position Which data to get
     5 * @return The data associated with the specified position in the list
     6 */
     7 public Object getItemAtPosition(int position) {
     8 T adapter = getAdapter();
     9 return (adapter == null || position < 0) ? null : adapter.getItem(position);
    10 }
    11  
    12 public long getItemIdAtPosition(int position) {
    13 T adapter = getAdapter();
    14 return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position);
    15 }
     
    如果在adapter部位null并且position不是负数的时候,那么就会直接调用listView中真正的adapter的getItem()方法
     
    因而我们自己定义的adapter,其实和listView中定义的getItemAtPosition()存在的差异就是在有headView和footView的时候
     
    但是在我们自己的adapter中还是应该用有效的position
    而在外部想直接调用的时候,应该让listView.getAdapter().getItem(position),如果调用到了headView或者footView的时候,那么就是返回为空的,因为在包装的
    那么就是调用的headViewInfo中的data或者mFooterViewInfos.data
     1 public Object getItem(int position) {
     2 // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
     3 int numHeaders = getHeadersCount();
     4 if (position < numHeaders) {
     5 return mHeaderViewInfos.get(position).data;
     6 }
     7  
     8 // Adapter
     9 final int adjPosition = position - numHeaders;
    10 int adapterCount = 0;
    11 if (mAdapter != null) {
    12 adapterCount = mAdapter.getCount();
    13 if (adjPosition < adapterCount) {
    14 return mAdapter.getItem(adjPosition);
    15 }
    16 }
    17  
    18 // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
    19 return mFooterViewInfos.get(adjPosition - adapterCount).data;
    20 }
    21 这个算是简单的View的包装器
    22 /**
    23 * A class that represents a fixed view in a list, for example a header at the top
    24 * or a footer at the bottom.
    25 */
    26 public class FixedViewInfo {
    27 /** The view to add to the list */
    28 public View view;
    29 /** The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. */
    30 public Object data;
    31 /** <code>true</code> if the fixed view should be selectable in the list */
    32 public boolean isSelectable;
    33 }
      
    2. listview中如何传递position
        在listView中获得的position是经过包装的,因而在我们的adapter中需要转换
    3. onItemClick的parent是否与listview为同一个view --> 是的
    4. 在获取类型时,到底应该使用那个类型 
       在使用类型的时候,即getViewTypeCount()一般都是我们的adapter的getViewTypeCount()    
     
    5.adapter中 getItemViewType()方法的作用
            我们使用的都是正数,而且是从0开始的,但是系统中的headView和footView的ViewType是负数
    6.listView的优化
    7.listView的扩展
            7.1 listView实现下拉刷新,下拉加载
            7.2 listView实现其他特效
            7.3 listView实现动态的更改headView和footView的大小
     
    ......
     
    8.listView相关知识: adapter的体系结构以及特点
     
     
    ListView 在 存在headView或者footView的时候,listView设置的adapter并不是我们设置的adapter
     
    查看源码便得知
     1 /**
     2 * Sets the data behind this ListView.
     3 *
     4 * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
     5 * depending on the ListView features currently in use. For instance, adding
     6 * headers and/or footers will cause the adapter to be wrapped.
     7 *
     8 * @param adapter The ListAdapter which is responsible for maintaining the
     9 * data backing this list and for producing a view to represent an
    10 * item in that data set.
    11 *
    12 * @see #getAdapter()
    13 */
    14 @Override
    15 public void setAdapter(ListAdapter adapter) {
    16 if (null != mAdapter) {
    17 mAdapter.unregisterDataSetObserver(mDataSetObserver);
    18 }
    19  
    20 resetList();
    21 mRecycler.clear();
    22 //关键代码 ListView 在 存在headView或者footView的时候,listView设置的adapter并不是我们设置的adapter,而是包装过的HeaderViewListAdapter
    23 
    24  
    25 if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
    26 mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
    27 } else {
    28 mAdapter = adapter;
    29 }
    30  
    31 ......
    32 }
    既然如此设计,那么在使用的时候,我们便需要注意一些细节
    listView中获取的getItemAtPosition中的position并不一定和我们的adapter的position相同
     
    因而在设置position的时候,需要将position进行处理
    例如
    onItemClick中,传递而来的position有可能是包裹后的,因而我们考虑手工去除或者让系统来去除,即将包裹后的position转换为我们的adapter的position
     
    1.手工方式
    1 listView.setOnItemClickListener(new OnItemClickListener() {
    2  
    3 @Override
    4 public void onItemClick(AdapterView<?> parent, View view,
    5 int position, long id) {
    6 int realPosition = position - listView.getHeaderViewsCount();
    7 }
    8 });
    2. 调用系统api的方式(推荐使用的方式)
     
    在设置listView的相关监听的时候,会提供AdapterView<?> parent这个参数,这个其实就是我们的listView
    调用他的getAdapter()获取到实际的adapter,然后调用adapter的获取数据的方式
     
    1 @Override
    2 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
    3 doSomething(parent.getAdapter().getItem(position));
    4 }
      1  
      2 扩展内容,包裹的adapter --> HeaderViewListAdapter
      3  
      4 ......
      5 import java.util.ArrayList;
      6  
      7 /**
      8 * ListAdapter used when a ListView has header views. This ListAdapter
      9 * wraps another one and also keeps track of the header views and their
     10 * associated data objects.
     11 *<p>This is intended as a base class; you will probably not need to
     12 * use this class directly in your own code.
     13 */
     14 public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {
     15  
     16 private final ListAdapter mAdapter;
     17  
     18 // These two ArrayList are assumed to NOT be null.
     19 // They are indeed created when declared in ListView and then shared.
     20 ArrayList<ListView.FixedViewInfo> mHeaderViewInfos;
     21 ArrayList<ListView.FixedViewInfo> mFooterViewInfos;
     22  
     23 // Used as a placeholder in case the provided info views are indeed null.
     24 // Currently only used by some CTS tests, which may be removed.
     25 static final ArrayList<ListView.FixedViewInfo> EMPTY_INFO_LIST =
     26 new ArrayList<ListView.FixedViewInfo>();
     27 ......
     28  
     29 public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,
     30 ArrayList<ListView.FixedViewInfo> footerViewInfos,
     31 ListAdapter adapter) {
     32 mAdapter = adapter;
     33 mIsFilterable = adapter instanceof Filterable;
     34  
     35 if (headerViewInfos == null) {
     36 mHeaderViewInfos = EMPTY_INFO_LIST;
     37 } else {
     38 mHeaderViewInfos = headerViewInfos;
     39 }
     40  
     41 if (footerViewInfos == null) {
     42 mFooterViewInfos = EMPTY_INFO_LIST;
     43 } else {
     44 mFooterViewInfos = footerViewInfos;
     45 }
     46  
     47 mAreAllFixedViewsSelectable =
     48 areAllListInfosSelectable(mHeaderViewInfos)
     49 && areAllListInfosSelectable(mFooterViewInfos);
     50 }
     51  
     52 public int getHeadersCount() {
     53 return mHeaderViewInfos.size();
     54 }
     55  
     56 public int getFootersCount() {
     57 return mFooterViewInfos.size();
     58 }
     59  
     60 public boolean isEmpty() {
     61 return mAdapter == null || mAdapter.isEmpty();
     62 }
     63  
     64 ......
     65  
     66 public boolean removeHeader(View v) {
     67 for (int i = 0; i < mHeaderViewInfos.size(); i++) {
     68 ListView.FixedViewInfo info = mHeaderViewInfos.get(i);
     69 if (info.view == v) {
     70 mHeaderViewInfos.remove(i);
     71  
     72 mAreAllFixedViewsSelectable =
     73 areAllListInfosSelectable(mHeaderViewInfos)
     74 && areAllListInfosSelectable(mFooterViewInfos);
     75  
     76 return true;
     77 }
     78 }
     79  
     80 return false;
     81 }
     82  
     83 public boolean removeFooter(View v) {
     84 for (int i = 0; i < mFooterViewInfos.size(); i++) {
     85 ListView.FixedViewInfo info = mFooterViewInfos.get(i);
     86 if (info.view == v) {
     87 mFooterViewInfos.remove(i);
     88  
     89 mAreAllFixedViewsSelectable =
     90 areAllListInfosSelectable(mHeaderViewInfos)
     91 && areAllListInfosSelectable(mFooterViewInfos);
     92  
     93 return true;
     94 }
     95 }
     96  
     97 return false;
     98 }
     99  
    100 public int getCount() {
    101 if (mAdapter != null) {
    102 return getFootersCount() + getHeadersCount() + mAdapter.getCount();
    103 } else {
    104 return getFootersCount() + getHeadersCount();
    105 }
    106 }
    107  
    108  
    109 ......
    110  
    111 public Object getItem(int position) {
    112 // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
    113 int numHeaders = getHeadersCount();
    114 if (position < numHeaders) {
    115 return mHeaderViewInfos.get(position).data;
    116 }
    117  
    118 // Adapter
    119 final int adjPosition = position - numHeaders;
    120 int adapterCount = 0;
    121 if (mAdapter != null) {
    122 adapterCount = mAdapter.getCount();
    123 if (adjPosition < adapterCount) {
    124 return mAdapter.getItem(adjPosition);
    125 }
    126 }
    127  
    128 // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
    129 return mFooterViewInfos.get(adjPosition - adapterCount).data;
    130 }
    131  
    132 public long getItemId(int position) {
    133 int numHeaders = getHeadersCount();
    134 if (mAdapter != null && position >= numHeaders) {
    135 int adjPosition = position - numHeaders;
    136 int adapterCount = mAdapter.getCount();
    137 if (adjPosition < adapterCount) {
    138 return mAdapter.getItemId(adjPosition);
    139 }
    140 }
    141 return -1;
    142 }
    143  
    144  
    145 public View getView(int position, View convertView, ViewGroup parent) {
    146 // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
    147 int numHeaders = getHeadersCount();
    148 if (position < numHeaders) {
    149 return mHeaderViewInfos.get(position).view;
    150 }
    151  
    152 // Adapter
    153 final int adjPosition = position - numHeaders;
    154 int adapterCount = 0;
    155 if (mAdapter != null) {
    156 adapterCount = mAdapter.getCount();
    157 if (adjPosition < adapterCount) {
    158 return mAdapter.getView(adjPosition, convertView, parent);
    159 }
    160 }
    161  
    162 // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
    163 return mFooterViewInfos.get(adjPosition - adapterCount).view;
    164 }
    165  
    166 public int getItemViewType(int position) {
    167 int numHeaders = getHeadersCount();
    168 if (mAdapter != null && position >= numHeaders) {
    169 int adjPosition = position - numHeaders;
    170 int adapterCount = mAdapter.getCount();
    171 if (adjPosition < adapterCount) {
    172 return mAdapter.getItemViewType(adjPosition);
    173 }
    174 }
    175  
    176 return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
    177 }
    178  
    179 public int getViewTypeCount() {
    180 if (mAdapter != null) {
    181 return mAdapter.getViewTypeCount();
    182 }
    183 return 1;
    184 }
    185 ......
    186  
    187 public Filter getFilter() {
    188 if (mIsFilterable) {
    189 return ((Filterable) mAdapter).getFilter();
    190 }
    191 return null;
    192 }
    193 //获取被包装的adapter,即我们设置的listView
    194 public ListAdapter getWrappedAdapter() {
    195 return mAdapter;
    196 }
    197 }
     
    要获取到我们设置的adapter,这个方法是在接口中实现的,直接获取到即可
    package android.widget;
     
     1 /**
     2 * List adapter that wraps another list adapter. The wrapped adapter can be retrieved
     3 * by calling {@link #getWrappedAdapter()}.
     4 *
     5 * @see ListView
     6 */
     7 public interface WrapperListAdapter extends ListAdapter {
     8 /**
     9 * Returns the adapter wrapped by this list adapter.
    10 *
    11 * @return The {@link android.widget.ListAdapter} wrapped by this adapter.
    12 */
    13 public ListAdapter getWrappedAdapter();
    14 }

     安卓源码分析群: Android源码分析QQ1群号:164812238

  • 相关阅读:
    $().each和$("input[name='XXX']")
    常规JS操作
    日期大小比较JS方法
    集合迭代
    技术点1
    GItHub pages 的使用方法
    node.js是做什么的?
    jQuery基础:下(事件及动画效果)
    jQuery基础:上(样式及DOM操作)
    页码demo制作
  • 原文地址:https://www.cnblogs.com/pandapan/p/4177153.html
Copyright © 2020-2023  润新知