├── AndroidManifest.xml
├── LICENSE
├── PullToRefreshDemo
├── PullRefreshDemo.apk
├── PullRefreshDemo
│ ├── .classpath
│ ├── .project
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── libs
│ │ └── android-support-v4.jar
│ ├── proguard-project.txt
│ ├── project.properties
│ ├── res
│ │ ├── anim
│ │ │ ├── pull_arrow_down.xml
│ │ │ ├── pull_arrow_up.xml
│ │ │ └── update_loading_progressbar_anim.xml
│ │ ├── drawable-hdpi
│ │ │ ├── default_ptr_rotate.png
│ │ │ ├── ic_launcher.png
│ │ │ ├── xsearch_loading.png
│ │ │ └── xsearch_msg_pull_arrow_down.png
│ │ ├── drawable-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ ├── pull_refresh_webview.xml
│ │ │ ├── pull_to_load_footer.xml
│ │ │ ├── pull_to_refresh_header.xml
│ │ │ └── pull_to_refresh_header2.xml
│ │ ├── menu
│ │ │ └── activity_main.xml
│ │ ├── values-sw600dp
│ │ │ └── dimens.xml
│ │ ├── values-sw720dp-land
│ │ │ └── dimens.xml
│ │ ├── values-v11
│ │ │ └── styles.xml
│ │ ├── values-v14
│ │ │ └── styles.xml
│ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── picture_dimens.xml
│ │ │ ├── pull_refresh_strings.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ └── src
│ │ └── com
│ │ └── lee
│ │ └── pullrefresh
│ │ ├── MainActivity.java
│ │ ├── PullRefreshListViewActivity.java
│ │ ├── PullRefreshScrollViewActivity.java
│ │ ├── PullRefreshWebViewActivity.java
│ │ └── ui
│ │ ├── FooterLoadingLayout.java
│ │ ├── HeaderLoadingLayout.java
│ │ ├── ILoadingLayout.java
│ │ ├── IPullToRefresh.java
│ │ ├── LoadingLayout.java
│ │ ├── PullToRefreshBase.java
│ │ ├── PullToRefreshGridView.java
│ │ ├── PullToRefreshListView.java
│ │ ├── PullToRefreshScrollView.java
│ │ ├── PullToRefreshWebView.java
│ │ └── RotateLoadingLayout.java
└── source.zip
├── README.md
├── bin
├── AndroidManifest.xml
├── OrderDishes.apk
├── classes.dex
├── classes
│ └── com
│ │ └── example
│ │ └── orderdishes
│ │ ├── BuildConfig.class
│ │ ├── MainActivity$1.class
│ │ ├── MainActivity$2.class
│ │ ├── MainActivity$GridAdapter.class
│ │ ├── MainActivity.class
│ │ ├── R$attr.class
│ │ ├── R$drawable.class
│ │ ├── R$id.class
│ │ ├── R$layout.class
│ │ ├── R$menu.class
│ │ ├── R$string.class
│ │ ├── R$style.class
│ │ └── R.class
├── dexedLibs
│ └── android-support-v4-d97d3d4d7255b3ab48cede3c77e494b7.jar
├── jarlist.cache
├── res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ └── drawable-xhdpi
│ │ └── ic_launcher.png
└── resources.ap_
├── gen
└── com
│ └── example
│ └── orderdishes
│ ├── BuildConfig.java
│ └── R.java
├── ic_launcher-web.png
├── libs
└── android-support-v4.jar
├── proguard-project.txt
├── project.properties
├── src
└── com
│ └── example
│ └── orderdishes
│ └── MainActivity.java
└── 未命名绘图.drawio
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo.apk
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | PullRefreshDemo
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 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/ic_launcher-web.png
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/project.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 edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-18
15 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/anim/pull_arrow_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/anim/pull_arrow_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/anim/update_loading_progressbar_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/drawable-hdpi/default_ptr_rotate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/res/drawable-hdpi/default_ptr_rotate.png
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/drawable-hdpi/xsearch_loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/res/drawable-hdpi/xsearch_loading.png
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/drawable-hdpi/xsearch_msg_pull_arrow_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/res/drawable-hdpi/xsearch_msg_pull_arrow_down.png
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/PullRefreshDemo/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
16 |
17 |
25 |
26 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/layout/pull_refresh_webview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/layout/pull_to_load_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
22 |
23 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/layout/pull_to_refresh_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
20 |
28 |
37 |
48 |
49 |
50 |
59 |
60 |
71 |
72 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/layout/pull_to_refresh_header2.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
20 |
21 |
26 |
34 |
43 |
54 |
55 |
56 |
62 |
68 |
69 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/menu/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ff0000
4 |
5 | #33353c
6 | #272830
7 |
8 | #666666
9 |
10 | #ffffffff
11 | #ffffffff
12 | #ff000000
13 | #ffdddddd
14 |
15 | #ffffffff
16 |
17 | #e5ffffff
18 | #e5ffffff
19 | #14000000
20 | #14000000
21 |
22 | #ff333333
23 | #000000
24 |
25 |
26 | #ff202020
27 |
28 | #ffffffff
29 | #00ffffff
30 |
31 | #00ffffff
32 | #33000000
33 |
34 | #00ffffff
35 |
36 |
37 | #ffffffff
38 |
39 |
40 | #686f75
41 |
42 |
43 | #FFFFFF
44 |
45 |
46 | #dedede
47 | #3E3F41
48 |
49 | #525252
50 | #98a1aa
51 | #999999
52 | #222222
53 | #333333
54 | #105dc5
55 |
56 | #E2E2E2
57 |
58 |
59 | #565656
60 | #cecece
61 |
62 | #222222
63 | #e2e2e2
64 |
65 |
66 | #777777
67 |
68 | #cecece
69 |
70 | #ffcecece
71 | #ff222222
72 |
73 |
74 | #4297ff
75 |
76 | #222222
77 |
78 | #626262
79 |
80 | #FFFFFF
81 |
82 | #e5e5e5
83 | #ffffff
84 |
85 | #ffffff
86 | #62A7FF
87 |
88 | #ff222222
89 | #ffa7a7a7
90 |
91 |
92 | #ffff0000
93 | #7f000000
94 |
95 | #ff000000
96 | #ff333333
97 |
98 |
99 | #F9F9F9
100 | #F9F9F9
101 | #C2C2C2
102 |
103 |
104 | #1E88E2
105 | #97A0A8
106 |
107 |
108 | #EEEEEE
109 | #46484A
110 |
111 |
112 | #222222
113 |
114 | #999999
115 | #DDDDDD
116 | #0072ff
117 | #e7e7e7
118 |
119 | #85B7E1
120 | #E6A973
121 | #76AD5A
122 | #eaeaea
123 |
124 | #33e5e5e5
125 | #14000000
126 | #ffffff
127 |
128 |
129 | #888888
130 | #EEEEEE
131 | #222222
132 | #c60c02
133 |
134 |
135 | #ffffff
136 | #e2e2e2
137 | #f5f5f5
138 | #e2e2e2
139 |
140 | #222222
141 | #ABB6BF
142 |
143 | #6A6F73
144 | #999999
145 |
146 | #2A2A2A
147 | #F5F5F5
148 |
149 | #222222
150 |
151 | #e2e2e2
152 | #ffffff
153 | #d8d8d8
154 | #f6f6f6
155 |
156 | #222222
157 | #888888
158 | #555555
159 | #CCCCCC
160 | #61AE1B
161 | #EEEEEE
162 | #4499EA
163 | #1E88E2
164 | #99000000
165 |
166 |
167 | #46484A
168 | #eeeeee
169 | #97a0a8
170 | #000000
171 | #353535
172 |
173 |
174 | #ffffff
175 | #28000000
176 | #222222
177 | #999999
178 | #777777
179 | #F5F5F5
180 | #DCDCDC
181 | #ffffff
182 | #555555
183 | #66555555
184 | #DFDFDF
185 | #4499EA
186 | #999999
187 | #eeeeee
188 | #66000000
189 |
190 |
191 | #33ffffff
192 | #1Affffff
193 |
194 |
195 | #4C000000
196 | #4C000000
197 |
198 |
199 | #FFFFFF
200 | #F2F2F2
201 |
202 |
203 | #0C000000
204 | #4C000000
205 |
206 | #4DAC00
207 | #F43400
208 | #00FFFFFF
209 |
210 |
211 | #F7F7F7
212 | #9c3a20
213 | #484848
214 | #EEEEEE
215 | #111111
216 | #c00b0b
217 | #b45137
218 | #b0000000
219 | #32373a
220 | #646464
221 | #64646464
222 | #08000000
223 | #4DAC00
224 | #EEEEEE
225 | #E4E4E4
226 |
227 |
228 | #4C000000
229 |
230 |
231 | #333333
232 |
233 | #eeeeee
234 |
235 | #80000000
236 |
237 | #14000000
238 |
239 | #999999
240 |
241 | #1effffff
242 |
243 | #c4c4c4
244 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 0dp
5 | 0dp
6 | 3dp
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values/picture_dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 80dp
4 |
5 | 0dp
6 | 48dp
7 |
8 | 16dp
9 |
10 | 12dp
11 |
12 | 12dp
13 |
14 | 8dp
15 | 9dp
16 | 6dp
17 | 5dp
18 | 10dp
19 | 30dp
20 |
21 | 18dp
22 |
23 | 8dp
24 |
25 | 12dp
26 |
27 | 14dp
28 | 10dp
29 | 6dp
30 | 40dp
31 |
32 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 已经到底啦
5 | 松开加载更多
6 | 下拉可以刷新
7 | 松开获取更多
8 | 最后更新时间 :
9 | 正在加载中
10 | 正在加载中…
11 |
12 |
13 | 点击屏幕,重新加载
14 |
15 | 正在加载…
16 |
17 |
18 | @string/pushmsg_center_pull_down_text
19 | 上拉可以刷新
20 | 松开后刷新
21 | @string/pushmsg_center_load_more_ongoing_text
22 | @string/pushmsg_center_pull_down_update_time
23 | 松开载入更多
24 | @string/pull_to_refresh_header_hint_loading
25 | @string/pushmsg_center_no_more_msg
26 | 网络不给力,请检查网络
27 |
28 |
29 | 图片已保存到相册
30 | 保存图片失败
31 | 下一组:
32 | 上一组:
33 |
34 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | PullRefreshDemo
4 |
5 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 |
8 | public class MainActivity extends Activity implements View.OnClickListener {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_main);
14 |
15 | findViewById(R.id.listview).setOnClickListener(this);
16 | findViewById(R.id.webview).setOnClickListener(this);
17 | findViewById(R.id.scrollview).setOnClickListener(this);
18 | }
19 |
20 | @Override
21 | public void onClick(View v) {
22 | switch (v.getId()) {
23 | case R.id.listview:
24 | startActivity(new Intent(this, PullRefreshListViewActivity.class));
25 | break;
26 | case R.id.scrollview:
27 | startActivity(new Intent(this, PullRefreshScrollViewActivity.class));
28 | break;
29 | case R.id.webview:
30 | startActivity(new Intent(this, PullRefreshWebViewActivity.class));
31 | break;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/PullRefreshListViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Arrays;
5 | import java.util.Date;
6 | import java.util.LinkedList;
7 |
8 | import android.app.Activity;
9 | import android.os.AsyncTask;
10 | import android.os.Bundle;
11 | import android.view.View;
12 | import android.widget.AdapterView;
13 | import android.widget.AdapterView.OnItemClickListener;
14 | import android.widget.ArrayAdapter;
15 | import android.widget.ListView;
16 | import android.widget.Toast;
17 |
18 | import com.lee.pullrefresh.ui.PullToRefreshBase;
19 | import com.lee.pullrefresh.ui.PullToRefreshBase.OnRefreshListener;
20 | import com.lee.pullrefresh.ui.PullToRefreshListView;
21 |
22 | public class PullRefreshListViewActivity extends Activity {
23 |
24 | private ListView mListView;
25 | private PullToRefreshListView mPullListView;
26 | private ArrayAdapter mAdapter;
27 | private LinkedList mListItems;
28 | private SimpleDateFormat mDateFormat = new SimpleDateFormat("MM-dd HH:mm");
29 | private boolean mIsStart = true;
30 | private int mCurIndex = 0;
31 | private static final int mLoadDataCount = 100;
32 |
33 | @Override
34 | public void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 |
37 | mPullListView = new PullToRefreshListView(this);
38 | setContentView(mPullListView);
39 |
40 | mPullListView.setPullLoadEnabled(false);
41 | mPullListView.setScrollLoadEnabled(true);
42 |
43 | mCurIndex = mLoadDataCount;
44 | mListItems = new LinkedList();
45 | mListItems.addAll(Arrays.asList(mStrings).subList(0, mCurIndex));
46 | mAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, mListItems);
47 | mListView = mPullListView.getRefreshableView();
48 | mListView.setAdapter(mAdapter);
49 | mListView.setOnItemClickListener(new OnItemClickListener() {
50 | @Override
51 | public void onItemClick(AdapterView> arg0, View view, int position, long id) {
52 | String text = mListItems.get(position) + ", index = " + (position + 1);
53 | Toast.makeText(PullRefreshListViewActivity.this, text, Toast.LENGTH_SHORT).show();
54 | }
55 | });
56 |
57 | mPullListView.setOnRefreshListener(new OnRefreshListener() {
58 | @Override
59 | public void onPullDownToRefresh(PullToRefreshBase refreshView) {
60 | mIsStart = true;
61 | new GetDataTask().execute();
62 | }
63 |
64 | @Override
65 | public void onPullUpToRefresh(PullToRefreshBase refreshView) {
66 | mIsStart = false;
67 | new GetDataTask().execute();
68 | }
69 | });
70 | setLastUpdateTime();
71 |
72 | mPullListView.doPullRefreshing(true, 500);
73 | }
74 |
75 | private class GetDataTask extends AsyncTask {
76 |
77 | @Override
78 | protected String[] doInBackground(Void... params) {
79 | // Simulates a background job.
80 | try {
81 | Thread.sleep(3000);
82 | } catch (InterruptedException e) {
83 | }
84 | return mStrings;
85 | }
86 |
87 | @Override
88 | protected void onPostExecute(String[] result) {
89 | boolean hasMoreData = true;
90 | if (mIsStart) {
91 | mListItems.addFirst("Added after refresh...");
92 | } else {
93 | int start = mCurIndex;
94 | int end = mCurIndex + mLoadDataCount;
95 | if (end >= mStrings.length) {
96 | end = mStrings.length;
97 | hasMoreData = false;
98 | }
99 |
100 | for (int i = start; i < end; ++i) {
101 | mListItems.add(mStrings[i]);
102 | }
103 |
104 | mCurIndex = end;
105 | }
106 |
107 | mAdapter.notifyDataSetChanged();
108 | mPullListView.onPullDownRefreshComplete();
109 | mPullListView.onPullUpRefreshComplete();
110 | mPullListView.setHasMoreData(hasMoreData);
111 | setLastUpdateTime();
112 |
113 | super.onPostExecute(result);
114 | }
115 | }
116 |
117 | private void setLastUpdateTime() {
118 | String text = formatDateTime(System.currentTimeMillis());
119 | mPullListView.setLastUpdatedLabel(text);
120 | }
121 |
122 | private String formatDateTime(long time) {
123 | if (0 == time) {
124 | return "";
125 | }
126 |
127 | return mDateFormat.format(new Date(time));
128 | }
129 |
130 | public static final String[] mStrings = {
131 | "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
132 | "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
133 | "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
134 | "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
135 | "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
136 | "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
137 | "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
138 | "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
139 | "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
140 | "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
141 | "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
142 | "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
143 | "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
144 | "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
145 | "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
146 | "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
147 | "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
148 | "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
149 | "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
150 | "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
151 | "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
152 | "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
153 | "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
154 | "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
155 | "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
156 | "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
157 | "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
158 | "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
159 | "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
160 | "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
161 | "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
162 | "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
163 | "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
164 | "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
165 | "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
166 | "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
167 | "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
168 | "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
169 | "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
170 | "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
171 | "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
172 | "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
173 | "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
174 | "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
175 | "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
176 | "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
177 | "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
178 | "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
179 | "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
180 | "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
181 | "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
182 | "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
183 | "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
184 | "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
185 | "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
186 | "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
187 | "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
188 | "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
189 | "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
190 | "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
191 | "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
192 | "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
193 | "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
194 | "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
195 | "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
196 | "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
197 | "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
198 | "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
199 | "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
200 | "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
201 | "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
202 | "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
203 | "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
204 | "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
205 | "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
206 | "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
207 | "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
208 | "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
209 | "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
210 | "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
211 | "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
212 | "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
213 | "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
214 | "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
215 | "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
216 | "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
217 | "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
218 | "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
219 | "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
220 | "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
221 | "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
222 | "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
223 | "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
224 | "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
225 | "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
226 | "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
227 | "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
228 | "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
229 | "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
230 | "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
231 | "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
232 | "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
233 | "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
234 | "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
235 | "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
236 | "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
237 | "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
238 | "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
239 | "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
240 | "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
241 | "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
242 | "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
243 | "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
244 | "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
245 | "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
246 | "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
247 | "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
248 | "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
249 | "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
250 | "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
251 | "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
252 | "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
253 | "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
254 | "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
255 | "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
256 | "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
257 | "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
258 | "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
259 | "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
260 | "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
261 | };
262 | }
263 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/PullRefreshScrollViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 |
6 | import android.app.Activity;
7 | import android.graphics.Color;
8 | import android.os.AsyncTask;
9 | import android.os.Bundle;
10 | import android.widget.ScrollView;
11 | import android.widget.TextView;
12 |
13 | import com.lee.pullrefresh.ui.PullToRefreshBase;
14 | import com.lee.pullrefresh.ui.PullToRefreshBase.OnRefreshListener;
15 | import com.lee.pullrefresh.ui.PullToRefreshScrollView;
16 |
17 | public class PullRefreshScrollViewActivity extends Activity {
18 |
19 | private ScrollView mScrollView;
20 | private PullToRefreshScrollView mPullScrollView;
21 | private SimpleDateFormat mDateFormat = new SimpleDateFormat("MM-dd HH:mm");
22 |
23 | @Override
24 | public void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 |
27 | mPullScrollView = new PullToRefreshScrollView(this);
28 | setContentView(mPullScrollView);
29 |
30 | mPullScrollView.setOnRefreshListener(new OnRefreshListener() {
31 |
32 | @Override
33 | public void onPullDownToRefresh(PullToRefreshBase refreshView) {
34 | new GetDataTask().execute();
35 | }
36 |
37 | @Override
38 | public void onPullUpToRefresh(PullToRefreshBase refreshView) {
39 |
40 | }
41 | });
42 |
43 | mScrollView = mPullScrollView.getRefreshableView();
44 | mScrollView.addView(createTextView());
45 |
46 | setLastUpdateTime();
47 | }
48 |
49 | private class GetDataTask extends AsyncTask {
50 |
51 | @Override
52 | protected String[] doInBackground(Void... params) {
53 | // Simulates a background job.
54 | try {
55 | Thread.sleep(2000);
56 | } catch (InterruptedException e) {
57 | }
58 | return null;
59 | }
60 |
61 | @Override
62 | protected void onPostExecute(String[] result) {
63 | mPullScrollView.onPullDownRefreshComplete();
64 | setLastUpdateTime();
65 |
66 | super.onPostExecute(result);
67 | }
68 | }
69 | private void setLastUpdateTime() {
70 | String text = formatDateTime(System.currentTimeMillis());
71 | mPullScrollView.setLastUpdatedLabel(text);
72 | }
73 |
74 | private String formatDateTime(long time) {
75 | if (0 == time) {
76 | return "";
77 | }
78 |
79 | return mDateFormat.format(new Date(time));
80 | }
81 |
82 | private TextView createTextView() {
83 | TextView textView = new TextView(this);
84 |
85 | StringBuilder sb = new StringBuilder();
86 | for (int i = 1; i < 200; ++i) {
87 | sb.append(String.format(" %03d", i)).append("\n");
88 | }
89 |
90 | textView.setText(sb.toString());
91 | textView.setTextColor(Color.WHITE);
92 | textView.setTextColor(Color.BLACK);
93 | textView.setTextSize(18);
94 |
95 | return textView;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/PullRefreshWebViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 |
6 | import android.app.Activity;
7 | import android.os.Bundle;
8 | import android.webkit.WebView;
9 | import android.webkit.WebViewClient;
10 |
11 | import com.lee.pullrefresh.ui.PullToRefreshBase;
12 | import com.lee.pullrefresh.ui.PullToRefreshBase.OnRefreshListener;
13 | import com.lee.pullrefresh.ui.PullToRefreshWebView;
14 |
15 | public class PullRefreshWebViewActivity extends Activity {
16 |
17 | private WebView mWebView;
18 | private PullToRefreshWebView mPullWebView;
19 | private SimpleDateFormat mDateFormat = new SimpleDateFormat("MM-dd HH:mm");
20 |
21 | @Override
22 | public void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 |
25 | setContentView(R.layout.pull_refresh_webview);
26 |
27 | mPullWebView = (PullToRefreshWebView) findViewById(R.id.pull_webview);//new PullToRefreshWebView(this);
28 | mPullWebView.setOnRefreshListener(new OnRefreshListener() {
29 |
30 | @Override
31 | public void onPullDownToRefresh(PullToRefreshBase refreshView) {
32 | loadUrl();
33 | }
34 |
35 | @Override
36 | public void onPullUpToRefresh(PullToRefreshBase refreshView) {
37 | }
38 | });
39 |
40 | mWebView = mPullWebView.getRefreshableView();
41 | mWebView.setWebViewClient(new WebViewClient() {
42 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
43 | return false;
44 | }
45 |
46 | public void onPageFinished(WebView view, String url) {
47 | mPullWebView.onPullDownRefreshComplete();
48 | setLastUpdateTime();
49 | }
50 | });
51 |
52 | loadUrl();
53 | setLastUpdateTime();
54 | }
55 |
56 |
57 | private void setLastUpdateTime() {
58 | String text = formatDateTime(System.currentTimeMillis());
59 | mPullWebView.setLastUpdatedLabel(text);
60 | }
61 |
62 | private String formatDateTime(long time) {
63 | if (0 == time) {
64 | return "";
65 | }
66 |
67 | return mDateFormat.format(new Date(time));
68 | }
69 |
70 | int mIndex = 0;
71 |
72 | private void loadUrl() {
73 |
74 | int length = sUrls.length;
75 | mIndex = mIndex % length;
76 | String url = sUrls[mIndex];
77 | mIndex++;
78 | mWebView.loadUrl(url);
79 | }
80 |
81 | private static final String[] sUrls = {
82 | // "file:///android_asset/html/test.html",
83 | "http://www.baidu.com",
84 | "http://www.google.com",
85 | "http://www.163.com",
86 | // "http://www.sina.com.cn",
87 | // "http://www.sohu.com"
88 | };
89 |
90 | static class JSInterface {
91 | public void getClass2() {
92 |
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/FooterLoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import com.lee.pullrefresh.R;
4 |
5 | import android.content.Context;
6 | import android.util.AttributeSet;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.widget.ProgressBar;
10 | import android.widget.TextView;
11 |
12 | /**
13 | * 这个类封装了下拉刷新的布局
14 | *
15 | * @author Li Hong
16 | * @since 2013-7-30
17 | */
18 | public class FooterLoadingLayout extends LoadingLayout {
19 | /**进度条*/
20 | private ProgressBar mProgressBar;
21 | /** 显示的文本 */
22 | private TextView mHintView;
23 |
24 | /**
25 | * 构造方法
26 | *
27 | * @param context context
28 | */
29 | public FooterLoadingLayout(Context context) {
30 | super(context);
31 | init(context);
32 | }
33 |
34 | /**
35 | * 构造方法
36 | *
37 | * @param context context
38 | * @param attrs attrs
39 | */
40 | public FooterLoadingLayout(Context context, AttributeSet attrs) {
41 | super(context, attrs);
42 | init(context);
43 | }
44 |
45 | /**
46 | * 初始化
47 | *
48 | * @param context context
49 | */
50 | private void init(Context context) {
51 | mProgressBar = (ProgressBar) findViewById(R.id.pull_to_load_footer_progressbar);
52 | mHintView = (TextView) findViewById(R.id.pull_to_load_footer_hint_textview);
53 |
54 | setState(State.RESET);
55 | }
56 |
57 | @Override
58 | protected View createLoadingView(Context context, AttributeSet attrs) {
59 | View container = LayoutInflater.from(context).inflate(R.layout.pull_to_load_footer, null);
60 | return container;
61 | }
62 |
63 | @Override
64 | public void setLastUpdatedLabel(CharSequence label) {
65 | }
66 |
67 | @Override
68 | public int getContentSize() {
69 | View view = findViewById(R.id.pull_to_load_footer_content);
70 | if (null != view) {
71 | return view.getHeight();
72 | }
73 |
74 | return (int) (getResources().getDisplayMetrics().density * 40);
75 | }
76 |
77 | @Override
78 | protected void onStateChanged(State curState, State oldState) {
79 | mProgressBar.setVisibility(View.GONE);
80 | mHintView.setVisibility(View.INVISIBLE);
81 |
82 | super.onStateChanged(curState, oldState);
83 | }
84 |
85 | @Override
86 | protected void onReset() {
87 | mHintView.setText(R.string.pull_to_refresh_header_hint_loading);
88 | }
89 |
90 | @Override
91 | protected void onPullToRefresh() {
92 | mHintView.setVisibility(View.VISIBLE);
93 | mHintView.setText(R.string.pull_to_refresh_header_hint_normal2);
94 | }
95 |
96 | @Override
97 | protected void onReleaseToRefresh() {
98 | mHintView.setVisibility(View.VISIBLE);
99 | mHintView.setText(R.string.pull_to_refresh_header_hint_ready);
100 | }
101 |
102 | @Override
103 | protected void onRefreshing() {
104 | mProgressBar.setVisibility(View.VISIBLE);
105 | mHintView.setVisibility(View.VISIBLE);
106 | mHintView.setText(R.string.pull_to_refresh_header_hint_loading);
107 | }
108 |
109 | @Override
110 | protected void onNoMoreData() {
111 | mHintView.setVisibility(View.VISIBLE);
112 | mHintView.setText(R.string.pushmsg_center_no_more_msg);
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/HeaderLoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import com.lee.pullrefresh.R;
4 |
5 | import android.content.Context;
6 | import android.text.TextUtils;
7 | import android.util.AttributeSet;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.animation.Animation;
11 | import android.view.animation.RotateAnimation;
12 | import android.widget.ImageView;
13 | import android.widget.ProgressBar;
14 | import android.widget.RelativeLayout;
15 | import android.widget.TextView;
16 |
17 | /**
18 | * 这个类封装了下拉刷新的布局
19 | *
20 | * @author Li Hong
21 | * @since 2013-7-30
22 | */
23 | public class HeaderLoadingLayout extends LoadingLayout {
24 | /** 旋转动画时间 */
25 | private static final int ROTATE_ANIM_DURATION = 150;
26 | /**Header的容器*/
27 | private RelativeLayout mHeaderContainer;
28 | /**箭头图片*/
29 | private ImageView mArrowImageView;
30 | /**进度条*/
31 | private ProgressBar mProgressBar;
32 | /**状态提示TextView*/
33 | private TextView mHintTextView;
34 | /**最后更新时间的TextView*/
35 | private TextView mHeaderTimeView;
36 | /**最后更新时间的标题*/
37 | private TextView mHeaderTimeViewTitle;
38 | /**向上的动画*/
39 | private Animation mRotateUpAnim;
40 | /**向下的动画*/
41 | private Animation mRotateDownAnim;
42 |
43 | /**
44 | * 构造方法
45 | *
46 | * @param context context
47 | */
48 | public HeaderLoadingLayout(Context context) {
49 | super(context);
50 | init(context);
51 | }
52 |
53 | /**
54 | * 构造方法
55 | *
56 | * @param context context
57 | * @param attrs attrs
58 | */
59 | public HeaderLoadingLayout(Context context, AttributeSet attrs) {
60 | super(context, attrs);
61 | init(context);
62 | }
63 |
64 | /**
65 | * 初始化
66 | *
67 | * @param context context
68 | */
69 | private void init(Context context) {
70 | mHeaderContainer = (RelativeLayout) findViewById(R.id.pull_to_refresh_header_content);
71 | mArrowImageView = (ImageView) findViewById(R.id.pull_to_refresh_header_arrow);
72 | mHintTextView = (TextView) findViewById(R.id.pull_to_refresh_header_hint_textview);
73 | mProgressBar = (ProgressBar) findViewById(R.id.pull_to_refresh_header_progressbar);
74 | mHeaderTimeView = (TextView) findViewById(R.id.pull_to_refresh_header_time);
75 | mHeaderTimeViewTitle = (TextView) findViewById(R.id.pull_to_refresh_last_update_time_text);
76 |
77 | float pivotValue = 0.5f; // SUPPRESS CHECKSTYLE
78 | float toDegree = -180f; // SUPPRESS CHECKSTYLE
79 | // 初始化旋转动画
80 | mRotateUpAnim = new RotateAnimation(0.0f, toDegree, Animation.RELATIVE_TO_SELF, pivotValue,
81 | Animation.RELATIVE_TO_SELF, pivotValue);
82 | mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
83 | mRotateUpAnim.setFillAfter(true);
84 | mRotateDownAnim = new RotateAnimation(toDegree, 0.0f, Animation.RELATIVE_TO_SELF, pivotValue,
85 | Animation.RELATIVE_TO_SELF, pivotValue);
86 | mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
87 | mRotateDownAnim.setFillAfter(true);
88 | }
89 |
90 | @Override
91 | public void setLastUpdatedLabel(CharSequence label) {
92 | // 如果最后更新的时间的文本是空的话,隐藏前面的标题
93 | mHeaderTimeViewTitle.setVisibility(TextUtils.isEmpty(label) ? View.INVISIBLE : View.VISIBLE);
94 | mHeaderTimeView.setText(label);
95 | }
96 |
97 | @Override
98 | public int getContentSize() {
99 | if (null != mHeaderContainer) {
100 | return mHeaderContainer.getHeight();
101 | }
102 |
103 | return (int) (getResources().getDisplayMetrics().density * 60);
104 | }
105 |
106 | @Override
107 | protected View createLoadingView(Context context, AttributeSet attrs) {
108 | View container = LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header, null);
109 | return container;
110 | }
111 |
112 | @Override
113 | protected void onStateChanged(State curState, State oldState) {
114 | mArrowImageView.setVisibility(View.VISIBLE);
115 | mProgressBar.setVisibility(View.INVISIBLE);
116 |
117 | super.onStateChanged(curState, oldState);
118 | }
119 |
120 | @Override
121 | protected void onReset() {
122 | mArrowImageView.clearAnimation();
123 | mHintTextView.setText(R.string.pull_to_refresh_header_hint_normal);
124 | }
125 |
126 | @Override
127 | protected void onPullToRefresh() {
128 | if (State.RELEASE_TO_REFRESH == getPreState()) {
129 | mArrowImageView.clearAnimation();
130 | mArrowImageView.startAnimation(mRotateDownAnim);
131 | }
132 |
133 | mHintTextView.setText(R.string.pull_to_refresh_header_hint_normal);
134 | }
135 |
136 | @Override
137 | protected void onReleaseToRefresh() {
138 | mArrowImageView.clearAnimation();
139 | mArrowImageView.startAnimation(mRotateUpAnim);
140 | mHintTextView.setText(R.string.pull_to_refresh_header_hint_ready);
141 | }
142 |
143 | @Override
144 | protected void onRefreshing() {
145 | mArrowImageView.clearAnimation();
146 | mArrowImageView.setVisibility(View.INVISIBLE);
147 | mProgressBar.setVisibility(View.VISIBLE);
148 | mHintTextView.setText(R.string.pull_to_refresh_header_hint_loading);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/ILoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | /**
4 | * 下拉刷新和上拉加载更多的界面接口
5 | *
6 | * @author Li Hong
7 | * @since 2013-7-29
8 | */
9 | public interface ILoadingLayout {
10 | /**
11 | * 当前的状态
12 | */
13 | public enum State {
14 |
15 | /**
16 | * Initial state
17 | */
18 | NONE,
19 |
20 | /**
21 | * When the UI is in a state which means that user is not interacting
22 | * with the Pull-to-Refresh function.
23 | */
24 | RESET,
25 |
26 | /**
27 | * When the UI is being pulled by the user, but has not been pulled far
28 | * enough so that it refreshes when released.
29 | */
30 | PULL_TO_REFRESH,
31 |
32 | /**
33 | * When the UI is being pulled by the user, and has
34 | * been pulled far enough so that it will refresh when released.
35 | */
36 | RELEASE_TO_REFRESH,
37 |
38 | /**
39 | * When the UI is currently refreshing, caused by a pull gesture.
40 | */
41 | REFRESHING,
42 |
43 | /**
44 | * When the UI is currently refreshing, caused by a pull gesture.
45 | */
46 | @Deprecated
47 | LOADING,
48 |
49 | /**
50 | * No more data
51 | */
52 | NO_MORE_DATA,
53 | }
54 |
55 | /**
56 | * 设置当前状态,派生类应该根据这个状态的变化来改变View的变化
57 | *
58 | * @param state 状态
59 | */
60 | public void setState(State state);
61 |
62 | /**
63 | * 得到当前的状态
64 | *
65 | * @return 状态
66 | */
67 | public State getState();
68 |
69 | /**
70 | * 得到当前Layout的内容大小,它将作为一个刷新的临界点
71 | *
72 | * @return 高度
73 | */
74 | public int getContentSize();
75 |
76 | /**
77 | * 在拉动时调用
78 | *
79 | * @param scale 拉动的比例
80 | */
81 | public void onPull(float scale);
82 | }
83 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/IPullToRefresh.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 |
7 | import com.lee.pullrefresh.ui.PullToRefreshBase.OnRefreshListener;
8 |
9 | /**
10 | * 定义了拉动刷新的接口
11 | *
12 | * @author Li Hong
13 | * @since 2013-8-22
14 | * @param
15 | */
16 | public interface IPullToRefresh {
17 |
18 | /**
19 | * 设置当前下拉刷新是否可用
20 | *
21 | * @param pullRefreshEnabled true表示可用,false表示不可用
22 | */
23 | public void setPullRefreshEnabled(boolean pullRefreshEnabled);
24 |
25 | /**
26 | * 设置当前上拉加载更多是否可用
27 | *
28 | * @param pullLoadEnabled true表示可用,false表示不可用
29 | */
30 | public void setPullLoadEnabled(boolean pullLoadEnabled);
31 |
32 | /**
33 | * 滑动到底部是否自动加载更多数据
34 | *
35 | * @param scrollLoadEnabled 如果这个值为true的话,那么上拉加载更多的功能将会禁用
36 | */
37 | public void setScrollLoadEnabled(boolean scrollLoadEnabled);
38 |
39 | /**
40 | * 判断当前下拉刷新是否可用
41 | *
42 | * @return true如果可用,false不可用
43 | */
44 | public boolean isPullRefreshEnabled();
45 |
46 | /**
47 | * 判断上拉加载是否可用
48 | *
49 | * @return true可用,false不可用
50 | */
51 | public boolean isPullLoadEnabled();
52 |
53 | /**
54 | * 滑动到底部加载是否可用
55 | *
56 | * @return true可用,否则不可用
57 | */
58 | public boolean isScrollLoadEnabled();
59 |
60 | /**
61 | * 设置刷新的监听器
62 | *
63 | * @param refreshListener 监听器对象
64 | */
65 | public void setOnRefreshListener(OnRefreshListener refreshListener);
66 |
67 | /**
68 | * 结束下拉刷新
69 | */
70 | public void onPullDownRefreshComplete();
71 |
72 | /**
73 | * 结束上拉加载更多
74 | */
75 | public void onPullUpRefreshComplete();
76 |
77 | /**
78 | * 得到可刷新的View对象
79 | *
80 | * @return 返回调用{@link #createRefreshableView(Context, AttributeSet)} 方法返回的对象
81 | */
82 | public T getRefreshableView();
83 |
84 | /**
85 | * 得到Header布局对象
86 | *
87 | * @return Header布局对象
88 | */
89 | public LoadingLayout getHeaderLoadingLayout();
90 |
91 | /**
92 | * 得到Footer布局对象
93 | *
94 | * @return Footer布局对象
95 | */
96 | public LoadingLayout getFooterLoadingLayout();
97 |
98 | /**
99 | * 设置最后更新的时间文本
100 | *
101 | * @param label 文本
102 | */
103 | public void setLastUpdatedLabel(CharSequence label);
104 | }
105 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/LoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.FrameLayout;
9 |
10 | /**
11 | * 这个类定义了Header和Footer的共通行为
12 | *
13 | * @author Li Hong
14 | * @since 2013-8-16
15 | */
16 | public abstract class LoadingLayout extends FrameLayout implements ILoadingLayout {
17 |
18 | /**容器布局*/
19 | private View mContainer;
20 | /**当前的状态*/
21 | private State mCurState = State.NONE;
22 | /**前一个状态*/
23 | private State mPreState = State.NONE;
24 |
25 | /**
26 | * 构造方法
27 | *
28 | * @param context context
29 | */
30 | public LoadingLayout(Context context) {
31 | this(context, null);
32 | }
33 |
34 | /**
35 | * 构造方法
36 | *
37 | * @param context context
38 | * @param attrs attrs
39 | */
40 | public LoadingLayout(Context context, AttributeSet attrs) {
41 | this(context, attrs, 0);
42 | }
43 |
44 | /**
45 | * 构造方法
46 | *
47 | * @param context context
48 | * @param attrs attrs
49 | * @param defStyle defStyle
50 | */
51 | public LoadingLayout(Context context, AttributeSet attrs, int defStyle) {
52 | super(context, attrs, defStyle);
53 |
54 | init(context, attrs);
55 | }
56 |
57 | /**
58 | * 初始化
59 | *
60 | * @param context context
61 | * @param attrs attrs
62 | */
63 | protected void init(Context context, AttributeSet attrs) {
64 | mContainer = createLoadingView(context, attrs);
65 | if (null == mContainer) {
66 | throw new NullPointerException("Loading view can not be null.");
67 | }
68 |
69 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
70 | LayoutParams.MATCH_PARENT,
71 | LayoutParams.WRAP_CONTENT);
72 | addView(mContainer, params);
73 | }
74 |
75 | /**
76 | * 显示或隐藏这个布局
77 | *
78 | * @param show flag
79 | */
80 | public void show(boolean show) {
81 | // If is showing, do nothing.
82 | if (show == (View.VISIBLE == getVisibility())) {
83 | return;
84 | }
85 |
86 | ViewGroup.LayoutParams params = mContainer.getLayoutParams();
87 | if (null != params) {
88 | if (show) {
89 | params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
90 | } else {
91 | params.height = 0;
92 | }
93 | setVisibility(show ? View.VISIBLE : View.INVISIBLE);
94 | }
95 | }
96 |
97 | /**
98 | * 设置最后更新的时间文本
99 | *
100 | * @param label 文本
101 | */
102 | public void setLastUpdatedLabel(CharSequence label) {
103 |
104 | }
105 |
106 | /**
107 | * 设置加载中的图片
108 | *
109 | * @param drawable 图片
110 | */
111 | public void setLoadingDrawable(Drawable drawable) {
112 |
113 | }
114 |
115 | /**
116 | * 设置拉动的文本,典型的是“下拉可以刷新”
117 | *
118 | * @param pullLabel 拉动的文本
119 | */
120 | public void setPullLabel(CharSequence pullLabel) {
121 |
122 | }
123 |
124 | /**
125 | * 设置正在刷新的文本,典型的是“正在刷新”
126 | *
127 | * @param refreshingLabel 刷新文本
128 | */
129 | public void setRefreshingLabel(CharSequence refreshingLabel) {
130 |
131 | }
132 |
133 | /**
134 | * 设置释放的文本,典型的是“松开可以刷新”
135 | *
136 | * @param releaseLabel 释放文本
137 | */
138 | public void setReleaseLabel(CharSequence releaseLabel) {
139 |
140 | }
141 |
142 | @Override
143 | public void setState(State state) {
144 | if (mCurState != state) {
145 | mPreState = mCurState;
146 | mCurState = state;
147 | onStateChanged(state, mPreState);
148 | }
149 | }
150 |
151 | @Override
152 | public State getState() {
153 | return mCurState;
154 | }
155 |
156 | @Override
157 | public void onPull(float scale) {
158 |
159 | }
160 |
161 | /**
162 | * 得到前一个状态
163 | *
164 | * @return 状态
165 | */
166 | protected State getPreState() {
167 | return mPreState;
168 | }
169 |
170 | /**
171 | * 当状态改变时调用
172 | *
173 | * @param curState 当前状态
174 | * @param oldState 老的状态
175 | */
176 | protected void onStateChanged(State curState, State oldState) {
177 | switch (curState) {
178 | case RESET:
179 | onReset();
180 | break;
181 |
182 | case RELEASE_TO_REFRESH:
183 | onReleaseToRefresh();
184 | break;
185 |
186 | case PULL_TO_REFRESH:
187 | onPullToRefresh();
188 | break;
189 |
190 | case REFRESHING:
191 | onRefreshing();
192 | break;
193 |
194 | case NO_MORE_DATA:
195 | onNoMoreData();
196 | break;
197 |
198 | default:
199 | break;
200 | }
201 | }
202 |
203 | /**
204 | * 当状态设置为{@link State#RESET}时调用
205 | */
206 | protected void onReset() {
207 |
208 | }
209 |
210 | /**
211 | * 当状态设置为{@link State#PULL_TO_REFRESH}时调用
212 | */
213 | protected void onPullToRefresh() {
214 |
215 | }
216 |
217 | /**
218 | * 当状态设置为{@link State#RELEASE_TO_REFRESH}时调用
219 | */
220 | protected void onReleaseToRefresh() {
221 |
222 | }
223 |
224 | /**
225 | * 当状态设置为{@link State#REFRESHING}时调用
226 | */
227 | protected void onRefreshing() {
228 |
229 | }
230 |
231 | /**
232 | * 当状态设置为{@link State#NO_MORE_DATA}时调用
233 | */
234 | protected void onNoMoreData() {
235 |
236 | }
237 |
238 | /**
239 | * 得到当前Layout的内容大小,它将作为一个刷新的临界点
240 | *
241 | * @return 高度
242 | */
243 | public abstract int getContentSize();
244 |
245 | /**
246 | * 创建Loading的View
247 | *
248 | * @param context context
249 | * @param attrs attrs
250 | * @return Loading的View
251 | */
252 | protected abstract View createLoadingView(Context context, AttributeSet attrs);
253 | }
254 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/PullToRefreshBase.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import com.lee.pullrefresh.ui.ILoadingLayout.State;
4 |
5 | import android.content.Context;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 | import android.view.ViewConfiguration;
10 | import android.view.ViewGroup;
11 | import android.view.ViewTreeObserver.OnGlobalLayoutListener;
12 | import android.view.animation.DecelerateInterpolator;
13 | import android.view.animation.Interpolator;
14 | import android.widget.FrameLayout;
15 | import android.widget.LinearLayout;
16 |
17 | /**
18 | * 这个实现了下拉刷新和上拉加载更多的功能
19 | *
20 | * @author Li Hong
21 | * @since 2013-7-29
22 | * @param
23 | */
24 | public abstract class PullToRefreshBase extends LinearLayout implements IPullToRefresh {
25 | /**
26 | * 定义了下拉刷新和上拉加载更多的接口。
27 | *
28 | * @author Li Hong
29 | * @since 2013-7-29
30 | */
31 | public interface OnRefreshListener {
32 |
33 | /**
34 | * 下拉松手后会被调用
35 | *
36 | * @param refreshView 刷新的View
37 | */
38 | void onPullDownToRefresh(final PullToRefreshBase refreshView);
39 |
40 | /**
41 | * 加载更多时会被调用或上拉时调用
42 | *
43 | * @param refreshView 刷新的View
44 | */
45 | void onPullUpToRefresh(final PullToRefreshBase refreshView);
46 | }
47 |
48 | /**回滚的时间*/
49 | private static final int SCROLL_DURATION = 150;
50 | /**阻尼系数*/
51 | private static final float OFFSET_RADIO = 2.5f;
52 | /**上一次移动的点 */
53 | private float mLastMotionY = -1;
54 | /**下拉刷新和加载更多的监听器 */
55 | private OnRefreshListener mRefreshListener;
56 | /**下拉刷新的布局 */
57 | private LoadingLayout mHeaderLayout;
58 | /**上拉加载更多的布局*/
59 | private LoadingLayout mFooterLayout;
60 | /**HeaderView的高度*/
61 | private int mHeaderHeight;
62 | /**FooterView的高度*/
63 | private int mFooterHeight;
64 | /**下拉刷新是否可用*/
65 | private boolean mPullRefreshEnabled = true;
66 | /**上拉加载是否可用*/
67 | private boolean mPullLoadEnabled = false;
68 | /**判断滑动到底部加载是否可用*/
69 | private boolean mScrollLoadEnabled = false;
70 | /**是否截断touch事件*/
71 | private boolean mInterceptEventEnable = true;
72 | /**表示是否消费了touch事件,如果是,则不调用父类的onTouchEvent方法*/
73 | private boolean mIsHandledTouchEvent = false;
74 | /**移动点的保护范围值*/
75 | private int mTouchSlop;
76 | /**下拉的状态*/
77 | private State mPullDownState = State.NONE;
78 | /**上拉的状态*/
79 | private State mPullUpState = State.NONE;
80 | /**可以下拉刷新的View*/
81 | T mRefreshableView;
82 | /**平滑滚动的Runnable*/
83 | private SmoothScrollRunnable mSmoothScrollRunnable;
84 | /**可刷新View的包装布局*/
85 | private FrameLayout mRefreshableViewWrapper;
86 |
87 | /**
88 | * 构造方法
89 | *
90 | * @param context context
91 | */
92 | public PullToRefreshBase(Context context) {
93 | super(context);
94 | init(context, null);
95 | }
96 |
97 | /**
98 | * 构造方法
99 | *
100 | * @param context context
101 | * @param attrs attrs
102 | */
103 | public PullToRefreshBase(Context context, AttributeSet attrs) {
104 | super(context, attrs);
105 | init(context, attrs);
106 | }
107 |
108 | /**
109 | * 构造方法
110 | *
111 | * @param context context
112 | * @param attrs attrs
113 | * @param defStyle defStyle
114 | */
115 | public PullToRefreshBase(Context context, AttributeSet attrs, int defStyle) {
116 | super(context, attrs, defStyle);
117 | init(context, attrs);
118 | }
119 |
120 | /**
121 | * 初始化
122 | *
123 | * @param context context
124 | */
125 | private void init(Context context, AttributeSet attrs) {
126 | setOrientation(LinearLayout.VERTICAL);
127 |
128 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
129 |
130 | mHeaderLayout = createHeaderLoadingLayout(context, attrs);
131 | mFooterLayout = createFooterLoadingLayout(context, attrs);
132 | mRefreshableView = createRefreshableView(context, attrs);
133 |
134 | if (null == mRefreshableView) {
135 | throw new NullPointerException("Refreshable view can not be null.");
136 | }
137 |
138 | addRefreshableView(context, mRefreshableView);
139 | addHeaderAndFooter(context);
140 |
141 | // 得到Header的高度,这个高度需要用这种方式得到,在onLayout方法里面得到的高度始终是0
142 | getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
143 | @Override
144 | public void onGlobalLayout() {
145 | refreshLoadingViewsSize();
146 | getViewTreeObserver().removeGlobalOnLayoutListener(this);
147 | }
148 | });
149 | }
150 |
151 | /**
152 | * 初始化padding,我们根据header和footer的高度来设置top padding和bottom padding
153 | */
154 | private void refreshLoadingViewsSize() {
155 | // 得到header和footer的内容高度,它将会作为拖动刷新的一个临界值,如果拖动距离大于这个高度
156 | // 然后再松开手,就会触发刷新操作
157 | int headerHeight = (null != mHeaderLayout) ? mHeaderLayout.getContentSize() : 0;
158 | int footerHeight = (null != mFooterLayout) ? mFooterLayout.getContentSize() : 0;
159 |
160 | if (headerHeight < 0) {
161 | headerHeight = 0;
162 | }
163 |
164 | if (footerHeight < 0) {
165 | footerHeight = 0;
166 | }
167 |
168 | mHeaderHeight = headerHeight;
169 | mFooterHeight = footerHeight;
170 |
171 | // 这里得到Header和Footer的高度,设置的padding的top和bottom就应该是header和footer的高度
172 | // 因为header和footer是完全看不见的
173 | headerHeight = (null != mHeaderLayout) ? mHeaderLayout.getMeasuredHeight() : 0;
174 | footerHeight = (null != mFooterLayout) ? mFooterLayout.getMeasuredHeight() : 0;
175 | if (0 == footerHeight) {
176 | footerHeight = mFooterHeight;
177 | }
178 |
179 | int pLeft = getPaddingLeft();
180 | int pTop = getPaddingTop();
181 | int pRight = getPaddingRight();
182 | int pBottom = getPaddingBottom();
183 |
184 | pTop = -headerHeight;
185 | pBottom = -footerHeight;
186 |
187 | setPadding(pLeft, pTop, pRight, pBottom);
188 | }
189 |
190 | @Override
191 | protected final void onSizeChanged(int w, int h, int oldw, int oldh) {
192 | super.onSizeChanged(w, h, oldw, oldh);
193 |
194 | // We need to update the header/footer when our size changes
195 | refreshLoadingViewsSize();
196 |
197 | // 设置刷新View的大小
198 | refreshRefreshableViewSize(w, h);
199 |
200 | /**
201 | * As we're currently in a Layout Pass, we need to schedule another one
202 | * to layout any changes we've made here
203 | */
204 | post(new Runnable() {
205 | @Override
206 | public void run() {
207 | requestLayout();
208 | }
209 | });
210 | }
211 |
212 | @Override
213 | public void setOrientation(int orientation) {
214 | if (LinearLayout.VERTICAL != orientation) {
215 | throw new IllegalArgumentException("This class only supports VERTICAL orientation.");
216 | }
217 |
218 | // Only support vertical orientation
219 | super.setOrientation(orientation);
220 | }
221 |
222 | @Override
223 | public final boolean onInterceptTouchEvent(MotionEvent event) {
224 | if (!isInterceptTouchEventEnabled()) {
225 | return false;
226 | }
227 |
228 | if (!isPullLoadEnabled() && !isPullRefreshEnabled()) {
229 | return false;
230 | }
231 |
232 | final int action = event.getAction();
233 | if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
234 | mIsHandledTouchEvent = false;
235 | return false;
236 | }
237 |
238 | if (action != MotionEvent.ACTION_DOWN && mIsHandledTouchEvent) {
239 | return true;
240 | }
241 |
242 | switch (action) {
243 | case MotionEvent.ACTION_DOWN:
244 | mLastMotionY = event.getY();
245 | mIsHandledTouchEvent = false;
246 | break;
247 |
248 | case MotionEvent.ACTION_MOVE:
249 | final float deltaY = event.getY() - mLastMotionY;
250 | final float absDiff = Math.abs(deltaY);
251 | // 这里有三个条件:
252 | // 1,位移差大于mTouchSlop,这是为了防止快速拖动引发刷新
253 | // 2,isPullRefreshing(),如果当前正在下拉刷新的话,是允许向上滑动,并把刷新的HeaderView挤上去
254 | // 3,isPullLoading(),理由与第2条相同
255 | if (absDiff > mTouchSlop || isPullRefreshing() || isPullLoading()) {
256 | mLastMotionY = event.getY();
257 | // 第一个显示出来,Header已经显示或拉下
258 | if (isPullRefreshEnabled() && isReadyForPullDown()) {
259 | // 1,Math.abs(getScrollY()) > 0:表示当前滑动的偏移量的绝对值大于0,表示当前HeaderView滑出来了或完全
260 | // 不可见,存在这样一种case,当正在刷新时并且RefreshableView已经滑到顶部,向上滑动,那么我们期望的结果是
261 | // 依然能向上滑动,直到HeaderView完全不可见
262 | // 2,deltaY > 0.5f:表示下拉的值大于0.5f
263 | mIsHandledTouchEvent = (Math.abs(getScrollYValue()) > 0 || deltaY > 0.5f);
264 | // 如果截断事件,我们则仍然把这个事件交给刷新View去处理,典型的情况是让ListView/GridView将按下
265 | // Child的Selector隐藏
266 | if (mIsHandledTouchEvent) {
267 | mRefreshableView.onTouchEvent(event);
268 | }
269 | } else if (isPullLoadEnabled() && isReadyForPullUp()) {
270 | // 原理如上
271 | mIsHandledTouchEvent = (Math.abs(getScrollYValue()) > 0 || deltaY < -0.5f);
272 | }
273 | }
274 | break;
275 |
276 | default:
277 | break;
278 | }
279 |
280 | return mIsHandledTouchEvent;
281 | }
282 |
283 | @Override
284 | public final boolean onTouchEvent(MotionEvent ev) {
285 | boolean handled = false;
286 | switch (ev.getAction()) {
287 | case MotionEvent.ACTION_DOWN:
288 | mLastMotionY = ev.getY();
289 | mIsHandledTouchEvent = false;
290 | break;
291 |
292 | case MotionEvent.ACTION_MOVE:
293 | final float deltaY = ev.getY() - mLastMotionY;
294 | mLastMotionY = ev.getY();
295 | if (isPullRefreshEnabled() && isReadyForPullDown()) {
296 | pullHeaderLayout(deltaY / OFFSET_RADIO);
297 | handled = true;
298 | } else if (isPullLoadEnabled() && isReadyForPullUp()) {
299 | pullFooterLayout(deltaY / OFFSET_RADIO);
300 | handled = true;
301 | } else {
302 | mIsHandledTouchEvent = false;
303 | }
304 | break;
305 |
306 | case MotionEvent.ACTION_CANCEL:
307 | case MotionEvent.ACTION_UP:
308 | if (mIsHandledTouchEvent) {
309 | mIsHandledTouchEvent = false;
310 | // 当第一个显示出来时
311 | if (isReadyForPullDown()) {
312 | // 调用刷新
313 | if (mPullRefreshEnabled && (mPullDownState == State.RELEASE_TO_REFRESH)) {
314 | startRefreshing();
315 | handled = true;
316 | }
317 | resetHeaderLayout();
318 | } else if (isReadyForPullUp()) {
319 | // 加载更多
320 | if (isPullLoadEnabled() && (mPullUpState == State.RELEASE_TO_REFRESH)) {
321 | startLoading();
322 | handled = true;
323 | }
324 | resetFooterLayout();
325 | }
326 | }
327 | break;
328 |
329 | default:
330 | break;
331 | }
332 |
333 | return handled;
334 | }
335 |
336 | @Override
337 | public void setPullRefreshEnabled(boolean pullRefreshEnabled) {
338 | mPullRefreshEnabled = pullRefreshEnabled;
339 | }
340 |
341 | @Override
342 | public void setPullLoadEnabled(boolean pullLoadEnabled) {
343 | mPullLoadEnabled = pullLoadEnabled;
344 | }
345 |
346 | @Override
347 | public void setScrollLoadEnabled(boolean scrollLoadEnabled) {
348 | mScrollLoadEnabled = scrollLoadEnabled;
349 | }
350 |
351 | @Override
352 | public boolean isPullRefreshEnabled() {
353 | return mPullRefreshEnabled && (null != mHeaderLayout);
354 | }
355 |
356 | @Override
357 | public boolean isPullLoadEnabled() {
358 | return mPullLoadEnabled && (null != mFooterLayout);
359 | }
360 |
361 | @Override
362 | public boolean isScrollLoadEnabled() {
363 | return mScrollLoadEnabled;
364 | }
365 |
366 | @Override
367 | public void setOnRefreshListener(OnRefreshListener refreshListener) {
368 | mRefreshListener = refreshListener;
369 | }
370 |
371 | @Override
372 | public void onPullDownRefreshComplete() {
373 | if (isPullRefreshing()) {
374 | mPullDownState = State.RESET;
375 | onStateChanged(State.RESET, true);
376 |
377 | // 回滚动有一个时间,我们在回滚完成后再设置状态为normal
378 | // 在将LoadingLayout的状态设置为normal之前,我们应该禁止
379 | // 截断Touch事件,因为设里有一个post状态,如果有post的Runnable
380 | // 未被执行时,用户再一次发起下拉刷新,如果正在刷新时,这个Runnable
381 | // 再次被执行到,那么就会把正在刷新的状态改为正常状态,这就不符合期望
382 | postDelayed(new Runnable() {
383 | @Override
384 | public void run() {
385 | setInterceptTouchEventEnabled(true);
386 | mHeaderLayout.setState(State.RESET);
387 | }
388 | }, getSmoothScrollDuration());
389 |
390 | resetHeaderLayout();
391 | setInterceptTouchEventEnabled(false);
392 | }
393 | }
394 |
395 | @Override
396 | public void onPullUpRefreshComplete() {
397 | if (isPullLoading()) {
398 | mPullUpState = State.RESET;
399 | onStateChanged(State.RESET, false);
400 |
401 | postDelayed(new Runnable() {
402 | @Override
403 | public void run() {
404 | setInterceptTouchEventEnabled(true);
405 | mFooterLayout.setState(State.RESET);
406 | }
407 | }, getSmoothScrollDuration());
408 |
409 | resetFooterLayout();
410 | setInterceptTouchEventEnabled(false);
411 | }
412 | }
413 |
414 | @Override
415 | public T getRefreshableView() {
416 | return mRefreshableView;
417 | }
418 |
419 | @Override
420 | public LoadingLayout getHeaderLoadingLayout() {
421 | return mHeaderLayout;
422 | }
423 |
424 | @Override
425 | public LoadingLayout getFooterLoadingLayout() {
426 | return mFooterLayout;
427 | }
428 |
429 | @Override
430 | public void setLastUpdatedLabel(CharSequence label){
431 | if (null != mHeaderLayout) {
432 | mHeaderLayout.setLastUpdatedLabel(label);
433 | }
434 |
435 | if (null != mFooterLayout) {
436 | mFooterLayout.setLastUpdatedLabel(label);
437 | }
438 | }
439 |
440 | /**
441 | * 开始刷新,通常用于调用者主动刷新,典型的情况是进入界面,开始主动刷新,这个刷新并不是由用户拉动引起的
442 | *
443 | * @param smoothScroll 表示是否有平滑滚动,true表示平滑滚动,false表示无平滑滚动
444 | * @param delayMillis 延迟时间
445 | */
446 | public void doPullRefreshing(final boolean smoothScroll, final long delayMillis) {
447 | postDelayed(new Runnable() {
448 | @Override
449 | public void run() {
450 | int newScrollValue = -mHeaderHeight;
451 | int duration = smoothScroll ? SCROLL_DURATION : 0;
452 |
453 | startRefreshing();
454 | smoothScrollTo(newScrollValue, duration, 0);
455 | }
456 | }, delayMillis);
457 | }
458 |
459 | /**
460 | * 创建可以刷新的View
461 | *
462 | * @param context context
463 | * @param attrs 属性
464 | * @return View
465 | */
466 | protected abstract T createRefreshableView(Context context, AttributeSet attrs);
467 |
468 | /**
469 | * 判断刷新的View是否滑动到顶部
470 | *
471 | * @return true表示已经滑动到顶部,否则false
472 | */
473 | protected abstract boolean isReadyForPullDown();
474 |
475 | /**
476 | * 判断刷新的View是否滑动到底
477 | *
478 | * @return true表示已经滑动到底部,否则false
479 | */
480 | protected abstract boolean isReadyForPullUp();
481 |
482 | /**
483 | * 创建Header的布局
484 | *
485 | * @param context context
486 | * @param attrs 属性
487 | * @return LoadingLayout对象
488 | */
489 | protected LoadingLayout createHeaderLoadingLayout(Context context, AttributeSet attrs) {
490 | return new HeaderLoadingLayout(context);
491 | }
492 |
493 | /**
494 | * 创建Footer的布局
495 | *
496 | * @param context context
497 | * @param attrs 属性
498 | * @return LoadingLayout对象
499 | */
500 | protected LoadingLayout createFooterLoadingLayout(Context context, AttributeSet attrs) {
501 | return new FooterLoadingLayout(context);
502 | }
503 |
504 | /**
505 | * 得到平滑滚动的时间,派生类可以重写这个方法来控件滚动时间
506 | *
507 | * @return 返回值时间为毫秒
508 | */
509 | protected long getSmoothScrollDuration() {
510 | return SCROLL_DURATION;
511 | }
512 |
513 | /**
514 | * 计算刷新View的大小
515 | *
516 | * @param width 当前容器的宽度
517 | * @param height 当前容器的宽度
518 | */
519 | protected void refreshRefreshableViewSize(int width, int height) {
520 | if (null != mRefreshableViewWrapper) {
521 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mRefreshableViewWrapper.getLayoutParams();
522 | if (lp.height != height) {
523 | lp.height = height;
524 | mRefreshableViewWrapper.requestLayout();
525 | }
526 | }
527 | }
528 |
529 | /**
530 | * 将刷新View添加到当前容器中
531 | *
532 | * @param context context
533 | * @param refreshableView 可以刷新的View
534 | */
535 | protected void addRefreshableView(Context context, T refreshableView) {
536 | int width = ViewGroup.LayoutParams.MATCH_PARENT;
537 | int height = ViewGroup.LayoutParams.MATCH_PARENT;
538 |
539 | // 创建一个包装容器
540 | mRefreshableViewWrapper = new FrameLayout(context);
541 | mRefreshableViewWrapper.addView(refreshableView, width, height);
542 |
543 | // 这里把Refresh view的高度设置为一个很小的值,它的高度最终会在onSizeChanged()方法中设置为MATCH_PARENT
544 | // 这样做的原因是,如果此是它的height是MATCH_PARENT,那么footer得到的高度就是0,所以,我们先设置高度很小
545 | // 我们就可以得到header和footer的正常高度,当onSizeChanged后,Refresh view的高度又会变为正常。
546 | height = 10;
547 | addView(mRefreshableViewWrapper, new LinearLayout.LayoutParams(width, height));
548 | }
549 |
550 | /**
551 | * 添加Header和Footer
552 | *
553 | * @param context context
554 | */
555 | protected void addHeaderAndFooter(Context context) {
556 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
557 | ViewGroup.LayoutParams.MATCH_PARENT,
558 | ViewGroup.LayoutParams.WRAP_CONTENT);
559 |
560 | final LoadingLayout headerLayout = mHeaderLayout;
561 | final LoadingLayout footerLayout = mFooterLayout;
562 |
563 | if (null != headerLayout) {
564 | if (this == headerLayout.getParent()) {
565 | removeView(headerLayout);
566 | }
567 |
568 | addView(headerLayout, 0, params);
569 | }
570 |
571 | if (null != footerLayout) {
572 | if (this == footerLayout.getParent()) {
573 | removeView(footerLayout);
574 | }
575 |
576 | addView(footerLayout, -1, params);
577 | }
578 | }
579 |
580 | /**
581 | * 拉动Header Layout时调用
582 | *
583 | * @param delta 移动的距离
584 | */
585 | protected void pullHeaderLayout(float delta) {
586 | // 向上滑动,并且当前scrollY为0时,不滑动
587 | int oldScrollY = getScrollYValue();
588 | if (delta < 0 && (oldScrollY - delta) >= 0) {
589 | setScrollTo(0, 0);
590 | return;
591 | }
592 |
593 | // 向下滑动布局
594 | setScrollBy(0, -(int)delta);
595 |
596 | if (null != mHeaderLayout && 0 != mHeaderHeight) {
597 | float scale = Math.abs(getScrollYValue()) / (float) mHeaderHeight;
598 | mHeaderLayout.onPull(scale);
599 | }
600 |
601 | // 未处于刷新状态,更新箭头
602 | int scrollY = Math.abs(getScrollYValue());
603 | if (isPullRefreshEnabled() && !isPullRefreshing()) {
604 | if (scrollY > mHeaderHeight) {
605 | mPullDownState = State.RELEASE_TO_REFRESH;
606 | } else {
607 | mPullDownState = State.PULL_TO_REFRESH;
608 | }
609 |
610 | mHeaderLayout.setState(mPullDownState);
611 | onStateChanged(mPullDownState, true);
612 | }
613 | }
614 |
615 | /**
616 | * 拉Footer时调用
617 | *
618 | * @param delta 移动的距离
619 | */
620 | protected void pullFooterLayout(float delta) {
621 | int oldScrollY = getScrollYValue();
622 | if (delta > 0 && (oldScrollY - delta) <= 0) {
623 | setScrollTo(0, 0);
624 | return;
625 | }
626 |
627 | setScrollBy(0, -(int)delta);
628 |
629 | if (null != mFooterLayout && 0 != mFooterHeight) {
630 | float scale = Math.abs(getScrollYValue()) / (float) mFooterHeight;
631 | mFooterLayout.onPull(scale);
632 | }
633 |
634 | int scrollY = Math.abs(getScrollYValue());
635 | if (isPullLoadEnabled() && !isPullLoading()) {
636 | if (scrollY > mFooterHeight) {
637 | mPullUpState = State.RELEASE_TO_REFRESH;
638 | } else {
639 | mPullUpState = State.PULL_TO_REFRESH;
640 | }
641 |
642 | mFooterLayout.setState(mPullUpState);
643 | onStateChanged(mPullUpState, false);
644 | }
645 | }
646 |
647 | /**
648 | * 得置header
649 | */
650 | protected void resetHeaderLayout() {
651 | final int scrollY = Math.abs(getScrollYValue());
652 | final boolean refreshing = isPullRefreshing();
653 |
654 | if (refreshing && scrollY <= mHeaderHeight) {
655 | smoothScrollTo(0);
656 | return;
657 | }
658 |
659 | if (refreshing) {
660 | smoothScrollTo(-mHeaderHeight);
661 | } else {
662 | smoothScrollTo(0);
663 | }
664 | }
665 |
666 | /**
667 | * 重置footer
668 | */
669 | protected void resetFooterLayout() {
670 | int scrollY = Math.abs(getScrollYValue());
671 | boolean isPullLoading = isPullLoading();
672 |
673 | if (isPullLoading && scrollY <= mFooterHeight) {
674 | smoothScrollTo(0);
675 | return;
676 | }
677 |
678 | if (isPullLoading) {
679 | smoothScrollTo(mFooterHeight);
680 | } else {
681 | smoothScrollTo(0);
682 | }
683 | }
684 |
685 | /**
686 | * 判断是否正在下拉刷新
687 | *
688 | * @return true正在刷新,否则false
689 | */
690 | protected boolean isPullRefreshing() {
691 | return (mPullDownState == State.REFRESHING);
692 | }
693 |
694 | /**
695 | * 是否正的上拉加载更多
696 | *
697 | * @return true正在加载更多,否则false
698 | */
699 | protected boolean isPullLoading() {
700 | return (mPullUpState == State.REFRESHING);
701 | }
702 |
703 | /**
704 | * 开始刷新,当下拉松开后被调用
705 | */
706 | protected void startRefreshing() {
707 | // 如果正在刷新
708 | if (isPullRefreshing()) {
709 | return;
710 | }
711 |
712 | mPullDownState = State.REFRESHING;
713 | onStateChanged(State.REFRESHING, true);
714 |
715 | if (null != mHeaderLayout) {
716 | mHeaderLayout.setState(State.REFRESHING);
717 | }
718 |
719 | if (null != mRefreshListener) {
720 | // 因为滚动回原始位置的时间是200,我们需要等回滚完后才执行刷新回调
721 | postDelayed(new Runnable() {
722 | @Override
723 | public void run() {
724 | mRefreshListener.onPullDownToRefresh(PullToRefreshBase.this);
725 | }
726 | }, getSmoothScrollDuration());
727 | }
728 | }
729 |
730 | /**
731 | * 开始加载更多,上拉松开后调用
732 | */
733 | protected void startLoading() {
734 | // 如果正在加载
735 | if (isPullLoading()) {
736 | return;
737 | }
738 |
739 | mPullUpState = State.REFRESHING;
740 | onStateChanged(State.REFRESHING, false);
741 |
742 | if (null != mFooterLayout) {
743 | mFooterLayout.setState(State.REFRESHING);
744 | }
745 |
746 | if (null != mRefreshListener) {
747 | // 因为滚动回原始位置的时间是200,我们需要等回滚完后才执行加载回调
748 | postDelayed(new Runnable() {
749 | @Override
750 | public void run() {
751 | mRefreshListener.onPullUpToRefresh(PullToRefreshBase.this);
752 | }
753 | }, getSmoothScrollDuration());
754 | }
755 | }
756 |
757 | /**
758 | * 当状态发生变化时调用
759 | *
760 | * @param state 状态
761 | * @param isPullDown 是否向下
762 | */
763 | protected void onStateChanged(State state, boolean isPullDown) {
764 |
765 | }
766 |
767 | /**
768 | * 设置滚动位置
769 | *
770 | * @param x 滚动到的x位置
771 | * @param y 滚动到的y位置
772 | */
773 | private void setScrollTo(int x, int y) {
774 | scrollTo(x, y);
775 | }
776 |
777 | /**
778 | * 设置滚动的偏移
779 | *
780 | * @param x 滚动x位置
781 | * @param y 滚动y位置
782 | */
783 | private void setScrollBy(int x, int y) {
784 | scrollBy(x, y);
785 | }
786 |
787 | /**
788 | * 得到当前Y的滚动值
789 | *
790 | * @return 滚动值
791 | */
792 | private int getScrollYValue() {
793 | return getScrollY();
794 | }
795 |
796 | /**
797 | * 平滑滚动
798 | *
799 | * @param newScrollValue 滚动的值
800 | */
801 | private void smoothScrollTo(int newScrollValue) {
802 | smoothScrollTo(newScrollValue, getSmoothScrollDuration(), 0);
803 | }
804 |
805 | /**
806 | * 平滑滚动
807 | *
808 | * @param newScrollValue 滚动的值
809 | * @param duration 滚动时候
810 | * @param delayMillis 延迟时间,0代表不延迟
811 | */
812 | private void smoothScrollTo(int newScrollValue, long duration, long delayMillis) {
813 | if (null != mSmoothScrollRunnable) {
814 | mSmoothScrollRunnable.stop();
815 | }
816 |
817 | int oldScrollValue = this.getScrollYValue();
818 | boolean post = (oldScrollValue != newScrollValue);
819 | if (post) {
820 | mSmoothScrollRunnable = new SmoothScrollRunnable(oldScrollValue, newScrollValue, duration);
821 | }
822 |
823 | if (post) {
824 | if (delayMillis > 0) {
825 | postDelayed(mSmoothScrollRunnable, delayMillis);
826 | } else {
827 | post(mSmoothScrollRunnable);
828 | }
829 | }
830 | }
831 |
832 | /**
833 | * 设置是否截断touch事件
834 | *
835 | * @param enabled true截断,false不截断
836 | */
837 | private void setInterceptTouchEventEnabled(boolean enabled) {
838 | mInterceptEventEnable = enabled;
839 | }
840 |
841 | /**
842 | * 标志是否截断touch事件
843 | *
844 | * @return true截断,false不截断
845 | */
846 | private boolean isInterceptTouchEventEnabled() {
847 | return mInterceptEventEnable;
848 | }
849 |
850 | /**
851 | * 实现了平滑滚动的Runnable
852 | *
853 | * @author Li Hong
854 | * @since 2013-8-22
855 | */
856 | final class SmoothScrollRunnable implements Runnable {
857 | /**动画效果*/
858 | private final Interpolator mInterpolator;
859 | /**结束Y*/
860 | private final int mScrollToY;
861 | /**开始Y*/
862 | private final int mScrollFromY;
863 | /**滑动时间*/
864 | private final long mDuration;
865 | /**是否继续运行*/
866 | private boolean mContinueRunning = true;
867 | /**开始时刻*/
868 | private long mStartTime = -1;
869 | /**当前Y*/
870 | private int mCurrentY = -1;
871 |
872 | /**
873 | * 构造方法
874 | *
875 | * @param fromY 开始Y
876 | * @param toY 结束Y
877 | * @param duration 动画时间
878 | */
879 | public SmoothScrollRunnable(int fromY, int toY, long duration) {
880 | mScrollFromY = fromY;
881 | mScrollToY = toY;
882 | mDuration = duration;
883 | mInterpolator = new DecelerateInterpolator();
884 | }
885 |
886 | @Override
887 | public void run() {
888 | /**
889 | * If the duration is 0, we scroll the view to target y directly.
890 | */
891 | if (mDuration <= 0) {
892 | setScrollTo(0, mScrollToY);
893 | return;
894 | }
895 |
896 | /**
897 | * Only set mStartTime if this is the first time we're starting,
898 | * else actually calculate the Y delta
899 | */
900 | if (mStartTime == -1) {
901 | mStartTime = System.currentTimeMillis();
902 | } else {
903 |
904 | /**
905 | * We do do all calculations in long to reduce software float
906 | * calculations. We use 1000 as it gives us good accuracy and
907 | * small rounding errors
908 | */
909 | final long oneSecond = 1000; // SUPPRESS CHECKSTYLE
910 | long normalizedTime = (oneSecond * (System.currentTimeMillis() - mStartTime)) / mDuration;
911 | normalizedTime = Math.max(Math.min(normalizedTime, oneSecond), 0);
912 |
913 | final int deltaY = Math.round((mScrollFromY - mScrollToY)
914 | * mInterpolator.getInterpolation(normalizedTime / (float) oneSecond));
915 | mCurrentY = mScrollFromY - deltaY;
916 |
917 | setScrollTo(0, mCurrentY);
918 | }
919 |
920 | // If we're not at the target Y, keep going...
921 | if (mContinueRunning && mScrollToY != mCurrentY) {
922 | PullToRefreshBase.this.postDelayed(this, 16);// SUPPRESS CHECKSTYLE
923 | }
924 | }
925 |
926 | /**
927 | * 停止滑动
928 | */
929 | public void stop() {
930 | mContinueRunning = false;
931 | removeCallbacks(this);
932 | }
933 | }
934 | }
935 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/PullToRefreshGridView.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import com.lee.pullrefresh.ui.ILoadingLayout.State;
4 |
5 | import android.content.Context;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.widget.AbsListView;
9 | import android.widget.AbsListView.OnScrollListener;
10 | import android.widget.Adapter;
11 | import android.widget.GridView;
12 |
13 | /**
14 | * 这个类实现了GridView下拉刷新,上加载更多和滑到底部自动加载
15 | *
16 | * @author Li Hong
17 | * @since 2013-8-15
18 | */
19 | public class PullToRefreshGridView extends PullToRefreshBase implements OnScrollListener {
20 |
21 | /**ListView*/
22 | private GridView mGridView;
23 | /**用于滑到底部自动加载的Footer*/
24 | private LoadingLayout mFooterLayout;
25 | /**滚动的监听器*/
26 | private OnScrollListener mScrollListener;
27 |
28 | /**
29 | * 构造方法
30 | *
31 | * @param context context
32 | */
33 | public PullToRefreshGridView(Context context) {
34 | this(context, null);
35 | }
36 |
37 | /**
38 | * 构造方法
39 | *
40 | * @param context context
41 | * @param attrs attrs
42 | */
43 | public PullToRefreshGridView(Context context, AttributeSet attrs) {
44 | this(context, attrs, 0);
45 | }
46 |
47 | /**
48 | * 构造方法
49 | *
50 | * @param context context
51 | * @param attrs attrs
52 | * @param defStyle defStyle
53 | */
54 | public PullToRefreshGridView(Context context, AttributeSet attrs, int defStyle) {
55 | super(context, attrs, defStyle);
56 |
57 | setPullLoadEnabled(false);
58 | }
59 |
60 | @Override
61 | protected GridView createRefreshableView(Context context, AttributeSet attrs) {
62 | GridView gridView = new GridView(context);
63 | mGridView = gridView;
64 | gridView.setOnScrollListener(this);
65 |
66 | return gridView;
67 | }
68 |
69 | /**
70 | * 设置是否有更多数据的标志
71 | *
72 | * @param hasMoreData true表示还有更多的数据,false表示没有更多数据了
73 | */
74 | public void setHasMoreData(boolean hasMoreData) {
75 | if (null != mFooterLayout) {
76 | if (!hasMoreData) {
77 | mFooterLayout.setState(State.NO_MORE_DATA);
78 | }
79 | }
80 | }
81 |
82 | /**
83 | * 设置滑动的监听器
84 | *
85 | * @param l 监听器
86 | */
87 | public void setOnScrollListener(OnScrollListener l) {
88 | mScrollListener = l;
89 | }
90 |
91 | @Override
92 | protected boolean isReadyForPullUp() {
93 | return isLastItemVisible();
94 | }
95 |
96 | @Override
97 | protected boolean isReadyForPullDown() {
98 | return isFirstItemVisible();
99 | }
100 |
101 | @Override
102 | protected void startLoading() {
103 | super.startLoading();
104 |
105 |
106 | if (null != mFooterLayout) {
107 | mFooterLayout.setState(State.REFRESHING);
108 | }
109 | }
110 |
111 | @Override
112 | public void onPullUpRefreshComplete() {
113 | super.onPullUpRefreshComplete();
114 |
115 | if (null != mFooterLayout) {
116 | mFooterLayout.setState(State.RESET);
117 | }
118 | }
119 |
120 | @Override
121 | public void setScrollLoadEnabled(boolean scrollLoadEnabled) {
122 | super.setScrollLoadEnabled(scrollLoadEnabled);
123 |
124 | if (scrollLoadEnabled) {
125 | // 设置Footer
126 | if (null == mFooterLayout) {
127 | mFooterLayout = new FooterLoadingLayout(getContext());
128 | }
129 |
130 | //mGridView.removeFooterView(mFooterLayout);
131 | //mGridView.addFooterView(mFooterLayout, null, false);
132 | } else {
133 | if (null != mFooterLayout) {
134 | //mGridView.removeFooterView(mFooterLayout);
135 | }
136 | }
137 | }
138 |
139 | @Override
140 | public void onScrollStateChanged(AbsListView view, int scrollState) {
141 | if (isScrollLoadEnabled() && hasMoreData()) {
142 | if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
143 | || scrollState == OnScrollListener.SCROLL_STATE_FLING) {
144 | if (isReadyForPullUp()) {
145 | startLoading();
146 | }
147 | }
148 | }
149 |
150 | if (null != mScrollListener) {
151 | mScrollListener.onScrollStateChanged(view, scrollState);
152 | }
153 | }
154 |
155 | @Override
156 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
157 | if (null != mScrollListener) {
158 | mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
159 | }
160 | }
161 |
162 | /**
163 | * 表示是否还有更多数据
164 | *
165 | * @return true表示还有更多数据
166 | */
167 | private boolean hasMoreData() {
168 | if ((null != mFooterLayout) && (mFooterLayout.getState() == State.NO_MORE_DATA)) {
169 | return false;
170 | }
171 |
172 | return true;
173 | }
174 |
175 | /**
176 | * 判断第一个child是否完全显示出来
177 | *
178 | * @return true完全显示出来,否则false
179 | */
180 | private boolean isFirstItemVisible() {
181 | final Adapter adapter = mGridView.getAdapter();
182 |
183 | if (null == adapter || adapter.isEmpty()) {
184 | return true;
185 | }
186 |
187 | int mostTop = (mGridView.getChildCount() > 0) ? mGridView.getChildAt(0).getTop() : 0;
188 | if (mostTop >= 0) {
189 | return true;
190 | }
191 |
192 | return false;
193 | }
194 |
195 | /**
196 | * 判断最后一个child是否完全显示出来
197 | *
198 | * @return true完全显示出来,否则false
199 | */
200 | private boolean isLastItemVisible() {
201 | final Adapter adapter = mGridView.getAdapter();
202 |
203 | if (null == adapter || adapter.isEmpty()) {
204 | return true;
205 | }
206 |
207 | final int lastItemPosition = adapter.getCount() - 1;
208 | final int lastVisiblePosition = mGridView.getLastVisiblePosition();
209 |
210 | /**
211 | * This check should really just be: lastVisiblePosition == lastItemPosition, but ListView
212 | * internally uses a FooterView which messes the positions up. For me we'll just subtract
213 | * one to account for it and rely on the inner condition which checks getBottom().
214 | */
215 | if (lastVisiblePosition >= lastItemPosition - 1) {
216 | final int childIndex = lastVisiblePosition - mGridView.getFirstVisiblePosition();
217 | final int childCount = mGridView.getChildCount();
218 | final int index = Math.min(childIndex, childCount - 1);
219 | final View lastVisibleChild = mGridView.getChildAt(index);
220 | if (lastVisibleChild != null) {
221 | return lastVisibleChild.getBottom() <= mGridView.getBottom();
222 | }
223 | }
224 |
225 | return false;
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/PullToRefreshListView.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import com.lee.pullrefresh.ui.ILoadingLayout.State;
4 |
5 | import android.content.Context;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.widget.AbsListView;
9 | import android.widget.AbsListView.OnScrollListener;
10 | import android.widget.Adapter;
11 | import android.widget.ListView;
12 |
13 | /**
14 | * 这个类实现了ListView下拉刷新,上加载更多和滑到底部自动加载
15 | *
16 | * @author Li Hong
17 | * @since 2013-8-15
18 | */
19 | public class PullToRefreshListView extends PullToRefreshBase implements OnScrollListener {
20 |
21 | /**ListView*/
22 | private ListView mListView;
23 | /**用于滑到底部自动加载的Footer*/
24 | private LoadingLayout mLoadMoreFooterLayout;
25 | /**滚动的监听器*/
26 | private OnScrollListener mScrollListener;
27 |
28 | /**
29 | * 构造方法
30 | *
31 | * @param context context
32 | */
33 | public PullToRefreshListView(Context context) {
34 | this(context, null);
35 | }
36 |
37 | /**
38 | * 构造方法
39 | *
40 | * @param context context
41 | * @param attrs attrs
42 | */
43 | public PullToRefreshListView(Context context, AttributeSet attrs) {
44 | this(context, attrs, 0);
45 | }
46 |
47 | /**
48 | * 构造方法
49 | *
50 | * @param context context
51 | * @param attrs attrs
52 | * @param defStyle defStyle
53 | */
54 | public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {
55 | super(context, attrs, defStyle);
56 |
57 | setPullLoadEnabled(false);
58 | }
59 |
60 | @Override
61 | protected ListView createRefreshableView(Context context, AttributeSet attrs) {
62 | ListView listView = new ListView(context);
63 | mListView = listView;
64 | listView.setOnScrollListener(this);
65 |
66 | return listView;
67 | }
68 |
69 | /**
70 | * 设置是否有更多数据的标志
71 | *
72 | * @param hasMoreData true表示还有更多的数据,false表示没有更多数据了
73 | */
74 | public void setHasMoreData(boolean hasMoreData) {
75 | if (!hasMoreData) {
76 | if (null != mLoadMoreFooterLayout) {
77 | mLoadMoreFooterLayout.setState(State.NO_MORE_DATA);
78 | }
79 |
80 | LoadingLayout footerLoadingLayout = getFooterLoadingLayout();
81 | if (null != footerLoadingLayout) {
82 | footerLoadingLayout.setState(State.NO_MORE_DATA);
83 | }
84 | }
85 | }
86 |
87 | /**
88 | * 设置滑动的监听器
89 | *
90 | * @param l 监听器
91 | */
92 | public void setOnScrollListener(OnScrollListener l) {
93 | mScrollListener = l;
94 | }
95 |
96 | @Override
97 | protected boolean isReadyForPullUp() {
98 | return isLastItemVisible();
99 | }
100 |
101 | @Override
102 | protected boolean isReadyForPullDown() {
103 | return isFirstItemVisible();
104 | }
105 |
106 | @Override
107 | protected void startLoading() {
108 | super.startLoading();
109 |
110 | if (null != mLoadMoreFooterLayout) {
111 | mLoadMoreFooterLayout.setState(State.REFRESHING);
112 | }
113 | }
114 |
115 | @Override
116 | public void onPullUpRefreshComplete() {
117 | super.onPullUpRefreshComplete();
118 |
119 | if (null != mLoadMoreFooterLayout) {
120 | mLoadMoreFooterLayout.setState(State.RESET);
121 | }
122 | }
123 |
124 | @Override
125 | public void setScrollLoadEnabled(boolean scrollLoadEnabled) {
126 | super.setScrollLoadEnabled(scrollLoadEnabled);
127 |
128 | if (scrollLoadEnabled) {
129 | // 设置Footer
130 | if (null == mLoadMoreFooterLayout) {
131 | mLoadMoreFooterLayout = new FooterLoadingLayout(getContext());
132 | }
133 |
134 | if (null == mLoadMoreFooterLayout.getParent()) {
135 | mListView.addFooterView(mLoadMoreFooterLayout, null, false);
136 | }
137 | mLoadMoreFooterLayout.show(true);
138 | } else {
139 | if (null != mLoadMoreFooterLayout) {
140 | mLoadMoreFooterLayout.show(false);
141 | }
142 | }
143 | }
144 |
145 | @Override
146 | public LoadingLayout getFooterLoadingLayout() {
147 | if (isScrollLoadEnabled()) {
148 | return mLoadMoreFooterLayout;
149 | }
150 |
151 | return super.getFooterLoadingLayout();
152 | }
153 |
154 | @Override
155 | public void onScrollStateChanged(AbsListView view, int scrollState) {
156 | if (isScrollLoadEnabled() && hasMoreData()) {
157 | if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
158 | || scrollState == OnScrollListener.SCROLL_STATE_FLING) {
159 | if (isReadyForPullUp()) {
160 | startLoading();
161 | }
162 | }
163 | }
164 |
165 | if (null != mScrollListener) {
166 | mScrollListener.onScrollStateChanged(view, scrollState);
167 | }
168 | }
169 |
170 | @Override
171 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
172 | if (null != mScrollListener) {
173 | mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
174 | }
175 | }
176 |
177 | @Override
178 | protected LoadingLayout createHeaderLoadingLayout(Context context, AttributeSet attrs) {
179 | return new RotateLoadingLayout(context);
180 | }
181 |
182 | /**
183 | * 表示是否还有更多数据
184 | *
185 | * @return true表示还有更多数据
186 | */
187 | private boolean hasMoreData() {
188 | if ((null != mLoadMoreFooterLayout) && (mLoadMoreFooterLayout.getState() == State.NO_MORE_DATA)) {
189 | return false;
190 | }
191 |
192 | return true;
193 | }
194 |
195 | /**
196 | * 判断第一个child是否完全显示出来
197 | *
198 | * @return true完全显示出来,否则false
199 | */
200 | private boolean isFirstItemVisible() {
201 | final Adapter adapter = mListView.getAdapter();
202 |
203 | if (null == adapter || adapter.isEmpty()) {
204 | return true;
205 | }
206 |
207 | int mostTop = (mListView.getChildCount() > 0) ? mListView.getChildAt(0).getTop() : 0;
208 | if (mostTop >= 0) {
209 | return true;
210 | }
211 |
212 | return false;
213 | }
214 |
215 | /**
216 | * 判断最后一个child是否完全显示出来
217 | *
218 | * @return true完全显示出来,否则false
219 | */
220 | private boolean isLastItemVisible() {
221 | final Adapter adapter = mListView.getAdapter();
222 |
223 | if (null == adapter || adapter.isEmpty()) {
224 | return true;
225 | }
226 |
227 | final int lastItemPosition = adapter.getCount() - 1;
228 | final int lastVisiblePosition = mListView.getLastVisiblePosition();
229 |
230 | /**
231 | * This check should really just be: lastVisiblePosition == lastItemPosition, but ListView
232 | * internally uses a FooterView which messes the positions up. For me we'll just subtract
233 | * one to account for it and rely on the inner condition which checks getBottom().
234 | */
235 | if (lastVisiblePosition >= lastItemPosition - 1) {
236 | final int childIndex = lastVisiblePosition - mListView.getFirstVisiblePosition();
237 | final int childCount = mListView.getChildCount();
238 | final int index = Math.min(childIndex, childCount - 1);
239 | final View lastVisibleChild = mListView.getChildAt(index);
240 | if (lastVisibleChild != null) {
241 | return lastVisibleChild.getBottom() <= mListView.getBottom();
242 | }
243 | }
244 |
245 | return false;
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/PullToRefreshScrollView.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.widget.ScrollView;
7 |
8 | /**
9 | * 封装了ScrollView的下拉刷新
10 | *
11 | * @author Li Hong
12 | * @since 2013-8-22
13 | */
14 | public class PullToRefreshScrollView extends PullToRefreshBase {
15 | /**
16 | * 构造方法
17 | *
18 | * @param context context
19 | */
20 | public PullToRefreshScrollView(Context context) {
21 | this(context, null);
22 | }
23 |
24 | /**
25 | * 构造方法
26 | *
27 | * @param context context
28 | * @param attrs attrs
29 | */
30 | public PullToRefreshScrollView(Context context, AttributeSet attrs) {
31 | this(context, attrs, 0);
32 | }
33 |
34 | /**
35 | * 构造方法
36 | *
37 | * @param context context
38 | * @param attrs attrs
39 | * @param defStyle defStyle
40 | */
41 | public PullToRefreshScrollView(Context context, AttributeSet attrs, int defStyle) {
42 | super(context, attrs, defStyle);
43 | }
44 |
45 | /**
46 | * @see com.nj1s.lib.pullrefresh.PullToRefreshBase#createRefreshableView(android.content.Context, android.util.AttributeSet)
47 | */
48 | @Override
49 | protected ScrollView createRefreshableView(Context context, AttributeSet attrs) {
50 | ScrollView scrollView = new ScrollView(context);
51 | return scrollView;
52 | }
53 |
54 | /**
55 | * @see com.nj1s.lib.pullrefresh.PullToRefreshBase#isReadyForPullDown()
56 | */
57 | @Override
58 | protected boolean isReadyForPullDown() {
59 | return mRefreshableView.getScrollY() == 0;
60 | }
61 |
62 | /**
63 | * @see com.nj1s.lib.pullrefresh.PullToRefreshBase#isReadyForPullUp()
64 | */
65 | @Override
66 | protected boolean isReadyForPullUp() {
67 | View scrollViewChild = mRefreshableView.getChildAt(0);
68 | if (null != scrollViewChild) {
69 | return mRefreshableView.getScrollY() >= (scrollViewChild.getHeight() - getHeight());
70 | }
71 |
72 | return false;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/PullToRefreshWebView.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.util.FloatMath;
6 | import android.webkit.WebView;
7 |
8 | /**
9 | * 封装了WebView的下拉刷新
10 | *
11 | * @author Li Hong
12 | * @since 2013-8-22
13 | */
14 | public class PullToRefreshWebView extends PullToRefreshBase {
15 | /**
16 | * 构造方法
17 | *
18 | * @param context context
19 | */
20 | public PullToRefreshWebView(Context context) {
21 | this(context, null);
22 | }
23 |
24 | /**
25 | * 构造方法
26 | *
27 | * @param context context
28 | * @param attrs attrs
29 | */
30 | public PullToRefreshWebView(Context context, AttributeSet attrs) {
31 | this(context, attrs, 0);
32 | }
33 |
34 | /**
35 | * 构造方法
36 | *
37 | * @param context context
38 | * @param attrs attrs
39 | * @param defStyle defStyle
40 | */
41 | public PullToRefreshWebView(Context context, AttributeSet attrs, int defStyle) {
42 | super(context, attrs, defStyle);
43 | }
44 |
45 | /**
46 | * @see com.nj1s.lib.pullrefresh.PullToRefreshBase#createRefreshableView(android.content.Context, android.util.AttributeSet)
47 | */
48 | @Override
49 | protected WebView createRefreshableView(Context context, AttributeSet attrs) {
50 | WebView webView = new WebView(context);
51 | return webView;
52 | }
53 |
54 | /**
55 | * @see com.nj1s.lib.pullrefresh.PullToRefreshBase#isReadyForPullDown()
56 | */
57 | @Override
58 | protected boolean isReadyForPullDown() {
59 | return mRefreshableView.getScrollY() == 0;
60 | }
61 |
62 | /**
63 | * @see com.nj1s.lib.pullrefresh.PullToRefreshBase#isReadyForPullUp()
64 | */
65 | @Override
66 | protected boolean isReadyForPullUp() {
67 | float exactContentHeight = FloatMath.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale());
68 | return mRefreshableView.getScrollY() >= (exactContentHeight - mRefreshableView.getHeight());
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/PullRefreshDemo/src/com/lee/pullrefresh/ui/RotateLoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.lee.pullrefresh.ui;
2 |
3 | import com.lee.pullrefresh.R;
4 |
5 | import android.content.Context;
6 | import android.text.TextUtils;
7 | import android.util.AttributeSet;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.animation.Animation;
11 | import android.view.animation.Interpolator;
12 | import android.view.animation.LinearInterpolator;
13 | import android.view.animation.RotateAnimation;
14 | import android.widget.ImageView;
15 | import android.widget.ImageView.ScaleType;
16 | import android.widget.RelativeLayout;
17 | import android.widget.TextView;
18 |
19 | /**
20 | * 这个类封装了下拉刷新的布局
21 | *
22 | * @author Li Hong
23 | * @since 2013-7-30
24 | */
25 | public class RotateLoadingLayout extends LoadingLayout {
26 | /**旋转动画的时间*/
27 | static final int ROTATION_ANIMATION_DURATION = 1200;
28 | /**动画插值*/
29 | static final Interpolator ANIMATION_INTERPOLATOR = new LinearInterpolator();
30 | /**Header的容器*/
31 | private RelativeLayout mHeaderContainer;
32 | /**箭头图片*/
33 | private ImageView mArrowImageView;
34 | /**状态提示TextView*/
35 | private TextView mHintTextView;
36 | /**最后更新时间的TextView*/
37 | private TextView mHeaderTimeView;
38 | /**最后更新时间的标题*/
39 | private TextView mHeaderTimeViewTitle;
40 | /**旋转的动画*/
41 | private Animation mRotateAnimation;
42 |
43 | /**
44 | * 构造方法
45 | *
46 | * @param context context
47 | */
48 | public RotateLoadingLayout(Context context) {
49 | super(context);
50 | init(context);
51 | }
52 |
53 | /**
54 | * 构造方法
55 | *
56 | * @param context context
57 | * @param attrs attrs
58 | */
59 | public RotateLoadingLayout(Context context, AttributeSet attrs) {
60 | super(context, attrs);
61 | init(context);
62 | }
63 |
64 | /**
65 | * 初始化
66 | *
67 | * @param context context
68 | */
69 | private void init(Context context) {
70 | mHeaderContainer = (RelativeLayout) findViewById(R.id.pull_to_refresh_header_content);
71 | mArrowImageView = (ImageView) findViewById(R.id.pull_to_refresh_header_arrow);
72 | mHintTextView = (TextView) findViewById(R.id.pull_to_refresh_header_hint_textview);
73 | mHeaderTimeView = (TextView) findViewById(R.id.pull_to_refresh_header_time);
74 | mHeaderTimeViewTitle = (TextView) findViewById(R.id.pull_to_refresh_last_update_time_text);
75 |
76 | mArrowImageView.setScaleType(ScaleType.CENTER);
77 | mArrowImageView.setImageResource(R.drawable.default_ptr_rotate);
78 |
79 | float pivotValue = 0.5f; // SUPPRESS CHECKSTYLE
80 | float toDegree = 720.0f; // SUPPRESS CHECKSTYLE
81 | mRotateAnimation = new RotateAnimation(0.0f, toDegree, Animation.RELATIVE_TO_SELF, pivotValue,
82 | Animation.RELATIVE_TO_SELF, pivotValue);
83 | mRotateAnimation.setFillAfter(true);
84 | mRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR);
85 | mRotateAnimation.setDuration(ROTATION_ANIMATION_DURATION);
86 | mRotateAnimation.setRepeatCount(Animation.INFINITE);
87 | mRotateAnimation.setRepeatMode(Animation.RESTART);
88 | }
89 |
90 | @Override
91 | protected View createLoadingView(Context context, AttributeSet attrs) {
92 | View container = LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header2, null);
93 | return container;
94 | }
95 |
96 | @Override
97 | public void setLastUpdatedLabel(CharSequence label) {
98 | // 如果最后更新的时间的文本是空的话,隐藏前面的标题
99 | mHeaderTimeViewTitle.setVisibility(TextUtils.isEmpty(label) ? View.INVISIBLE : View.VISIBLE);
100 | mHeaderTimeView.setText(label);
101 | }
102 |
103 | @Override
104 | public int getContentSize() {
105 | if (null != mHeaderContainer) {
106 | return mHeaderContainer.getHeight();
107 | }
108 |
109 | return (int) (getResources().getDisplayMetrics().density * 60);
110 | }
111 |
112 | @Override
113 | protected void onStateChanged(State curState, State oldState) {
114 | super.onStateChanged(curState, oldState);
115 | }
116 |
117 | @Override
118 | protected void onReset() {
119 | resetRotation();
120 | mHintTextView.setText(R.string.pull_to_refresh_header_hint_normal);
121 | }
122 |
123 | @Override
124 | protected void onReleaseToRefresh() {
125 | mHintTextView.setText(R.string.pull_to_refresh_header_hint_ready);
126 | }
127 |
128 | @Override
129 | protected void onPullToRefresh() {
130 | mHintTextView.setText(R.string.pull_to_refresh_header_hint_normal);
131 | }
132 |
133 | @Override
134 | protected void onRefreshing() {
135 | resetRotation();
136 | mArrowImageView.startAnimation(mRotateAnimation);
137 | mHintTextView.setText(R.string.pull_to_refresh_header_hint_loading);
138 | }
139 |
140 | @Override
141 | public void onPull(float scale) {
142 | float angle = scale * 180f; // SUPPRESS CHECKSTYLE
143 | mArrowImageView.setRotation(angle);
144 | }
145 |
146 | /**
147 | * 重置动画
148 | */
149 | private void resetRotation() {
150 | mArrowImageView.clearAnimation();
151 | mArrowImageView.setRotation(0);
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/PullToRefreshDemo/source.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/PullToRefreshDemo/source.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | demo
2 | ====
3 |
4 | my own demo and practices
5 |
6 | ##master
7 |
8 | * SlideDrawer Demo
9 | * PullToRefreshDemo
10 |
--------------------------------------------------------------------------------
/bin/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/bin/OrderDishes.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/OrderDishes.apk
--------------------------------------------------------------------------------
/bin/classes.dex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes.dex
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/BuildConfig.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/BuildConfig.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/MainActivity$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/MainActivity$1.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/MainActivity$2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/MainActivity$2.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/MainActivity$GridAdapter.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/MainActivity$GridAdapter.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/MainActivity.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/MainActivity.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/R$attr.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/R$attr.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/R$drawable.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/R$drawable.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/R$id.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/R$id.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/R$layout.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/R$layout.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/R$menu.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/R$menu.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/R$string.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/R$string.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/R$style.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/R$style.class
--------------------------------------------------------------------------------
/bin/classes/com/example/orderdishes/R.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/classes/com/example/orderdishes/R.class
--------------------------------------------------------------------------------
/bin/dexedLibs/android-support-v4-d97d3d4d7255b3ab48cede3c77e494b7.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/dexedLibs/android-support-v4-d97d3d4d7255b3ab48cede3c77e494b7.jar
--------------------------------------------------------------------------------
/bin/jarlist.cache:
--------------------------------------------------------------------------------
1 | # cache for current jar dependecy. DO NOT EDIT.
2 | # format is
3 | # Encoding is UTF-8
4 |
--------------------------------------------------------------------------------
/bin/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/bin/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/bin/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/bin/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/bin/resources.ap_:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/bin/resources.ap_
--------------------------------------------------------------------------------
/gen/com/example/orderdishes/BuildConfig.java:
--------------------------------------------------------------------------------
1 | /** Automatically generated file. DO NOT MODIFY */
2 | package com.example.orderdishes;
3 |
4 | public final class BuildConfig {
5 | public final static boolean DEBUG = true;
6 | }
--------------------------------------------------------------------------------
/gen/com/example/orderdishes/R.java:
--------------------------------------------------------------------------------
1 | /* AUTO-GENERATED FILE. DO NOT MODIFY.
2 | *
3 | * This class was automatically generated by the
4 | * aapt tool from the resource data it found. It
5 | * should not be modified by hand.
6 | */
7 |
8 | package com.example.orderdishes;
9 |
10 | public final class R {
11 | public static final class attr {
12 | }
13 | public static final class drawable {
14 | public static final int ic_launcher=0x7f020000;
15 | }
16 | public static final class id {
17 | public static final int allApps=0x7f070001;
18 | public static final int app_icon=0x7f070004;
19 | public static final int app_title=0x7f070003;
20 | public static final int imageViewIcon=0x7f070002;
21 | public static final int menu_settings=0x7f070005;
22 | public static final int sliding=0x7f070000;
23 | }
24 | public static final class layout {
25 | public static final int activity_main=0x7f030000;
26 | public static final int application_layout=0x7f030001;
27 | }
28 | public static final class menu {
29 | public static final int activity_main=0x7f060000;
30 | }
31 | public static final class string {
32 | public static final int app_name=0x7f040000;
33 | public static final int hello_world=0x7f040001;
34 | public static final int menu_settings=0x7f040002;
35 | }
36 | public static final class style {
37 | /**
38 | Base application theme, dependent on API level. This theme is replaced
39 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
40 |
41 |
42 | Theme customizations available in newer API levels can go in
43 | res/values-vXX/styles.xml, while customizations related to
44 | backward-compatibility can go here.
45 |
46 |
47 | Base application theme for API 11+. This theme completely replaces
48 | AppBaseTheme from res/values/styles.xml on API 11+ devices.
49 |
50 | API 11 theme customizations can go here.
51 |
52 | Base application theme for API 14+. This theme completely replaces
53 | AppBaseTheme from BOTH res/values/styles.xml and
54 | res/values-v11/styles.xml on API 14+ devices.
55 |
56 | API 14 theme customizations can go here.
57 | */
58 | public static final int AppBaseTheme=0x7f050000;
59 | /** Application theme.
60 | All customizations that are NOT specific to a particular API-level can go here.
61 | */
62 | public static final int AppTheme=0x7f050001;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/ic_launcher-web.png
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/project.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 edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-17
15 |
--------------------------------------------------------------------------------
/src/com/example/orderdishes/MainActivity.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edagarli/demo/dc67e75afaf534b23d2ca13e5bd46e2b1be5f3bb/src/com/example/orderdishes/MainActivity.java
--------------------------------------------------------------------------------
/未命名绘图.drawio:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------