新的LAC设想中需要一个类似IOS中的'Pull to Refresh ListView'功能,即是当ListView显示到最后一列时,向上拖动ListView将开始加载后续数据列,如下图所示:
一直以为Android应该自带了这个view,但翻了一下,竟然没有,至少API8中没有...赶紧google下,嗯,很多前人都做过了,很好,不过...LAC中只需要最下面的pull刷新功能,上面那个还真不需要,但所有的例子中要不是上下都有,要不只有上面,这..这不满足我的需求啊...(好吧,是我毛病太多..)
于是,发扬"
轮子精神"--咱自己做个不行吗...于是就有了下面的代码.
RefreshListView
1 package jie.java.android.view.refreshlistview;
2
3 import android.content.Context;
4 import android.util.AttributeSet;
5 import android.util.Log;
6 import android.view.Gravity;
7 import android.view.MotionEvent;
8 import android.view.View;
9 import android.view.ViewGroup;
10 import android.widget.AbsListView;
11 import android.widget.LinearLayout;
12 import android.widget.AbsListView.OnScrollListener;
13 import android.widget.ListView;
14 import android.widget.ProgressBar;
15 import android.widget.TextView;
16
17 public class RefreshListView extends ListView implements OnScrollListener {
18
19 private class FooterView extends LinearLayout {
20 private TextView title = null;
21 private ProgressBar progress = null;
22
23 public FooterView(Context context) {
24 super(context);
25
26 initViews();
27 }
28
29 public FooterView(Context context, AttributeSet attrs) {
30 super(context, attrs);
31
32 initViews();
33 }
34
35 private void initViews() {
36 /*
37 LinearLayout layout = new LinearLayout(this.getContext());
38 layout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.MATCH_PARENT));
39 layout.setGravity(Gravity.CENTER_HORIZONTAL);
40
41 layout.setOrientation(HORIZONTAL);
42 */
43 //this.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL));
44 progress = new ProgressBar(this.getContext());
45 progress.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
46 progress.setPadding(80, 10, 20, 10);
47 title = new TextView(this.getContext());
48 title.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));// CONTENT));
49 title.setGravity(Gravity.CENTER_VERTICAL);
50 //title.setText("test");
51 // progress.setMinimumHeight(40);
52
53 this.addView(progress);
54 this.addView(title);
55
56 // this.addView(layout);
57 }
58
59 public void setVisible(boolean isVisible) {
60 progress.setVisibility(isVisible ? View.VISIBLE : View.GONE);
61 title.setVisibility(isVisible ? View.VISIBLE : View.GONE);
62 //this.setVisibility(isVisible ? View.VISIBLE : View.GONE);
63 }
64
65 public void setText(String text) {
66 title.setText(text);
67 }
68 }
69
70 public interface OnRefreshListener {
71 public void onRefresh(int firstVisibleItem, int visibleItemCount, int totalItemCount);
72
73 public void onBeginRefresh();
74
75 public void onEndRefresh();
76
77 public void onStopRefresh();
78 }
79
80 private FooterView footer = null;
81
82 private boolean isBottom = false;
83 private int footerHeight = 0;
84 private int mLastMotionY = -1;
85
86 private int firstVisibleItem = -1;
87 private int visibleItemCount = -1;
88 private int totalItemCount = -1;
89 private boolean hasNotify = false;
90
91 private OnRefreshListener refreshListener = null;
92
93
94 public RefreshListView(Context context) {
95 super(context);
96
97 initFooter();
98 }
99
100 public RefreshListView(Context context, AttributeSet attrs) {
101 super(context, attrs);
102 initFooter();
103 }
104
105 public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
106 super(context, attrs, defStyle);
107 initFooter();
108 }
109
110 private void initFooter() {
111 footer = new FooterView(this.getContext());
112
113 footer.setVisible(false);
114 this.addFooterView(footer);
115
116 measureView(footer);
117
118 footerHeight = footer.getMeasuredHeight();
119
120 this.setOnScrollListener(this);
121 }
122
123 private void measureView(View child) {
124 ViewGroup.LayoutParams p = child.getLayoutParams();
125 if (p == null) {
126 p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
127 }
128
129 int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
130 int lpHeight = p.height;
131 int childHeightSpec;
132 if (lpHeight > 0) {
133 childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
134 } else {
135 childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
136 }
137 child.measure(childWidthSpec, childHeightSpec);
138 }
139
140 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
141
142 if(totalItemCount > 0 && (totalItemCount > visibleItemCount) && ((firstVisibleItem + visibleItemCount) == totalItemCount)) {
143 isBottom = true;
144
145 this.firstVisibleItem = firstVisibleItem;
146 this.visibleItemCount = visibleItemCount;
147 this.totalItemCount = totalItemCount;
148 }
149 else {
150 isBottom = false;
151 }
152 }
153
154 public void onScrollStateChanged(AbsListView view, int scrollState) {
155 }
156
157 @Override
158 public boolean onTouchEvent(MotionEvent ev) {
159 if(isBottom) {
160
161 if(mLastMotionY == -1) {
162 mLastMotionY = (int) ev.getRawY();
163 }
164
165 if(ev.getAction() == MotionEvent.ACTION_MOVE) {
166
167 footer.setVisible(isBottom);
168 int pad = (int) (((mLastMotionY - ev.getRawY()) - footerHeight ) / 1.75);
169 footer.setPadding(0, 0, 0, pad);
170
171 if(!hasNotify && refreshListener != null) {
172 refreshListener.onBeginRefresh();
173 hasNotify = true;
174 }
175 }
176 else if(ev.getAction() == MotionEvent.ACTION_DOWN) {
177 mLastMotionY = (int) ev.getRawY();// ev.getY();
178 }
179 else if(ev.getAction() == MotionEvent.ACTION_UP) {
180
181 if(refreshListener != null) {
182 refreshListener.onRefresh(this.firstVisibleItem, this.visibleItemCount, this.totalItemCount);
183 }
184
185 footer.setPadding(0, 0, 0, 0);
186 footer.setVisible(false);
187
188 if(refreshListener != null) {
189 refreshListener.onEndRefresh();
190 }
191 hasNotify = false;
192 }
193 }
194 else {
195 if(ev.getAction() == MotionEvent.ACTION_UP) {
196 if(refreshListener != null) {
197 refreshListener.onStopRefresh();
198 }
199 hasNotify = false;
200 }
201 }
202
203 return super.onTouchEvent(ev);
204 }
205
206 public void setOnRefreshListener(OnRefreshListener listener) {
207 refreshListener = listener;
208 }
209
210 public void setText(String text) {
211 footer.setText(text);
212 }
213 }
214 下面是测试代码.
MainActivity
1 package jie.java.android.test_listview;
2
3 import java.util.ArrayList;
4
5 import jie.java.android.view.refreshlistview.RefreshListView;
6 import android.os.Bundle;
7 import android.app.Activity;
8 import android.util.Log;
9 import android.view.Menu;
10 import android.widget.ArrayAdapter;
11
12 public class MainActivity extends Activity {
13
14 private RefreshListView listView = null;
15
16
17 private ArrayList<String> astring = new ArrayList<String>();
18 private int count = 9;//2;
19
20 @Override
21 public void onCreate(Bundle savedInstanceState) {
22 super.onCreate(savedInstanceState);
23 setContentView(R.layout.activity_main);
24
25 listView = (RefreshListView) this.findViewById(R.id.refreshListView1);
26 listView.setOnRefreshListener(new RefreshListView.OnRefreshListener() {
27
28 public void onRefresh(int firstVisibleItem, int visibleItemCount, int totalItemCount) {
29 onListViewRefresh(firstVisibleItem, visibleItemCount, totalItemCount);
30 }
31
32 public void onBeginRefresh() {
33 Log.d("this", "onBeginRefresh()");
34 onListViewBeginRefresh();
35 }
36
37 public void onEndRefresh() {
38 Log.d("this", "onEndRefresh()");
39 }
40
41 public void onStopRefresh() {
42 Log.d("this", "onStopRefresh()");
43 }
44 });
45
46 initListViewData();
47 }
48
49 protected void onListViewBeginRefresh() {
50 listView.setText("Release to refresh!");
51 }
52
53 protected void onListViewRefresh(int firstVisibleItem, int visibleItemCount, int totalItemCount) {
54
55 // for(Integer i = totalItemCount - 1; i < totalItemCount + visibleItemCount; ++ i) {
56 // astring.add(Integer.toString(++ count));
57 // }
58 astring.add(Integer.toString(++ count));
59 listView.setSelection(firstVisibleItem + visibleItemCount - 1);
60 }
61
62 private void initListViewData() {
63
64 for(Integer i = 0; i < count; ++ i) {
65 astring.add(i.toString());
66 }
67
68 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, astring);
69 listView.setAdapter(adapter);
70 }
71
72 @Override
73 public boolean onCreateOptionsMenu(Menu menu) {
74 getMenuInflater().inflate(R.menu.activity_main, menu);
75 return true;
76 }
77 }
78 不知为何代码比google来的都短了许多,估计是我考虑的不全面吧,但基本满足俺的需求了...最好的一点,咱的不用额外的layout文件,就两个子控件,直接就内置了...