原创StickHeaderListView的简单实现,解决footerView问题

Posted HalfmanHuang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原创StickHeaderListView的简单实现,解决footerView问题相关的知识,希望对你有一定的参考价值。

1、前言:

 

前几天用了GitHub上se.emilsjolander.stickylistheaders这个组件,然后发现这个组件的listview不能添加footerView,加了footer后,滑倒footer的时候head会消失,与我项目中的需求不符。

于是就自己写了一个StickHeaderListView,实现比较简单,做法和stickylistheaders基本相同只是没有封装那么多功能,可以添加footer但不能添加header,有需要的同学可以拿去改良后用。

另外由于是临时写的一个组件,代码没做什么优化,如果有想法可以提点意见,谢谢!

 

2、示例效果:

 

3、组件源码:

  1 /**
  2  * 带头部固定的列表
  3  * Created by shengdong.huang on 2016/6/24.
  4  */
  5 public class StickHeaderListView extends FrameLayout {
  6 
  7     /** 页面引用 */
  8     protected Context context;
  9     /** 列表视图 */
 10     protected ListView listView;
 11     /** 适配器 */
 12     protected StickHeaderAdapter adapter;
 13     /** 头部布局 */
 14     protected FrameLayout headLayout;
 15     /** 滚动监听器 */
 16     protected OnScrollListener listener;
 17     /** 提供Adapter响应的观察者 */
 18     protected DataSetObserver mDataSetObserver = new DataSetObserver() {
 19         @Override
 20         public void onChanged() {
 21             if (listView != null && headLayout != null && adapter != null) {
 22                 refreshHead(listView.getFirstVisiblePosition(), true);
 23             }
 24         }
 25 
 26         @Override
 27         public void onInvalidated() {
 28         }
 29     };
 30 
 31     /**
 32      * 滚动监听器
 33      */
 34     protected AbsListView.OnScrollListener scrollListener = new AbsListView.OnScrollListener() {
 35 
 36         @Override
 37         public void onScrollStateChanged(AbsListView view, int scrollState) {
 38             if (listener != null) {
 39                 listener.onScrollStateChanged(view, scrollState);
 40             }
 41         }
 42 
 43         @Override
 44         public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
 45             if (listener != null) {
 46                 listener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
 47             }
 48             // 刷新
 49             refreshHead(firstVisibleItem, false);
 50         }
 51     };
 52 
 53     protected void refreshHead(int firstVisibleItem, boolean forceRefresh) {
 54         // 防空
 55         if (headLayout == null || adapter == null || adapter.getHeadPos() == null
 56                 || listView.getChildAt(0) == null) {
 57             return;
 58         }
 59 
 60         // 获取头部位置记录
 61         ArrayList<Integer> headPos = adapter.getHeadPos();
 62         // 是否有找到head
 63         boolean find = false;
 64 
 65         // 获取head中的位置
 66         int prevHeadPos = -1;
 67         if (headLayout.getChildCount() > 0 && headLayout.getChildAt(0) != null &&
 68                 headLayout.getChildAt(0).getTag() != null) {
 69             prevHeadPos = (int) headLayout.getChildAt(0).getTag();
 70         }
 71 
 72         // 反向遍历头部位置记录
 73         for (int i = (headPos.size() - 1); i>=0; i--) {
 74             // 如果当前位置大于等于某个头部记录,表示应该使用该头部
 75             if (firstVisibleItem >= headPos.get(i)) {
 76                 // 获取headLayout中视图的pos标签
 77 
 78                 // 构造或者从headLayout中获取视图
 79                 View v;
 80                 if (prevHeadPos == -1 || prevHeadPos != headPos.get(i) || forceRefresh) {
 81                     // 无Pos标签或POS标签不配对
 82                     headLayout.removeAllViews();
 83                     v = listView.getAdapter().getView(headPos.get(i), null, null);
 84                     v.setTag(headPos.get(i));
 85                     LayoutParams params = new FrameLayout.LayoutParams(-1, -2);
 86                     v.setLayoutParams(params);
 87                     headLayout.addView(v);
 88                 } else if (i+1 < headPos.size() && firstVisibleItem == headPos.get(i+1) - 1) {
 89                     // 当前第一个item的top值
 90                     int top = listView.getChildAt(0).getTop();
 91                     // Pos标签配对但,有下一个head,且下一个head的pos为下一个item时
 92                     v = headLayout.getChildAt(0);
 93                     // 设置head的Top
 94                     LayoutParams params = (LayoutParams) v.getLayoutParams();
 95                     params.setMargins(0, top, 0, -top);
 96                     v.setLayoutParams(params);
 97                 } else {
 98                     // 修正head top没有回到0的问题
 99                     v = headLayout.getChildAt(0);
100                     LayoutParams params = (LayoutParams) v.getLayoutParams();
101                     if (params.topMargin != 0) {
102                         params.setMargins(0, 0, 0, 0);
103                         v.setLayoutParams(params);
104                     }
105                 }
106                 find = true;
107                 break;
108             }
109         }
110         // 未找到head的情况,清空Head
111         if (!find && headLayout != null) {
112             headLayout.removeAllViews();
113         }
114     }
115 
116     public StickHeaderListView(Context context) {
117         super(context);
118         this.context = context;
119     }
120 
121     public StickHeaderListView(Context context, AttributeSet attrs) {
122         super(context, attrs);
123         this.context = context;
124     }
125 
126     public void setBackgroundColor(int color) {
127         if (listView != null) {
128             listView.setBackgroundColor(color);
129         }
130     }
131 
132     public void addFooterView(View v) {
133         if (listView != null) {
134             listView.addFooterView(v);
135         }
136     }
137 
138     public boolean removeFooterView(View v) {
139         if (listView != null) {
140             return listView.removeFooterView(v);
141         }
142         return false;
143     }
144 
145     public int getFooterViewsCount() {
146         if (listView != null) {
147             return listView.getFooterViewsCount();
148         }
149         return 0;
150     }
151 
152     public void setDividerHeight(int height) {
153         if (listView != null) {
154             listView.setDividerHeight(height);
155         }
156     }
157 
158     public void setCacheColorHint(int color) {
159         if (listView != null) {
160             listView.setCacheColorHint(color);
161         }
162     }
163 
164     public void setSelector(int resID) {
165         if (listView != null) {
166             listView.setSelector(resID);
167         }
168     }
169 
170     public void setAdapter(StickHeaderAdapter adapter) {
171         if (adapter instanceof BaseAdapter && listView != null) {
172             this.adapter = adapter;
173             if (adapter != null && mDataSetObserver != null) {
174                 try {
175                     ((BaseAdapter) adapter).unregisterDataSetObserver(mDataSetObserver);
176                 } catch (Exception e) {}
177             }
178             listView.setAdapter((ListAdapter) this.adapter);
179             ((BaseAdapter) adapter).registerDataSetObserver(mDataSetObserver);
180         }
181     }
182 
183     public void setOnScrollListener(OnScrollListener listener) {
184         this.listener = listener;
185     }
186 
187     @Override
188     protected void onFinishInflate() {
189         super.onFinishInflate();
190         // 添加列表,属性直接使用父视图
191         listView = new ListView(context);
192         listView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
193                 ViewGroup.LayoutParams.MATCH_PARENT));
194         addView(listView);
195         // 添加head
196         headLayout = new FrameLayout(context);
197         headLayout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
198                 ViewGroup.LayoutParams.WRAP_CONTENT));
199         addView(headLayout);
200         // 添加滚动监听
201         listView.setOnScrollListener(scrollListener);
202     }
203 
204     public interface OnScrollListener extends AbsListView.OnScrollListener {}
205 
206     public interface StickHeaderAdapter {
207         public ArrayList<Integer> getHeadPos();
208     }
209 }

 

4、示例代码:

 1 /**
 2  * 主页面
 3  * Created by shengdong.huang on 2016/6/20.
 4  */
 5 public class MainActivity extends FragmentActivity {
 6 
 7     private StickHeaderListView listView;
 8     private TestAdapter adapter;
 9 
10     @Override
11     protected void onCreate(@Nullable Bundle savedInstanceState) {
12         super.onCreate(savedInstanceState);
13         setContentView(R.layout.activity_main);
14         listView = (StickHeaderListView) findViewById(R.id.list);
15 
16         View footer = LayoutInflater.from(this).inflate(R.layout.item_head_foot, null);
17         footer.setBackgroundColor(Color.GREEN);
18         listView.addFooterView(footer);
19 
20         View footer2 = LayoutInflater.from(this).inflate(R.layout.item_head_foot, null);
21         footer2.setBackgroundColor(Color.BLUE);
22         listView.addFooterView(footer2);
23 
24         View footer3 = LayoutInflater.from(this).inflate(R.layout.item_head_foot, null);
25         footer3.setBackgroundColor(Color.RED);
26         listView.addFooterView(footer3);
27 
28         listView = (StickHeaderListView) findViewById(R.id.list);
29 
30         adapter = new TestAdapter();
31         listView.setAdapter(adapter);
32     }
33 
34     public class TestAdapter extends BaseAdapter implements StickHeaderListView.StickHeaderAdapter {
35 
36         private ArrayList<Integer> headpos = new ArrayList<>();
37 
38         public TestAdapter() {
39             headpos.add(0);
40             headpos.add(5);
41             headpos.add(15);
42         }
43         @Override
44         public int getCount() {
45             return 30;
46         }
47         @Override
48         public Object getItem(int position) {
49             return position;
50         }
51         @Override
52         public long getItemId(int position) {
53             return position;
54         }
55         @Override
56         public View getView(final int position, View convertView, ViewGroup parent) {
57             ViewHolder holder;
58             if (convertView == null) {
59                 convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_list, null);
60                 holder = new ViewHolder();
61                 holder.text = (TextView) convertView.findViewById(R.id.text);
62                 convertView.setTag(holder);
63             } else {
64                 holder = (ViewHolder) convertView.getTag();
65             }
66             holder.text.setText("AAAAAAAAAAAAAAAAAAAAA"+position);
67             holder.text.setOnClickListener(new View.OnClickListener() {
68                 @Override
69                 public void onClick(View v) {
70                     Toast.makeText(MainActivity.this, "pos:"+position, Toast.LENGTH_SHORT).show();
71                 }
72             });
73             convertView.setBackgroundColor(0x110011 * position % 0xffffff + 0xff000000);
74             return convertView;
75         }
76 
77         @Override
78         public ArrayList<Integer> getHeadPos() {
79             return headpos;
80         }
81     }
82 
83     private class ViewHolder {
84         TextView text;
85     }
86 }

 

5、使用方法:

1、布局中加入StickHeaderListView

2、Adapter实现StickHeaderAdapter接口

3、getHeadPos()中返回headitem的位置,标示listview item中各个head的起点(这点与stickylistheaders不同)

4、如果有需要用到一些listview的方法,请自行在StickHeaderListView中添加,但注意,不能addHeaderView,会导致滑动异常

 

-END-

以上是关于原创StickHeaderListView的简单实现,解决footerView问题的主要内容,如果未能解决你的问题,请参考以下文章

dedecms发布文章实自动推送百度地图

科技向“实”万物生长,2023年云计算五大技术趋势展望

科技向“实”万物生长,2023年云计算五大技术趋势展望

Hive简单实操

Python列表和字典的简单实操例子

房地产企业股权融资(含明股实债)交易架构设计暨融资实操要点