1、前言:
前几天用了GitHub上se.emilsjolander.stickylistheaders这个组件,然后发现这个组件的listview不能添加footerView,加了footer后,滑倒footer的时候head会消失,与我项目中的需求不符。
于是就自己写了一个StickHeaderListView,实现比较简单,做法和stickylistheaders基本相同只是没有封装那么多功能,可以添加footer但不能添加header,有需要的同学可以拿去改良后用。
另外由于是临时写的一个组件,代码没做什么优化,如果有想法可以提点意见,谢谢!
2、示例效果:
images/loading.gif' data-original="http://images2015.cnblogs.com/blog/522798/201606/522798-20160628173624984-1488830955.gif" />
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的情况,清空Head111 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 @Override188 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 // 添加head196 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 @Override11 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 @Override44 public int getCount() {45 return 30;46 }47 @Override48 public Object getItem(int position) {49 return position;50 }51 @Override52 public long getItemId(int position) {53 return position;54 }55 @Override56 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 @Override69 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 @Override78 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问题
关键词:ie