編輯:關於android開發
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-
Android性能優化之常見的內存洩漏 前言 對於內存洩漏,我想大家在開發中肯定都遇到過,只不過內存洩漏對我們來說並不是可見的,因為它是在堆中活動,而要想檢測程序中是
XAMARIN.ANDROID SIGNALR 實時消息接收發送示例,xamarinsignalrSignalR 是一個開發實時 Web 應用的 .NET 類庫,使用 S
JSON解析和XML解析對比,JSON解析XML解析 JSON解析和XML解析是較為普遍的兩種解析方式,其中JSON解析的市場分額更大
淺談android:clipChildren屬性,實現功能: 1、APP主界面底部模塊欄 2、ViewPager一屏多個界面顯示 3、........ 首先