└── PullToRefresh
├── .classpath
├── .project
├── AndroidManifest.xml
├── bin
├── PullToRefresh.apk
├── classes.dex
└── resources.ap_
├── default.properties
├── proguard.cfg
├── res
├── drawable-hdpi
│ ├── ic_pulltorefresh_arrow.png
│ └── icon.png
├── drawable-ldpi
│ ├── ic_pulltorefresh_arrow.png
│ └── icon.png
├── drawable-mdpi
│ ├── ic_pulltorefresh_arrow.png
│ └── icon.png
├── drawable
│ └── pull_to_refresh_header_background.xml
├── layout
│ ├── main.xml
│ └── pull_to_refresh_list.xml
└── values
│ └── strings.xml
└── src
└── com
└── pullToRefresh
├── Main.java
├── NoRefreshListener.java
├── OnPullingAction.java
├── OnReleaseReady.java
├── PullToRefreshComponent.java
├── PullToRefreshListView.java
├── PullToRefreshState.java
├── PullingDownState.java
├── PullingUpState.java
├── RefreshListener.java
├── RefreshingState.java
├── ScrollingState.java
└── utils
└── Pixel.java
/PullToRefresh/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PullToRefresh/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | PullToRefresh
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/PullToRefresh/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/PullToRefresh/bin/PullToRefresh.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/bin/PullToRefresh.apk
--------------------------------------------------------------------------------
/PullToRefresh/bin/classes.dex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/bin/classes.dex
--------------------------------------------------------------------------------
/PullToRefresh/bin/resources.ap_:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/bin/resources.ap_
--------------------------------------------------------------------------------
/PullToRefresh/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-4
12 |
--------------------------------------------------------------------------------
/PullToRefresh/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class * extends android.app.backup.BackupAgentHelper
14 | -keep public class * extends android.preference.Preference
15 | -keep public class com.android.vending.licensing.ILicensingService
16 |
17 | -keepclasseswithmembernames class * {
18 | native ;
19 | }
20 |
21 | -keepclasseswithmembernames class * {
22 | public (android.content.Context, android.util.AttributeSet);
23 | }
24 |
25 | -keepclasseswithmembernames class * {
26 | public (android.content.Context, android.util.AttributeSet, int);
27 | }
28 |
29 | -keepclassmembers enum * {
30 | public static **[] values();
31 | public static ** valueOf(java.lang.String);
32 | }
33 |
34 | -keep class * implements android.os.Parcelable {
35 | public static final android.os.Parcelable$Creator *;
36 | }
37 |
--------------------------------------------------------------------------------
/PullToRefresh/res/drawable-hdpi/ic_pulltorefresh_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/res/drawable-hdpi/ic_pulltorefresh_arrow.png
--------------------------------------------------------------------------------
/PullToRefresh/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/PullToRefresh/res/drawable-ldpi/ic_pulltorefresh_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/res/drawable-ldpi/ic_pulltorefresh_arrow.png
--------------------------------------------------------------------------------
/PullToRefresh/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/PullToRefresh/res/drawable-mdpi/ic_pulltorefresh_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/res/drawable-mdpi/ic_pulltorefresh_arrow.png
--------------------------------------------------------------------------------
/PullToRefresh/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guillep/PullToRefresh/3b6be414370989ebecd3b8c3301d0e8f3af6c879/PullToRefresh/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/PullToRefresh/res/drawable/pull_to_refresh_header_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
18 |
22 |
--------------------------------------------------------------------------------
/PullToRefresh/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/PullToRefresh/res/layout/pull_to_refresh_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
18 |
23 |
25 |
31 |
36 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
60 |
61 |
62 |
65 |
70 |
72 |
78 |
83 |
90 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/PullToRefresh/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | PullToRefresh
4 | Pull to refresh...
5 | Pull to refresh...
6 | Release to refresh...
7 | Refreshing...
8 |
9 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/Main.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | import android.app.ListActivity;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.view.ViewGroup;
7 | import android.widget.ArrayAdapter;
8 |
9 | import com.pull.R;
10 |
11 | public class Main extends ListActivity {
12 | private PullToRefreshComponent pullToRefresh;
13 | private ArrayAdapter adapter;
14 |
15 | /** Called when the activity is first created. */
16 | @Override
17 | public void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | this.setContentView(R.layout.main);
20 | ViewGroup upperButton = (ViewGroup) this
21 | .findViewById(R.id.refresh_upper_button);
22 | ViewGroup lowerButton = (ViewGroup) this
23 | .findViewById(R.id.refresh_lower_button);
24 | this.adapter = new ArrayAdapter(this,
25 | android.R.layout.simple_list_item_1);
26 | this.getListView().setAdapter(this.adapter);
27 |
28 | this.pullToRefresh = new PullToRefreshComponent(upperButton,
29 | lowerButton, this.getListView(), new Handler());
30 | this.pullToRefresh.setOnPullDownRefreshAction(new RefreshListener() {
31 |
32 | @Override
33 | public void refreshFinished() {
34 | Main.this.runOnUiThread(new Runnable() {
35 |
36 | @Override
37 | public void run() {
38 | Main.this.adapter.add("itemm from pull down");
39 | }
40 | });
41 | }
42 |
43 | @Override
44 | public void doRefresh() {
45 | try {
46 | Thread.sleep(1500);
47 | } catch (InterruptedException e) {
48 | e.printStackTrace();
49 | }
50 | }
51 | });
52 |
53 | this.pullToRefresh.setOnPullUpRefreshAction(new RefreshListener() {
54 |
55 | @Override
56 | public void refreshFinished() {
57 | Main.this.runOnUiThread(new Runnable() {
58 |
59 | @Override
60 | public void run() {
61 | Main.this.adapter.add("itemm from the up");
62 | }
63 | });
64 | }
65 |
66 | @Override
67 | public void doRefresh() {
68 | try {
69 | Thread.sleep(1500);
70 | } catch (InterruptedException e) {
71 | e.printStackTrace();
72 | }
73 | }
74 | });
75 | }
76 | }
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/NoRefreshListener.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | public class NoRefreshListener implements RefreshListener {
4 |
5 | @Override
6 | public void doRefresh() {
7 | }
8 |
9 | @Override
10 | public void refreshFinished() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/OnPullingAction.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | public interface OnPullingAction {
4 |
5 | void handlePull(boolean down, int height);
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/OnReleaseReady.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | public interface OnReleaseReady {
4 |
5 | void releaseReady(boolean ready);
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/PullToRefreshComponent.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | import java.util.Date;
4 |
5 | import android.os.Handler;
6 | import android.util.Log;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 | import android.view.View.OnTouchListener;
10 | import android.widget.ListView;
11 |
12 | import com.pullToRefresh.utils.Pixel;
13 |
14 | public class PullToRefreshComponent {
15 |
16 | private static final int EVENT_COUNT = 3;
17 | protected static final float MIN_PULL_ELEMENT_HEIGHT = 100;
18 | protected static final float MAX_PULL_ELEMENT_HEIGHT = 200;
19 | private static final float PULL_ELEMENT_STANDBY_HEIGHT = 100;
20 | protected static int firstVisibleItem = 0;
21 |
22 | private View upperView;
23 | private View lowerView;
24 | private ListView listView;
25 | private Handler uiThreadHandler;
26 |
27 | private float[] lastYs = new float[EVENT_COUNT];
28 |
29 | private RefreshListener onPullDownRefreshAction = new NoRefreshListener();
30 | private RefreshListener onPullUpRefreshAction = new NoRefreshListener();
31 |
32 | protected ScrollingState state;
33 | private boolean mayPullUpToRefresh = true;
34 | private boolean mayPullDownToRefresh;
35 | private OnReleaseReady onReleaseLowerReady;
36 | private OnReleaseReady onReleaseUpperReady;
37 |
38 | public PullToRefreshComponent(View upperView, View lowerView,
39 | ListView listView, Handler uiThreadHandler) {
40 | this.upperView = upperView;
41 | this.lowerView = lowerView;
42 | this.listView = listView;
43 | this.uiThreadHandler = uiThreadHandler;
44 | this.initialize();
45 | }
46 |
47 | private void initialize() {
48 | this.state = new PullToRefreshState();
49 | this.listView.setOnTouchListener(new OnTouchListener() {
50 |
51 | @Override
52 | public boolean onTouch(View v, MotionEvent event) {
53 | if (event.getAction() == MotionEvent.ACTION_UP) {
54 | PullToRefreshComponent.this.initializeYsHistory();
55 | return PullToRefreshComponent.this.state.touchStopped(
56 | event, PullToRefreshComponent.this);
57 | } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
58 | return PullToRefreshComponent.this.state.handleMovement(
59 | event, PullToRefreshComponent.this);
60 | }
61 | return false;
62 | }
63 | });
64 | }
65 |
66 | protected float average(float[] ysArray) {
67 | float avg = 0;
68 | for (int i = 0; i < EVENT_COUNT; i++) {
69 | avg += ysArray[i];
70 | }
71 | return avg / EVENT_COUNT;
72 | }
73 |
74 | public void beginPullDownRefresh() {
75 | this.beginRefresh(this.upperView, this.onPullDownRefreshAction);
76 | }
77 |
78 | private void beginRefresh(View viewToUpdate,
79 | final RefreshListener refreshAction) {
80 | android.view.ViewGroup.LayoutParams params = viewToUpdate
81 | .getLayoutParams();
82 | params.height = (int) PULL_ELEMENT_STANDBY_HEIGHT;
83 | viewToUpdate.setLayoutParams(params);
84 | Log.i("PullDown", "refreshing");
85 | this.state = new RefreshingState();
86 | new Thread(new Runnable() {
87 | @Override
88 | public void run() {
89 | try {
90 | Date start = new Date();
91 | refreshAction.doRefresh();
92 | Date finish = new Date();
93 | long difference = finish.getTime() - start.getTime();
94 | try {
95 | Thread.sleep(Math.max(difference, 1500));
96 | } catch (InterruptedException e) {
97 | }
98 | } catch (RuntimeException e) {
99 | Log.e("Error", e.getMessage(), e);
100 | throw e;
101 | } finally {
102 | PullToRefreshComponent.this.runOnUiThread(new Runnable() {
103 | @Override
104 | public void run() {
105 | PullToRefreshComponent.this
106 | .refreshFinished(refreshAction);
107 | }
108 | });
109 | }
110 | }
111 | }).start();
112 | }
113 |
114 | public void beginPullUpRefresh() {
115 | this.beginRefresh(this.lowerView, this.onPullUpRefreshAction);
116 | }
117 |
118 | /**************************************************************/
119 | // Listeners
120 | /**************************************************************/
121 |
122 | public void setOnPullDownRefreshAction(RefreshListener onRefreshAction) {
123 | this.enablePullDownToRefresh();
124 | this.onPullDownRefreshAction = onRefreshAction;
125 | }
126 |
127 | public void setOnPullUpRefreshAction(RefreshListener onRefreshAction) {
128 | this.enablePullUpToRefresh();
129 | this.onPullUpRefreshAction = onRefreshAction;
130 | }
131 |
132 | protected void refreshFinished(final RefreshListener refreshAction) {
133 | Log.i("PullDown", "ready");
134 | this.state = new PullToRefreshState();
135 | this.initializeYsHistory();
136 | this.runOnUiThread(new Runnable() {
137 | @Override
138 | public void run() {
139 | float dp = new Pixel(0, PullToRefreshComponent.this.listView
140 | .getResources()).toDp();
141 | PullToRefreshComponent.this.setUpperButtonHeight(dp);
142 | PullToRefreshComponent.this.setLowerButtonHeight(dp);
143 | refreshAction.refreshFinished();
144 | }
145 | });
146 |
147 | }
148 |
149 | private void runOnUiThread(Runnable runnable) {
150 | this.uiThreadHandler.post(runnable);
151 | }
152 |
153 | synchronized void setUpperButtonHeight(float height) {
154 | this.setHeight(height, this.upperView);
155 | }
156 |
157 | synchronized void setLowerButtonHeight(float height) {
158 | this.setHeight(height, this.lowerView);
159 | }
160 |
161 | private void setHeight(float height, View view) {
162 | if (view == null) {
163 | return;
164 | }
165 | android.view.ViewGroup.LayoutParams params = view.getLayoutParams();
166 | if (params == null) {
167 | return;
168 | }
169 | params.height = (int) height;
170 | view.setLayoutParams(params);
171 | view.getParent().requestLayout();
172 | }
173 |
174 | public int getListTop() {
175 | return this.listView.getTop();
176 | }
177 |
178 | public void initializeYsHistory() {
179 | for (int i = 0; i < EVENT_COUNT; i++) {
180 | PullToRefreshComponent.this.lastYs[i] = 0;
181 | }
182 | }
183 |
184 | /**************************************************************/
185 | // HANDLE PULLING
186 | /**************************************************************/
187 |
188 | public void pullDown(MotionEvent event, float firstY) {
189 | float averageY = PullToRefreshComponent.this
190 | .average(PullToRefreshComponent.this.lastYs);
191 |
192 | int height = (int) Math.max(
193 | Math.min(averageY - firstY, MAX_PULL_ELEMENT_HEIGHT), 0);
194 | PullToRefreshComponent.this.setUpperButtonHeight(height);
195 | }
196 |
197 | public void pullUp(MotionEvent event, float firstY) {
198 | float averageY = PullToRefreshComponent.this
199 |
200 | .average(PullToRefreshComponent.this.lastYs);
201 |
202 | int height = (int) Math.max(
203 | Math.min(firstY - averageY, MAX_PULL_ELEMENT_HEIGHT), 0);
204 | PullToRefreshComponent.this.setLowerButtonHeight(height);
205 | }
206 |
207 | public boolean isPullingDownToRefresh() {
208 | return this.mayPullDownToRefresh && this.isIncremental()
209 | && this.isFirstVisible();
210 | }
211 |
212 | public boolean isPullingUpToRefresh() {
213 | return this.mayPullUpToRefresh && this.isDecremental()
214 | && this.isLastVisible();
215 | }
216 |
217 | private boolean isFirstVisible() {
218 | if (this.listView.getCount() == 0) {
219 | return true;
220 | } else if (this.listView.getFirstVisiblePosition() == 0) {
221 | return this.listView.getChildAt(0).getTop() >= this.listView
222 | .getTop();
223 | } else {
224 | return false;
225 | }
226 | }
227 |
228 | private boolean isLastVisible() {
229 | if (this.listView.getCount() == 0) {
230 | return true;
231 | } else if (this.listView.getLastVisiblePosition() + 1 == this.listView
232 | .getCount()) {
233 | return this.listView.getChildAt(this.listView.getChildCount() - 1)
234 | .getBottom() <= this.listView.getBottom();
235 | } else {
236 | return false;
237 | }
238 | }
239 |
240 | private boolean isIncremental(int from, int to, int step) {
241 | float realFrom = this.lastYs[from];
242 | float realTo = this.lastYs[to];
243 | Log.i("pull to refresh", "scrolling from " + String.valueOf(realFrom));
244 | Log.i("pull to refresh", "scrolling to " + String.valueOf(realTo));
245 | return this.lastYs[from] != 0 && realTo != 0
246 | && Math.abs(realFrom - realTo) > 50 && realFrom * step < realTo;
247 | }
248 |
249 | private boolean isIncremental() {
250 | return this.isIncremental(0, EVENT_COUNT - 1, +1);
251 | }
252 |
253 | private boolean isDecremental() {
254 | return this.isIncremental(0, EVENT_COUNT - 1, -1);
255 | }
256 |
257 | public void updateEventStates(MotionEvent event) {
258 | for (int i = 0; i < EVENT_COUNT - 1; i++) {
259 | PullToRefreshComponent.this.lastYs[i] = PullToRefreshComponent.this.lastYs[i + 1];
260 | }
261 |
262 | float y = event.getY();
263 | int top = PullToRefreshComponent.this.listView.getTop();
264 | Log.i("Pulltorefresh", "event y:" + String.valueOf(y));
265 | Log.i("Pulltorefresh", "list top:" + String.valueOf(top));
266 | PullToRefreshComponent.this.lastYs[EVENT_COUNT - 1] = y + top;
267 | }
268 |
269 | /**************************************************************/
270 | // State Change
271 | /**************************************************************/
272 |
273 | public void setPullingDown(MotionEvent event) {
274 | Log.i("PullDown", "pulling down");
275 | this.state = new PullingDownState(event);
276 | }
277 |
278 | public void setPullingUp(MotionEvent event) {
279 | Log.i("PullDown", "pulling up");
280 | this.state = new PullingUpState(event);
281 | }
282 |
283 | public float getBottomViewHeight() {
284 | return this.lowerView.getHeight();
285 | }
286 |
287 | public RefreshListener getOnUpperRefreshAction() {
288 | return this.onPullDownRefreshAction;
289 | }
290 |
291 | public RefreshListener getOnLowerRefreshAction() {
292 | return this.onPullUpRefreshAction;
293 | }
294 |
295 | public void disablePullUpToRefresh() {
296 | this.mayPullUpToRefresh = false;
297 | }
298 |
299 | public void disablePullDownToRefresh() {
300 | this.mayPullDownToRefresh = false;
301 | }
302 |
303 | public void enablePullUpToRefresh() {
304 | this.mayPullUpToRefresh = true;
305 | }
306 |
307 | public void enablePullDownToRefresh() {
308 | this.mayPullDownToRefresh = true;
309 | }
310 |
311 | public void setOnReleaseUpperReady(OnReleaseReady onReleaseUpperReady) {
312 | this.onReleaseUpperReady = onReleaseUpperReady;
313 | }
314 |
315 | public void setOnReleaseLowerReady(OnReleaseReady onReleaseUpperReady) {
316 | this.onReleaseLowerReady = onReleaseUpperReady;
317 | }
318 |
319 | public void readyToReleaseUpper(boolean ready) {
320 | if (this.onReleaseUpperReady != null) {
321 | this.onReleaseUpperReady.releaseReady(ready);
322 | }
323 | }
324 |
325 | public void readyToReleaseLower(boolean ready) {
326 | if (this.onReleaseLowerReady != null) {
327 | this.onReleaseLowerReady.releaseReady(ready);
328 | }
329 | }
330 | }
331 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/PullToRefreshListView.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.util.AttributeSet;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ListView;
10 | import android.widget.RelativeLayout;
11 | import android.widget.TextView;
12 |
13 | import com.pull.R;
14 |
15 | public class PullToRefreshListView extends RelativeLayout {
16 |
17 | private PullToRefreshComponent pullToRefresh;
18 | private ViewGroup upperButton;
19 | private ViewGroup lowerButton;
20 | private Handler uiThreadHandler;
21 | private ListView listView;
22 |
23 | public PullToRefreshListView(Context context, AttributeSet attrs) {
24 | super(context, attrs);
25 | LayoutInflater inflater = (LayoutInflater) context
26 | .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
27 | inflater.inflate(R.layout.pull_to_refresh_list, this);
28 | this.listView = (ListView) this.findViewById(android.R.id.list);
29 | this.uiThreadHandler = new Handler();
30 | this.initializePullToRefreshList();
31 | }
32 |
33 | private void initializePullToRefreshList() {
34 | this.initializeRefreshUpperButton();
35 | this.initializeRefreshLowerButton();
36 | this.pullToRefresh = new com.pullToRefresh.PullToRefreshComponent(
37 | this.upperButton, this.lowerButton, this.listView,
38 | this.uiThreadHandler);
39 |
40 | this.pullToRefresh.setOnReleaseUpperReady(new OnReleaseReady() {
41 | @Override
42 | public void releaseReady(boolean ready) {
43 | if (ready) {
44 | ((TextView) PullToRefreshListView.this.upperButton
45 | .findViewById(R.id.pull_to_refresh_text))
46 | .setText(R.string.pull_to_refresh_release_label);
47 | } else {
48 | ((TextView) PullToRefreshListView.this.upperButton
49 | .findViewById(R.id.pull_to_refresh_text))
50 | .setText(R.string.pull_to_refresh_pull_down_label);
51 | }
52 | }
53 | });
54 |
55 | this.pullToRefresh.setOnReleaseLowerReady(new OnReleaseReady() {
56 | @Override
57 | public void releaseReady(boolean ready) {
58 | if (ready) {
59 | ((TextView) PullToRefreshListView.this.lowerButton
60 | .findViewById(R.id.pull_to_refresh_text))
61 | .setText(R.string.pull_to_refresh_release_label);
62 | } else {
63 | ((TextView) PullToRefreshListView.this.lowerButton
64 | .findViewById(R.id.pull_to_refresh_text))
65 | .setText(R.string.pull_to_refresh_pull_up_label);
66 | }
67 | }
68 | });
69 | }
70 |
71 | public void setOnPullDownRefreshAction(final RefreshListener listener) {
72 | this.pullToRefresh.setOnPullDownRefreshAction(new RefreshListener() {
73 |
74 | @Override
75 | public void refreshFinished() {
76 | PullToRefreshListView.this.runOnUIThread(new Runnable() {
77 |
78 | @Override
79 | public void run() {
80 | PullToRefreshListView.this
81 | .setPullToRefresh(PullToRefreshListView.this.upperButton);
82 | PullToRefreshListView.this.invalidate();
83 | }
84 |
85 | });
86 | PullToRefreshListView.this.runOnUIThread(new Runnable() {
87 |
88 | @Override
89 | public void run() {
90 | listener.refreshFinished();
91 | }
92 | });
93 | }
94 |
95 | @Override
96 | public void doRefresh() {
97 | PullToRefreshListView.this.uiThreadHandler.post(new Runnable() {
98 | @Override
99 | public void run() {
100 | PullToRefreshListView.this
101 | .setRefreshing(PullToRefreshListView.this.upperButton);
102 | PullToRefreshListView.this.invalidate();
103 | }
104 | });
105 | listener.doRefresh();
106 | }
107 | });
108 | }
109 |
110 | protected void runOnUIThread(Runnable runnable) {
111 | this.uiThreadHandler.post(runnable);
112 | }
113 |
114 | public void setOnPullUpRefreshAction(final RefreshListener listener) {
115 | this.pullToRefresh.setOnPullUpRefreshAction(new RefreshListener() {
116 |
117 | @Override
118 | public void refreshFinished() {
119 | PullToRefreshListView.this
120 | .setPullToRefresh(PullToRefreshListView.this.lowerButton);
121 | PullToRefreshListView.this.invalidate();
122 | listener.refreshFinished();
123 | }
124 |
125 | @Override
126 | public void doRefresh() {
127 | PullToRefreshListView.this.uiThreadHandler.post(new Runnable() {
128 | @Override
129 | public void run() {
130 | PullToRefreshListView.this
131 | .setRefreshing(PullToRefreshListView.this.lowerButton);
132 | PullToRefreshListView.this.invalidate();
133 | }
134 | });
135 | listener.doRefresh();
136 | }
137 | });
138 | }
139 |
140 | private void initializeRefreshLowerButton() {
141 | this.upperButton = (ViewGroup) this
142 | .findViewById(R.id.refresh_upper_button);
143 | }
144 |
145 | private void initializeRefreshUpperButton() {
146 | this.lowerButton = (ViewGroup) this
147 | .findViewById(R.id.refresh_lower_button);
148 | }
149 |
150 | protected void setPullToRefresh(ViewGroup refreshView) {
151 | int text = 0;
152 | if (refreshView == this.upperButton) {
153 | text = R.string.pull_to_refresh_pull_down_label;
154 | } else {
155 | text = R.string.pull_to_refresh_pull_up_label;
156 | }
157 | ((TextView) refreshView.findViewById(R.id.pull_to_refresh_text))
158 | .setText(text);
159 | refreshView.findViewById(R.id.pull_to_refresh_progress).setVisibility(
160 | View.INVISIBLE);
161 | refreshView.findViewById(R.id.pull_to_refresh_image).setVisibility(
162 | View.VISIBLE);
163 | }
164 |
165 | protected void setRefreshing(ViewGroup refreshView) {
166 | ((TextView) refreshView.findViewById(R.id.pull_to_refresh_text))
167 | .setText(R.string.pull_to_refresh_refreshing_label);
168 | refreshView.findViewById(R.id.pull_to_refresh_progress).setVisibility(
169 | View.VISIBLE);
170 | refreshView.findViewById(R.id.pull_to_refresh_image).setVisibility(
171 | View.INVISIBLE);
172 | }
173 |
174 | public void disablePullUpToRefresh() {
175 | this.pullToRefresh.disablePullUpToRefresh();
176 | }
177 |
178 | public void disablePullDownToRefresh() {
179 | this.pullToRefresh.disablePullDownToRefresh();
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/PullToRefreshState.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | import android.view.MotionEvent;
4 |
5 | public class PullToRefreshState implements ScrollingState {
6 |
7 | @Override
8 | public boolean touchStopped(MotionEvent event,
9 | PullToRefreshComponent onTouchListener) {
10 | return false;
11 | }
12 |
13 | @Override
14 | public boolean handleMovement(MotionEvent event,
15 | PullToRefreshComponent pullToRefreshComponent) {
16 | pullToRefreshComponent.updateEventStates(event);
17 | if (pullToRefreshComponent.isPullingDownToRefresh()) {
18 | pullToRefreshComponent.setPullingDown(event);
19 | return true;
20 | } else if (pullToRefreshComponent.isPullingUpToRefresh()) {
21 | pullToRefreshComponent.setPullingUp(event);
22 | return true;
23 | }
24 | return false;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/PullingDownState.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | import android.view.MotionEvent;
4 |
5 | public class PullingDownState implements ScrollingState {
6 |
7 | private float firstY;
8 |
9 | public PullingDownState(MotionEvent event) {
10 | this.firstY = event.getY();
11 | }
12 |
13 | @Override
14 | public boolean touchStopped(MotionEvent event,
15 | PullToRefreshComponent pullToRefreshComponent) {
16 | if (pullToRefreshComponent.getListTop() > PullToRefreshComponent.MIN_PULL_ELEMENT_HEIGHT) {
17 | pullToRefreshComponent.beginPullDownRefresh();
18 | } else {
19 | pullToRefreshComponent.refreshFinished(pullToRefreshComponent
20 | .getOnUpperRefreshAction());
21 | }
22 | return true;
23 | }
24 |
25 | @Override
26 | public boolean handleMovement(MotionEvent event,
27 | PullToRefreshComponent pullToRefreshComponent) {
28 | pullToRefreshComponent.updateEventStates(event);
29 | pullToRefreshComponent.pullDown(event, this.firstY);
30 | pullToRefreshComponent.readyToReleaseUpper(pullToRefreshComponent
31 | .getListTop() > PullToRefreshComponent.MIN_PULL_ELEMENT_HEIGHT);
32 | return true;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/PullingUpState.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | import android.view.MotionEvent;
4 |
5 | public class PullingUpState implements ScrollingState {
6 |
7 | private float firstY;
8 |
9 | public PullingUpState(MotionEvent event) {
10 | this.firstY = event.getY();
11 | }
12 |
13 | @Override
14 | public boolean touchStopped(MotionEvent event,
15 | PullToRefreshComponent pullToRefreshComponent) {
16 | if (pullToRefreshComponent.getBottomViewHeight() > PullToRefreshComponent.MIN_PULL_ELEMENT_HEIGHT) {
17 | pullToRefreshComponent.beginPullUpRefresh();
18 | } else {
19 | pullToRefreshComponent.refreshFinished(pullToRefreshComponent
20 | .getOnLowerRefreshAction());
21 | }
22 | return true;
23 | }
24 |
25 | @Override
26 | public boolean handleMovement(MotionEvent event,
27 | PullToRefreshComponent pullToRefreshComponent) {
28 | pullToRefreshComponent.updateEventStates(event);
29 | pullToRefreshComponent.pullUp(event, this.firstY);
30 | pullToRefreshComponent
31 | .readyToReleaseLower(pullToRefreshComponent
32 | .getBottomViewHeight() > PullToRefreshComponent.MIN_PULL_ELEMENT_HEIGHT);
33 | return true;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/RefreshListener.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | public interface RefreshListener {
4 |
5 | void doRefresh();
6 |
7 | void refreshFinished();
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/RefreshingState.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | import android.view.MotionEvent;
4 |
5 | public class RefreshingState implements ScrollingState {
6 |
7 | @Override
8 | public boolean touchStopped(MotionEvent event,
9 | PullToRefreshComponent pullToRefreshComponent) {
10 | return true;
11 | }
12 |
13 | @Override
14 | public boolean handleMovement(MotionEvent event,
15 | PullToRefreshComponent pullToRefreshComponent) {
16 | return true;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/ScrollingState.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh;
2 |
3 | import android.view.MotionEvent;
4 |
5 | public interface ScrollingState {
6 |
7 | boolean touchStopped(MotionEvent event,
8 | PullToRefreshComponent pullToRefreshComponent);
9 |
10 | boolean handleMovement(MotionEvent event,
11 | PullToRefreshComponent pullToRefreshComponent);
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/PullToRefresh/src/com/pullToRefresh/utils/Pixel.java:
--------------------------------------------------------------------------------
1 | package com.pullToRefresh.utils;
2 |
3 | import android.content.res.Resources;
4 |
5 | public class Pixel {
6 |
7 | private Resources resources;
8 | private int value;
9 |
10 | public Pixel(int value, Resources resources) {
11 | this.value = value;
12 | this.resources = resources;
13 | }
14 |
15 | public float toDp() {
16 | return this.value * this.resources.getDisplayMetrics().density + 0.5f;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------