├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── app-release.apk
├── build.gradle
├── libs
│ └── glide-3.6.1.jar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── liangmutian
│ │ └── airrecyclerview
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── liangmutian
│ │ │ └── airrecyclerview
│ │ │ ├── ActType.java
│ │ │ ├── Adapter.java
│ │ │ ├── ChangeScrollStateCallback.java
│ │ │ ├── MainActivity.java
│ │ │ └── swipetoloadlayout
│ │ │ ├── BaseRecyclerAdapter.java
│ │ │ ├── OnLoadMoreListener.java
│ │ │ ├── OnRefreshListener.java
│ │ │ ├── RefreshHeaderView.java
│ │ │ ├── SuperRefreshRecyclerView.java
│ │ │ ├── SwipeLoadMoreFooterLayout.java
│ │ │ ├── SwipeLoadMoreTrigger.java
│ │ │ ├── SwipeRefreshHeaderLayout.java
│ │ │ ├── SwipeRefreshTrigger.java
│ │ │ ├── SwipeToLoadLayout.java
│ │ │ └── SwipeTrigger.java
│ └── res
│ │ ├── drawable
│ │ ├── anim_refresh.xml
│ │ └── bg_progressbar.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── item_choose_act_type.xml
│ │ ├── item_choose_act_type2.xml
│ │ ├── layout_footer_loading.xml
│ │ ├── layout_refresh_header.xml
│ │ ├── layout_super_recycler.xml
│ │ └── layout_super_refresh_recycler.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ ├── bg_loading_circle.png
│ │ ├── gpf.png
│ │ ├── gpg.png
│ │ ├── gph.png
│ │ ├── gpi.png
│ │ ├── gpj.png
│ │ ├── gpk.png
│ │ ├── gpl.png
│ │ ├── gpm.png
│ │ ├── gpn.png
│ │ ├── gpo.png
│ │ ├── gpq.png
│ │ ├── gpr.png
│ │ ├── ic_launcher.png
│ │ ├── icon_refresh.png
│ │ ├── n1.png
│ │ ├── n2.png
│ │ ├── n3.png
│ │ ├── n4.png
│ │ └── n5.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ ├── attrs.xml
│ │ ├── dimens.xml
│ │ └── ids.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── liangmutian
│ └── airrecyclerview
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
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 | Abstraction issuesJava
46 |
47 |
48 | Android
49 |
50 |
51 | Android > Lint > Accessibility
52 |
53 |
54 | Android > Lint > Correctness
55 |
56 |
57 | Android > Lint > Correctness > Messages
58 |
59 |
60 | Android > Lint > Internationalization
61 |
62 |
63 | Android > Lint > Internationalization > Bidirectional Text
64 |
65 |
66 | Android > Lint > Performance
67 |
68 |
69 | Android > Lint > Security
70 |
71 |
72 | Android > Lint > Usability
73 |
74 |
75 | Android > Lint > Usability > Icons
76 |
77 |
78 | Android > Lint > Usability > Typography
79 |
80 |
81 | Assignment issuesJava
82 |
83 |
84 | Bitwise operation issuesJava
85 |
86 |
87 | C/C++
88 |
89 |
90 | Class metricsJava
91 |
92 |
93 | Class structureJava
94 |
95 |
96 | Cloning issuesJava
97 |
98 |
99 | Code maturity issuesJava
100 |
101 |
102 | Code style issuesJava
103 |
104 |
105 | Compiler issuesJava
106 |
107 |
108 | Control FlowGroovy
109 |
110 |
111 | Control flow issuesJava
112 |
113 |
114 | Data flow issuesJava
115 |
116 |
117 | Dependency issuesJava
118 |
119 |
120 | Encapsulation issuesJava
121 |
122 |
123 | Error handlingJava
124 |
125 |
126 | Finalization issuesJava
127 |
128 |
129 | General
130 |
131 |
132 | GeneralC/C++
133 |
134 |
135 | GeneralJava
136 |
137 |
138 | Google Cloud Endpoints
139 |
140 |
141 | Gradle
142 |
143 |
144 | Groovy
145 |
146 |
147 | HTML
148 |
149 |
150 | ImportsJava
151 |
152 |
153 | Inheritance issuesJava
154 |
155 |
156 | Initialization issuesJava
157 |
158 |
159 | Internationalization issues
160 |
161 |
162 | Internationalization issuesJava
163 |
164 |
165 | J2ME issuesJava
166 |
167 |
168 | JUnit issuesJava
169 |
170 |
171 | Java
172 |
173 |
174 | Java language level issuesJava
175 |
176 |
177 | Java language level migration aidsJava
178 |
179 |
180 | JavaBeans issuesJava
181 |
182 |
183 | Javadoc issuesJava
184 |
185 |
186 | Logging issuesJava
187 |
188 |
189 | Manifest
190 |
191 |
192 | Memory issuesJava
193 |
194 |
195 | Method MetricsGroovy
196 |
197 |
198 | Method metricsJava
199 |
200 |
201 | Modularization issuesJava
202 |
203 |
204 | Naming ConventionsGroovy
205 |
206 |
207 | Naming conventionsJava
208 |
209 |
210 | Numeric issuesJava
211 |
212 |
213 | Packaging issuesJava
214 |
215 |
216 | Pattern Validation
217 |
218 |
219 | Performance issuesJava
220 |
221 |
222 | Portability issuesJava
223 |
224 |
225 | Potentially confusing code constructsGroovy
226 |
227 |
228 | Probable bugsGradle
229 |
230 |
231 | Probable bugsGroovy
232 |
233 |
234 | Probable bugsJava
235 |
236 |
237 | Properties Files
238 |
239 |
240 | Properties FilesJava
241 |
242 |
243 | Security issuesJava
244 |
245 |
246 | Serialization issuesJava
247 |
248 |
249 | StyleGroovy
250 |
251 |
252 | TestNGJava
253 |
254 |
255 | Threading issuesGroovy
256 |
257 |
258 | Threading issuesJava
259 |
260 |
261 | Visibility issuesJava
262 |
263 |
264 | XML
265 |
266 |
267 | toString() issuesJava
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 | 1.8
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | 让RecyclerView优先加载可见item,如何在RecyclerView滑动中停止图片的加载保证页面流畅。
3 |
4 | 先看效果图:
5 | 
6 | 
7 |
8 | 额。算了再流畅GIF也无法展示,想看效果去GITHUB下载代码吧。
9 | 本文Github代码链接
10 | https://github.com/AndroidMsky/GlideScrollRecyclerView
11 | 欢迎star哦。
12 |
13 |
14 | 对下拉刷新上滑加载RecyclerView还不明白的请看:
15 | http://blog.csdn.net/androidmsky/article/details/52922348
16 | 对多样式布局Gilde基本用法还不懂得请看:
17 | http://blog.csdn.net/androidmsky/article/details/52944370
18 | 两篇都是笔者的博文,相信入门搭建起可用框架还是有帮助的。
19 |
20 | 让我们来回顾一下陈旧的Listview,如果item中有网络图片,那时候我们怎么做的呢?我们要注意一下几个重点:
21 | 1.网络图片获取
22 | 2.网络图片二级缓存(至少一级缓存)
23 | 3.在高速滑动时候停止图片加载线程
24 | 4.在低速滑动,停止滑动时候开启线程
25 | 5.下拉刷新
26 | 6.上滑加载
27 | 7.优先加载可见item
28 |
29 | 如果不用第三方框架,自己维护线程池等等东西,想想都复杂。而如今我们不需要这些东西了,本文的Dome轻轻松松做到这7点。
30 | 首先1 2 glide给予我们完美的支持,5 6 我前文提到过的RecyclerView也有完美的支持。今天主要讲 3 4 7这三点如何实现。
31 |
32 | 首先看7.优先加载可见item,之前在listview我们可能这样做,写个滑动监听并且获取可见item的位置,然后加载对应图片,那么我们使用RecyclerView+Gilde到底如何做这一点呢,笔者一开始也有些犹豫,于是直接issues到了github :
33 |
34 | https://github.com/bumptech/glide/issues/1575#event-852660755
35 |
36 | 
37 |
38 |
39 | 看来老外对于自己的亲儿子项目还是很关爱的生怕我不懂啪啪啪举了几个例子,我只好用CET3.9的水平翻译一下了。
40 | 我的意思是当glide和recyclerview配合使用的时候,glide会不会优先加载可见item。
41 | TWiStErRob大概说,所有的加载优先级都是默认的,但是可以通过设置priority来这是优先级,但是不是在特别的情况下这个方法一般不被使用,他举了个例子说,如果一个item中有3个图片,他们的信息有重叠的部分,其中有一张图是最重要,信息最全的时候,可以提高这张图的优先级。
42 | 然而TWiStErRob给我的答案似乎并没有理解我想问的(可能是我CET3.9)的原因,我想算啦吧,问别人不如自己实践出来的更真实。于是我准备出如下场景:
43 | 1.网速很渣(因为速度快瞬间加载完很多图难以测试)
44 | 2.打开一个游戏的下载(先把比较渣的网速给我占了!)
45 | 3.item比较多
46 | 4.当前可见item比较少
47 | 5.设置Glide跳过二级缓存
48 | 6.对Glide加载成功进行监听并且打印图片对应位置log
49 |
50 |
51 | ```
52 | Glide.with(mContext).load(data.URl)
53 | .placeholder(R.mipmap.ic_launcher)
54 | .centerCrop()
55 | .skipMemoryCache(skipcache)
56 | .diskCacheStrategy(DiskCacheStrategy.NONE)
57 | .into(new GlideDrawableImageViewTarget(productHolder.imgRight) {
58 | @Override
59 | public void onResourceReady(GlideDrawable drawable, GlideAnimation anim) {
60 | super.onResourceReady(drawable, anim);
61 | Log.d("-------------------+", "" + (position+1));
62 | }
63 | ```
64 |
65 | 首先进来缓慢滑动几次:
66 |
67 | 
68 |
69 | 前四张图片被加载了符合预期。
70 |
71 |
72 | 接下来我们快速滑动到底部:
73 |
74 | 
75 |
76 |
77 | 如我所料,优先加载了可见的底部的item。
78 |
79 | 到这里7问题就解决了。我们以正缺的姿势去使用RecyclerView+Gilde就可以了。
80 |
81 | 接下来是:
82 | 3.在高速滑动时候停止图片加载线程
83 | 4.在低速滑动,停止滑动时候开启线程
84 | RecyclerView是可以滑动监听的但是别高兴的太早:
85 |
86 | ```
87 | SuperRefreshRecyclerView.一脸懵逼
88 | ```
89 | 你点不出设置滑动监听方法,其实是这样的:
90 |
91 | ```
92 | public class SuperRefreshRecyclerView extends FrameLayout {
93 |
94 | private RelativeLayout emptyView,errorView;
95 | private SwipeToLoadLayout swipeToLoadLayout;
96 | private SwipeLoadMoreFooterLayout swipeLoadMoreFooterLayout;
97 | private RecyclerView recyclerView;
98 | ```
99 | SuperRefreshRecyclerView中有个原声的RecyclerView所以我们肯定不能直接.到RecyclerView的方法了。于是决定自己写个callback接口就好了:
100 |
101 | ```
102 | public interface ChangeScrollStateCallback {
103 |
104 | public void change(int c);
105 |
106 | }
107 | ```
108 | 然后提供set方法:
109 |
110 | ```
111 | public void setChangeScrollStateCallback(ChangeScrollStateCallback mChangeScrollStateCallback){
112 | this.mChangeScrollStateCallback=mChangeScrollStateCallback;
113 |
114 | }
115 | ```
116 |
117 | 并在Activity中调用:
118 |
119 | ```
120 | superRecyclerView.setChangeScrollStateCallback(new ChangeScrollStateCallback() {
121 |
122 | //0 表示停止滑动的状态 SCROLL_STATE_IDLE
123 | //1表示正在滚动,用户手指在屏幕上 SCROLL_STATE_TOUCH_SCROLL
124 | //2表示正在滑动。用户手指已经离开屏幕 SCROLL_STATE_FLING
125 | @Override
126 | public void change(int c) {
127 |
128 | switch (c) {
129 | case 2:
130 | Glide.with(MainActivity.this).pauseRequests();
131 | Log.d("AAAAAAAAAAAAAAA", "暂停加载" + c);
132 |
133 | break;
134 | case 0:
135 | Glide.with(MainActivity.this).resumeRequests();
136 | Log.d("AAAAAAAAAAAAAAA","恢复加载" + c);
137 |
138 | break;
139 | case 1:
140 | Glide.with(MainActivity.this).resumeRequests();
141 | Log.d("AAAAAAAAAAAAAAA", "恢复加载" + c);
142 |
143 | break;
144 |
145 |
146 | }
147 |
148 | }
149 | });
150 | ```
151 |
152 | Glide提供的暂停恢复方法有没有很爽:
153 |
154 | ```
155 | Glide.with(MainActivity.this).pauseRequests();
156 | Glide.with(MainActivity.this).resumeRequests();
157 |
158 | ```
159 |
160 |
161 | 高速滑动一下屏幕:
162 |
163 | 
164 |
165 |
166 | 缓慢滑动屏幕:
167 |
168 | 
169 |
170 |
171 | 一切符合预期,1-7点我们就这样轻松的完成了。同事也给大家建议,在怀疑一个地方的时候不妨打断点打日志去看看到底是怎么回事,不断提高自己解决问题的能力,不要只会问而不会做。
172 |
173 | 欢迎关注作者。欢迎评论讨论。欢迎拍砖。
174 | 如果觉得这篇文章对你有帮助,欢迎打赏,
175 | 欢迎star,Fork我的github。
176 | 喜欢作者的也可以Follow。也算对作者的一种支持。
177 | 本文Github代码链接
178 | https://github.com/AndroidMsky/GlideScrollRecyclerView
179 |
180 |
181 |
182 | 欢迎加作者自营安卓开发交流群:308372687
183 |
184 | 
185 |
186 |
187 | 博主原创未经允许不得转载,转载必究。
188 |
189 |
190 |
191 |
192 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/app-release.apk
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 | defaultConfig {
7 | applicationId "com.example.liangmutian.airrecyclerview"
8 | minSdkVersion 15
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:23.1.1'
28 | compile 'com.android.support:recyclerview-v7:23.1.1'
29 | testCompile 'junit:junit:4.12'
30 | compile files('libs/glide-3.6.1.jar')
31 | }
32 |
--------------------------------------------------------------------------------
/app/libs/glide-3.6.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/libs/glide-3.6.1.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/ex-liyongqiang001/Desktop/andriodstudio/adt-bundle-mac-x86_64-20140702/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/liangmutian/airrecyclerview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.liangmutian.airrecyclerview", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/ActType.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview;
2 |
3 |
4 | import java.io.Serializable;
5 | import java.util.ArrayList;
6 |
7 | /**
8 | * Created by wuduogen838 on 16/10/8.
9 | */
10 |
11 | public class ActType implements Serializable {
12 | public static final int SHOW_TYPE_1=1;
13 | public static final int SHOW_TYPE_2=2;
14 | public int showType;
15 | public String name;
16 | public String code;
17 |
18 | public String URl;
19 | public ArrayList actTypeList=new ArrayList<>();
20 | public ActType(String code,int showType,String url){
21 | this.showType=showType;
22 | this.URl=url;
23 | this.name= code;
24 | this.code=code;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/Adapter.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 | import android.widget.Toast;
11 |
12 |
13 | import com.bumptech.glide.Glide;
14 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
15 | import com.bumptech.glide.load.resource.drawable.GlideDrawable;
16 | import com.bumptech.glide.request.animation.GlideAnimation;
17 | import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
18 | import com.example.liangmutian.airrecyclerview.swipetoloadlayout.BaseRecyclerAdapter;
19 |
20 | import java.util.List;
21 |
22 |
23 | /**
24 | */
25 | public class Adapter extends BaseRecyclerAdapter {
26 |
27 | private List list;
28 | private Context mContext;
29 |
30 | private boolean skipcache = true;
31 |
32 |
33 | public Adapter(List list, Context context) {
34 | super(list);
35 | this.mContext = context;
36 | this.list = list;
37 | }
38 |
39 | @Override
40 | public BaseRecyclerViewHolder createViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
41 | BaseRecyclerViewHolder holder = null;
42 |
43 |
44 | switch (viewType) {
45 | case ActType.SHOW_TYPE_1:
46 | holder = new ProductHolder(inflater.inflate(R.layout.item_choose_act_type, parent, false));
47 | break;
48 | case ActType.SHOW_TYPE_2:
49 | holder = new ProductHolder2(inflater.inflate(R.layout.item_choose_act_type2, parent, false));
50 | break;
51 |
52 | }
53 | return holder;
54 |
55 |
56 | }
57 |
58 | @Override
59 | public int getItemViewType(int position) {
60 | return list.get(position).showType;
61 | }
62 |
63 | @Override
64 | public void onBindViewHolder(BaseRecyclerViewHolder holder, final int position, final ActType data) {
65 |
66 |
67 | switch (getItemViewType(position)) {
68 | case ActType.SHOW_TYPE_1:
69 | ProductHolder productHolder = (ProductHolder) holder;
70 | productHolder.tvName.setText(data.name);
71 |
72 | productHolder.imgRight.setOnClickListener(new View.OnClickListener() {
73 | @Override
74 | public void onClick(View view) {
75 | Toast.makeText(mContext, "" + position, Toast.LENGTH_LONG).show();
76 | }
77 | });
78 |
79 | Glide.with(mContext).load(data.URl)
80 | .placeholder(R.mipmap.ic_launcher)
81 | .centerCrop()
82 | .skipMemoryCache(skipcache)
83 | .diskCacheStrategy(DiskCacheStrategy.NONE)
84 | .into(new GlideDrawableImageViewTarget(productHolder.imgRight) {
85 | @Override
86 | public void onResourceReady(GlideDrawable drawable, GlideAnimation anim) {
87 | super.onResourceReady(drawable, anim);
88 | Log.d("-------------------+", "" + (position+1));
89 | }
90 | });
91 |
92 |
93 | // Glide.with(mContext).load(data.URl)
94 | // .placeholder(R.mipmap.ic_launcher)
95 | // .centerCrop()
96 | // .skipMemoryCache(true)
97 | // .diskCacheStrategy(DiskCacheStrategy.NONE)
98 | // .into();
99 |
100 |
101 | break;
102 | case ActType.SHOW_TYPE_2:
103 |
104 |
105 | ProductHolder2 productHolder2 = (ProductHolder2) holder;
106 | productHolder2.tvName.setText(data.name);
107 |
108 | productHolder2.imgRight.setOnClickListener(new View.OnClickListener() {
109 | @Override
110 | public void onClick(View view) {
111 | Toast.makeText(mContext, "w:::" + position, Toast.LENGTH_LONG).show();
112 | }
113 | });
114 |
115 |
116 | Glide.with(mContext).load(data.URl)
117 | .placeholder(R.mipmap.ic_launcher)
118 | .diskCacheStrategy(DiskCacheStrategy.NONE)
119 | .skipMemoryCache(skipcache)
120 |
121 | .centerCrop()
122 |
123 | .into(new GlideDrawableImageViewTarget(productHolder2.imgRight) {
124 | @Override
125 | public void onResourceReady(GlideDrawable drawable, GlideAnimation anim) {
126 | super.onResourceReady(drawable, anim);
127 | Log.d("--------------------", "" + (position+1));
128 | //progressBar.setVisibility(View.GONE);
129 | }
130 | });
131 | break;
132 |
133 | }
134 |
135 |
136 | }
137 |
138 | class ProductHolder extends BaseRecyclerViewHolder {
139 | public TextView tvName;
140 | public ImageView imgRight;
141 |
142 | public ProductHolder(View itemView) {
143 | super(itemView);
144 | tvName = findView(R.id.tv_type_name);
145 | imgRight = findView(R.id.img_right);
146 |
147 | }
148 | }
149 |
150 | class ProductHolder2 extends BaseRecyclerViewHolder {
151 | public TextView tvName;
152 | public ImageView imgRight;
153 |
154 | public ProductHolder2(View itemView) {
155 | super(itemView);
156 | tvName = findView(R.id.tv_type_name);
157 | imgRight = findView(R.id.img_right);
158 |
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/ChangeScrollStateCallback.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview;
2 |
3 | /**
4 | * Created by wuduogen838 on 16/11/10.
5 | */
6 |
7 |
8 | public interface ChangeScrollStateCallback {
9 |
10 | public void change(int c);
11 |
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview;
2 |
3 | import android.os.Handler;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.os.Bundle;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.util.Log;
8 |
9 | import com.bumptech.glide.Glide;
10 | import com.example.liangmutian.airrecyclerview.swipetoloadlayout.ChangeScrollStateCallback;
11 | import com.example.liangmutian.airrecyclerview.swipetoloadlayout.OnLoadMoreListener;
12 | import com.example.liangmutian.airrecyclerview.swipetoloadlayout.OnRefreshListener;
13 | import com.example.liangmutian.airrecyclerview.swipetoloadlayout.SuperRefreshRecyclerView;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | public class MainActivity extends AppCompatActivity
19 | implements OnRefreshListener, OnLoadMoreListener {
20 |
21 | private SuperRefreshRecyclerView superRecyclerView;
22 | private Adapter adapter;
23 | private List list = new ArrayList<>();
24 |
25 | private String url1 = "http://img2.imgtn.bdimg.com/it/u=2313041955,732263015&fm=21&gp=0.jpg";
26 | private String url2 = "http://p4.yokacdn.com/pic/cr/2013/0115/2026031677.jpg";
27 | private String url3 = "http://img5.imgtn.bdimg.com/it/u=3931738195,194607292&fm=21&gp=0.jpg";
28 | private String url4 = "http://img0.imgtn.bdimg.com/it/u=1174544731,79277711&fm=21&gp=0.jpg";
29 |
30 | private String url11 = "http://a.hiphotos.baidu.com/zhidao/pic/item/4afbfbedab64034ff00f9069a9c379310b551d9a.jpg";
31 | private String url12 = "http://www.286868.org.cn/imgall/mnsg453fmixgenlnfzrw63i/web/cmsphp/article/201505/8d19ff6db94a466c861f4adf760e3d4e.jpg";
32 | private String url13 = "http://imgsrc.baidu.com/forum/w%3D580/sign=8f6610cf5e6034a829e2b889fb1249d9/9e0049afa40f4bfbedae079a014f78f0f6361887.jpg";
33 | private String url14 = "http://www.1919111.net/imgall/on2gc5djmmxhoz3qmv2c4y3pnu/editor/attached/image/20141124/20141124225933_71813.jpg";
34 | private String url15 = "http://img4.duitang.com/uploads/item/201407/16/20140716112423_BBvCR.thumb.700_0.jpeg";
35 | private String url16 = "http://www.22777788.cc/imgall/nfwwomzomrxxkytbnyxgg33n/view/commodity_story/imedium/public/p7634330.jpg";
36 | private String url17 = "http://cdn.duitang.com/uploads/item/201501/07/20150107194411_VQEAy.thumb.700_0.jpeg";
37 | private String url18 = "http://static.wgpet.com/editor/attached/image/20141124/20141124230747_89589.jpeg";
38 | private String url19 = "http://img4.duitang.com/uploads/item/201601/28/20160128211836_ivVs2.thumb.700_0.jpeg";
39 | private String url110 = "http://cdnq.duitang.com/uploads/item/201412/11/20141211192322_EytUS.jpeg";
40 | private String url111 = "";
41 | private String url112= "";
42 | private String url113 = "";
43 | private String url114= "";
44 |
45 |
46 | @Override
47 | protected void onCreate(Bundle savedInstanceState) {
48 | super.onCreate(savedInstanceState);
49 | setContentView(R.layout.activity_main);
50 |
51 |
52 | superRecyclerView = (SuperRefreshRecyclerView) findViewById(R.id.super_recyclerview);
53 | superRecyclerView.init(new LinearLayoutManager(this), this, this);
54 | superRecyclerView.setRefreshEnabled(true);
55 | superRecyclerView.setLoadingMoreEnable(true);
56 | // superRecyclerView.addOnAttachStateChangeListener();
57 |
58 | superRecyclerView.setChangeScrollStateCallback(new ChangeScrollStateCallback() {
59 |
60 | // 0 表示停止滑动的状态 SCROLL_STATE_IDLE
61 | //
62 | // 1表示正在滚动,用户手指在屏幕上 SCROLL_STATE_TOUCH_SCROLL
63 | //
64 | // 2表示正在滑动。用户手指已经离开屏幕 SCROLL_STATE_FLING
65 | @Override
66 | public void change(int c) {
67 |
68 | switch (c) {
69 | case 2:
70 | Glide.with(MainActivity.this).pauseRequests();
71 | Log.d("AAAAAAAAAAAAAAA", "暂停加载" + c);
72 |
73 | break;
74 | case 0:
75 | Glide.with(MainActivity.this).resumeRequests();
76 | Log.d("AAAAAAAAAAAAAAA","恢复加载" + c);
77 |
78 | break;
79 | case 1:
80 | Glide.with(MainActivity.this).resumeRequests();
81 | Log.d("AAAAAAAAAAAAAAA", "恢复加载" + c);
82 |
83 | break;
84 |
85 |
86 | }
87 |
88 | }
89 | });
90 |
91 |
92 | for (int i = 0; i < 5; i++) {
93 | ActType info1 = new ActType("01", 1, url11);
94 | ActType info2 = new ActType("02", 1, url12);
95 | ActType info3 = new ActType("03", 1, url13);
96 | ActType info4 = new ActType("04", 1, url14);
97 | ActType info5 = new ActType("05", 1, url15);
98 | ActType info6 = new ActType("06", 1, url16);
99 | ActType info7 = new ActType("07", 1, url17);
100 |
101 |
102 | list.add(info1);
103 | list.add(info2);
104 | list.add(info3);
105 | list.add(info4);
106 | list.add(info5);
107 | list.add(info6);
108 | list.add(info7);
109 |
110 | }
111 | adapter = new Adapter(list, this);
112 | superRecyclerView.setAdapter(adapter);
113 | superRecyclerView.showData();
114 | // adapter.setOnItemClickListener(itemClickListener);
115 |
116 |
117 | }
118 |
119 | private void setData() {
120 | list.clear();
121 | for (int i = 0; i < 3; i++) {
122 | ActType info5 = new ActType("01", 2, url11);
123 | ActType info3 = new ActType("04", 1, url4);
124 | ActType info2 = new ActType("02", 2, url2);
125 | list.add(info5);
126 | list.add(info3);
127 | list.add(info2);
128 | }
129 |
130 | }
131 |
132 | @Override
133 | public void onLoadMore() {
134 |
135 |
136 | ActType info2 = new ActType("04", 1, url4);
137 | ActType info3 = new ActType("02", 1, url2);
138 | ActType info4 = new ActType("01", 2, url11);
139 |
140 |
141 | list.add(info2);
142 | list.add(info3);
143 |
144 | list.add(info4);
145 |
146 |
147 | adapter.notifyDataSetChanged();
148 |
149 | superRecyclerView.setLoadingMore(false);
150 |
151 | }
152 |
153 | @Override
154 | public void onRefresh() {
155 |
156 | new Handler().postDelayed(new Runnable() {
157 |
158 | public void run() {
159 |
160 | setData();
161 | superRecyclerView.setRefreshing(false);
162 |
163 | }
164 |
165 | }, 3000);
166 |
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/BaseRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import java.util.List;
9 |
10 |
11 | public abstract class BaseRecyclerAdapter extends RecyclerView.Adapter {
12 |
13 | private List mDataList ;
14 |
15 | private OnItemClickListener mListener ;
16 | private OnItemLongClickListener mLongListener ;
17 |
18 | public BaseRecyclerAdapter(List mDataList) {
19 | this.mDataList = mDataList;
20 | }
21 | public List getDataList(){
22 | return mDataList ;
23 | }
24 | @Override
25 | public T onCreateViewHolder(ViewGroup parent, int viewType) {
26 | T holder ;
27 | holder = createViewHolder(LayoutInflater.from(parent.getContext()),parent, viewType) ;
28 | if (holder == null){
29 | holder = createViewHolder(LayoutInflater.from(parent.getContext()), viewType) ;
30 | }
31 |
32 | return holder;
33 | }
34 |
35 |
36 | @Override
37 | public void onBindViewHolder(final BaseRecyclerViewHolder holder, final int position) {
38 |
39 | holder.itemView.setOnClickListener(new View.OnClickListener() {
40 | @Override
41 | public void onClick(View v) {
42 | if (mListener != null){
43 | mListener.onItemClick(v,holder.getPosition(),getItemId(holder.getPosition()));
44 | }
45 | }
46 | });
47 | holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
48 | @Override
49 | public boolean onLongClick(View v) {
50 | if (mLongListener != null){
51 | return mLongListener.onItemLongClick(v,holder.getPosition(),getItemId(holder.getPosition()));
52 | }
53 | return false;
54 | }
55 | });
56 | onBindViewHolder((T) holder, position, mDataList.get(position)) ;
57 | }
58 |
59 | public void setOnItemClickListener(OnItemClickListener listener){
60 | mListener = listener ;
61 | }
62 | public void setOnItemLongClickListener(OnItemLongClickListener listener){
63 | mLongListener = listener ;
64 | }
65 |
66 | @Override
67 | public int getItemCount() {
68 | return mDataList.size();
69 | }
70 |
71 | static public class BaseRecyclerViewHolder extends RecyclerView.ViewHolder{
72 | public BaseRecyclerViewHolder(View itemView) {
73 | super(itemView);
74 | }
75 | public K findView(int id){
76 | return (K) itemView.findViewById(id);
77 | }
78 | }
79 |
80 | @Deprecated
81 | public T createViewHolder(LayoutInflater inflater,int viewType){
82 | return null ;
83 | }
84 |
85 | public T createViewHolder(LayoutInflater inflater,ViewGroup parent, int viewType){
86 | return null ;
87 | };
88 |
89 | public abstract void onBindViewHolder(T holder, int position,D data);
90 |
91 | public interface OnItemClickListener{
92 | void onItemClick(View view, int position, long id) ;
93 |
94 | }
95 | public interface OnItemLongClickListener{
96 | boolean onItemLongClick(View view, int position, long id) ;
97 |
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/OnLoadMoreListener.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | /**
4 | * Created by Aspsine on 2015/8/13.
5 | */
6 | public interface OnLoadMoreListener {
7 | public void onLoadMore();
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/OnRefreshListener.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | /**
4 | * Created by Aspsine on 2015/8/13.
5 | */
6 | public interface OnRefreshListener {
7 | public void onRefresh();
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/RefreshHeaderView.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.AnimationDrawable;
5 | import android.util.AttributeSet;
6 | import android.util.Log;
7 | import android.view.LayoutInflater;
8 | import android.widget.FrameLayout;
9 | import android.widget.ImageView;
10 | import android.widget.TextView;
11 |
12 | import com.example.liangmutian.airrecyclerview.R;
13 |
14 |
15 | /**
16 | * Created by ex-liyongqiang001 on 16/7/28.
17 | */
18 | public class RefreshHeaderView extends FrameLayout implements SwipeRefreshTrigger,SwipeTrigger {
19 |
20 | private Context mcontext;
21 | private TextView tvTip;
22 | private ImageView iconRefresh;
23 | private AnimationDrawable animationDrawable;
24 |
25 | public RefreshHeaderView(Context context) {
26 | super(context);
27 | init(context);
28 | }
29 |
30 | public RefreshHeaderView(Context context, AttributeSet attrs) {
31 | super(context, attrs);
32 | init(context);
33 | }
34 |
35 | public RefreshHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
36 | super(context, attrs, defStyleAttr);
37 | init(context);
38 | }
39 |
40 | private void init(Context context){
41 | LayoutInflater.from(context).inflate(R.layout.layout_refresh_header,this);
42 | tvTip=(TextView)findViewById(R.id.tv_tip);
43 | iconRefresh=(ImageView)findViewById(R.id.icon_refresh);
44 | }
45 |
46 | @Override
47 | public void onRefresh() {
48 | //下拉到一定位置松开之后,调用此方法
49 | tvTip.setText("正在刷新...");
50 | iconRefresh.setRotationX(0);
51 | iconRefresh.setImageResource(R.drawable.anim_refresh);
52 | animationDrawable = (AnimationDrawable) iconRefresh.getDrawable();
53 | animationDrawable.start();
54 | Log.i("info", "onRefresh");
55 | }
56 |
57 | @Override
58 | public void onPrepare() {
59 | //下拉之前调用此方法
60 | tvTip.setText("下拉刷新");
61 | Log.i("info", "onPrepare");
62 | }
63 |
64 | @Override
65 | public void onMove(int yScrolled, boolean isComplete, boolean automatic) {
66 | if (!isComplete) {
67 | //当前Y轴偏移量大于控件高度时,标识下拉到界限,显示“松开已刷新”
68 | if (yScrolled >= getHeight()) {
69 | iconRefresh.setRotationX(180);
70 | tvTip.setText("释放立即刷新");
71 | tvTip.postInvalidate();
72 | } else {
73 | //未达到偏移量
74 | tvTip.setText("下拉刷新");
75 | iconRefresh.setRotationX(0);
76 |
77 | }
78 | }
79 | //Log.i("info","onMove");
80 | }
81 |
82 | @Override
83 | public void onRelease() {
84 | //达到一定滑动距离,松开刷新时调用
85 | //setText("释放立即刷新");
86 | Log.i("info","onRelease");
87 | }
88 |
89 | @Override
90 | public void onComplete() {
91 | //加载完成之后调用此方法
92 | tvTip.setText("刷新完成");
93 | animationDrawable.stop();
94 | //iconRefresh.setImageResource(R.mipmap.icon_refresh);
95 | Log.i("info","onComplete");
96 | }
97 |
98 | @Override
99 | public void onReset() {
100 | //重置
101 | tvTip.setText("下拉刷新");
102 | iconRefresh.setImageResource(R.mipmap.icon_refresh);
103 | Log.i("info","onReset");
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/SuperRefreshRecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.AttributeSet;
7 | import android.util.Log;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.widget.FrameLayout;
11 | import android.widget.RelativeLayout;
12 |
13 | import com.example.liangmutian.airrecyclerview.R;
14 |
15 |
16 | /**
17 | * Created by ex-liyongqiang001 on 16/6/30.
18 | */
19 | public class SuperRefreshRecyclerView extends FrameLayout {
20 |
21 | private RelativeLayout emptyView,errorView;
22 | private SwipeToLoadLayout swipeToLoadLayout;
23 | private SwipeLoadMoreFooterLayout swipeLoadMoreFooterLayout;
24 | private RecyclerView recyclerView;
25 | private boolean move;
26 | private int mIndex;
27 | private RecyclerView.LayoutManager layoutManager;
28 |
29 | private Context mContext;
30 |
31 |
32 | ChangeScrollStateCallback mChangeScrollStateCallback;
33 |
34 | public SuperRefreshRecyclerView(Context context) {
35 | super(context);
36 | initView(context);
37 | }
38 |
39 | public SuperRefreshRecyclerView(Context context, AttributeSet attrs) {
40 | super(context, attrs);
41 | initView(context);
42 | }
43 |
44 | public SuperRefreshRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
45 | super(context, attrs, defStyleAttr);
46 | initView(context);
47 | }
48 |
49 | private void initView(Context context){
50 | mContext=context;
51 | LayoutInflater.from(mContext).inflate(R.layout.layout_super_refresh_recycler,this);
52 | emptyView=(RelativeLayout)findViewById(R.id.layout_empty);
53 | errorView=(RelativeLayout)findViewById(R.id.layout_error);
54 | swipeToLoadLayout=(SwipeToLoadLayout)findViewById(R.id.swipe_to_load);
55 | swipeLoadMoreFooterLayout=(SwipeLoadMoreFooterLayout)findViewById(R.id.swipe_load_more_footer);
56 | recyclerView=(RecyclerView)findViewById(R.id.swipe_target);
57 | }
58 |
59 |
60 | public void init(RecyclerView.LayoutManager layoutManager,OnRefreshListener onRefreshListener,OnLoadMoreListener onLoadMoreListener){
61 | recyclerView.setLayoutManager(layoutManager);
62 | this.layoutManager=layoutManager;
63 | swipeToLoadLayout.setOnRefreshListener(onRefreshListener);
64 | swipeToLoadLayout.setOnLoadMoreListener(onLoadMoreListener);
65 | recyclerView.setOnScrollListener(new RecyclerViewListener());
66 | }
67 |
68 | public void showEmpty(OnClickListener onEmptyClick){
69 | swipeToLoadLayout.setVisibility(GONE);
70 | emptyView.setVisibility(VISIBLE);
71 | errorView.setVisibility(GONE);
72 | if(onEmptyClick!=null){
73 | emptyView.setOnClickListener(onEmptyClick);
74 | }
75 | }
76 |
77 | public void showError(OnClickListener onErrorClick){
78 | swipeToLoadLayout.setVisibility(GONE);
79 | emptyView.setVisibility(GONE);
80 | errorView.setVisibility(VISIBLE);
81 | if(onErrorClick!=null){
82 | errorView.setOnClickListener(onErrorClick);
83 | }
84 | }
85 |
86 | public void showData(){
87 | swipeToLoadLayout.setVisibility(VISIBLE);
88 | emptyView.setVisibility(GONE);
89 | errorView.setVisibility(GONE);
90 | }
91 |
92 | public void setEmptyView(View view){
93 | emptyView.removeAllViews();
94 | emptyView.addView(view);
95 | }
96 |
97 | public boolean isRefreshing(){
98 | return swipeToLoadLayout.isRefreshing();
99 | }
100 |
101 | public void setRefreshing(boolean refreshing){
102 | swipeToLoadLayout.setRefreshing(refreshing);
103 | }
104 |
105 | public boolean isLoadingMore(){
106 | return swipeToLoadLayout.isLoadingMore();
107 | }
108 |
109 | public void setLoadingMore(boolean loadMore){
110 | swipeToLoadLayout.setLoadingMore(loadMore);
111 | }
112 |
113 | public void setLoadingMoreEnable(boolean enable){
114 | swipeToLoadLayout.setLoadMoreEnabled(enable);
115 | }
116 |
117 | public void setRefreshEnabled(boolean enable){
118 | swipeToLoadLayout.setRefreshEnabled(enable);
119 | }
120 |
121 | public void setAdapter(RecyclerView.Adapter adapter){
122 | recyclerView.setAdapter(adapter);
123 | }
124 |
125 | public void addItemDecoration(RecyclerView.ItemDecoration itemDecoration){
126 | recyclerView.addItemDecoration(itemDecoration);
127 | }
128 |
129 | public void moveToPosition(int n) {
130 | mIndex=n;
131 | LinearLayoutManager mLinearLayoutManager=(LinearLayoutManager)layoutManager;
132 | int firstItem = mLinearLayoutManager.findFirstVisibleItemPosition();
133 | int lastItem = mLinearLayoutManager.findLastVisibleItemPosition();
134 | //然后区分情况
135 | if (n <= firstItem ){
136 | //当要置顶的项在当前显示的第一个项的前面时
137 | recyclerView.scrollToPosition(n);
138 | }else if ( n <= lastItem ){
139 | //当要置顶的项已经在屏幕上显示时
140 | int top = recyclerView.getChildAt(n - firstItem).getTop();
141 | recyclerView.scrollBy(0, top);
142 | }else{
143 | //当要置顶的项在当前显示的最后一项的后面时
144 | recyclerView.scrollToPosition(n);
145 | //这里这个变量是用在RecyclerView滚动监听里面的
146 | move = true;
147 | }
148 |
149 | }
150 |
151 | class RecyclerViewListener extends RecyclerView.OnScrollListener{
152 |
153 | @Override
154 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
155 | super.onScrollStateChanged(recyclerView, newState);
156 |
157 | mChangeScrollStateCallback.change(newState);
158 |
159 | //Log.d("AAAAAAAAAAAAAAA", "" + newState);
160 |
161 |
162 | }
163 |
164 | @Override
165 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
166 | super.onScrolled(recyclerView, dx, dy);
167 | //在这里进行第二次滚动(最后的100米!)
168 | if (move ){
169 | move = false;
170 | //获取要置顶的项在当前屏幕的位置,mIndex是记录的要置顶项在RecyclerView中的位置
171 | LinearLayoutManager mLinearLayoutManager=(LinearLayoutManager)layoutManager;
172 | int n = mIndex - mLinearLayoutManager.findFirstVisibleItemPosition();
173 | if ( 0 <= n && n < recyclerView.getChildCount()){
174 | //获取要置顶的项顶部离RecyclerView顶部的距离
175 | int top = recyclerView.getChildAt(n).getTop();
176 | //最后的移动
177 | recyclerView.scrollBy(0, top);
178 | }
179 | }
180 | }
181 | }
182 |
183 | public void setChangeScrollStateCallback(ChangeScrollStateCallback mChangeScrollStateCallback){
184 | this.mChangeScrollStateCallback=mChangeScrollStateCallback;
185 |
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/SwipeLoadMoreFooterLayout.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.util.Log;
6 | import android.view.LayoutInflater;
7 | import android.widget.FrameLayout;
8 |
9 | import com.example.liangmutian.airrecyclerview.R;
10 |
11 |
12 | /**
13 | * Created by Aspsine on 2015/8/13.
14 | */
15 | public class SwipeLoadMoreFooterLayout extends FrameLayout implements SwipeLoadMoreTrigger, SwipeTrigger {
16 |
17 | private Context mContext;
18 |
19 | public SwipeLoadMoreFooterLayout(Context context) {
20 | this(context, null);
21 | init(context);
22 | }
23 |
24 | public SwipeLoadMoreFooterLayout(Context context, AttributeSet attrs) {
25 | this(context, attrs, 0);
26 | init(context);
27 | }
28 |
29 | public SwipeLoadMoreFooterLayout(Context context, AttributeSet attrs, int defStyleAttr) {
30 | super(context, attrs, defStyleAttr);
31 | init(context);
32 | }
33 |
34 | private void init(Context context){
35 | mContext=context;
36 | LayoutInflater.from(mContext).inflate(R.layout.layout_footer_loading, this);
37 | }
38 |
39 | @Override
40 | public void onLoadMore() {
41 | //setVisibility(VISIBLE);
42 | Log.i("info", "onLoadMore");
43 | }
44 |
45 | @Override
46 | public void onPrepare() {
47 | Log.i("info","onPrepare");
48 | }
49 |
50 | @Override
51 | public void onMove(int y, boolean isComplete, boolean automatic) {
52 | //Log.i("info","onMove");
53 | }
54 |
55 | @Override
56 | public void onRelease() {
57 | Log.i("info","onRelease");
58 | }
59 |
60 | @Override
61 | public void onComplete() {
62 | //setVisibility(GONE);
63 | Log.i("info","onComplete");
64 | }
65 |
66 | @Override
67 | public void onReset() {
68 | Log.i("info","onReset");
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/SwipeLoadMoreTrigger.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | /**
4 | * Created by Aspsine on 2015/8/17.
5 | */
6 | public interface SwipeLoadMoreTrigger {
7 | void onLoadMore();
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/SwipeRefreshHeaderLayout.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.FrameLayout;
6 |
7 | /**
8 | * Created by Aspsine on 2015/8/13.
9 | */
10 | public class SwipeRefreshHeaderLayout extends FrameLayout implements SwipeRefreshTrigger, SwipeTrigger {
11 |
12 | public SwipeRefreshHeaderLayout(Context context) {
13 | this(context, null);
14 | }
15 |
16 | public SwipeRefreshHeaderLayout(Context context, AttributeSet attrs) {
17 | this(context, attrs, 0);
18 | }
19 |
20 | public SwipeRefreshHeaderLayout(Context context, AttributeSet attrs, int defStyleAttr) {
21 | super(context, attrs, defStyleAttr);
22 | }
23 |
24 | @Override
25 | public void onRefresh() {
26 | }
27 |
28 | @Override
29 | public void onPrepare() {
30 | }
31 |
32 | @Override
33 | public void onMove(int y, boolean isComplete, boolean automatic) {
34 | }
35 |
36 | @Override
37 | public void onRelease() {
38 |
39 | }
40 |
41 | @Override
42 | public void onComplete() {
43 |
44 | }
45 |
46 | @Override
47 | public void onReset() {
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/SwipeRefreshTrigger.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | /**
4 | * Created by Aspsine on 2015/8/13.
5 | */
6 | public interface SwipeRefreshTrigger {
7 |
8 | void onRefresh();
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/SwipeToLoadLayout.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.v4.view.MotionEventCompat;
6 | import android.support.v4.view.ViewCompat;
7 | import android.util.AttributeSet;
8 | import android.util.Log;
9 | import android.view.MotionEvent;
10 | import android.view.View;
11 | import android.view.ViewConfiguration;
12 | import android.view.ViewGroup;
13 | import android.widget.AbsListView;
14 | import android.widget.Scroller;
15 |
16 | import com.example.liangmutian.airrecyclerview.R;
17 |
18 |
19 | /**
20 | * Created by Aspsine on 2015/8/13.
21 | */
22 | public class SwipeToLoadLayout extends ViewGroup {
23 |
24 | private static final String TAG = SwipeToLoadLayout.class.getSimpleName();
25 |
26 | private static final int DEFAULT_SWIPING_TO_REFRESH_TO_DEFAULT_SCROLLING_DURATION = 200;
27 |
28 | private static final int DEFAULT_RELEASE_TO_REFRESHING_SCROLLING_DURATION = 200;
29 |
30 | private static final int DEFAULT_REFRESH_COMPLETE_DELAY_DURATION = 300;
31 |
32 | private static final int DEFAULT_REFRESH_COMPLETE_TO_DEFAULT_SCROLLING_DURATION = 500;
33 |
34 | private static final int DEFAULT_DEFAULT_TO_REFRESHING_SCROLLING_DURATION = 500;
35 |
36 | private static final int DEFAULT_SWIPING_TO_LOAD_MORE_TO_DEFAULT_SCROLLING_DURATION = 200;
37 |
38 | private static final int DEFAULT_RELEASE_TO_LOADING_MORE_SCROLLING_DURATION = 200;
39 |
40 | private static final int DEFAULT_LOAD_MORE_COMPLETE_DELAY_DURATION = 300;
41 |
42 | private static final int DEFAULT_LOAD_MORE_COMPLETE_TO_DEFAULT_SCROLLING_DURATION = 300;
43 |
44 | private static final int DEFAULT_DEFAULT_TO_LOADING_MORE_SCROLLING_DURATION = 300;
45 |
46 | /**
47 | * how hard to drag
48 | */
49 | private static final float DEFAULT_DRAG_RATIO = 0.5f;
50 |
51 | private static final int INVALID_POINTER = -1;
52 |
53 | private static final int INVALID_COORDINATE = -1;
54 |
55 | private AutoScroller mAutoScroller;
56 |
57 | private OnRefreshListener mRefreshListener;
58 |
59 | private OnLoadMoreListener mLoadMoreListener;
60 |
61 | private View mHeaderView;
62 |
63 | private View mTargetView;
64 |
65 | private View mFooterView;
66 |
67 | private int mHeaderHeight;
68 |
69 | private int mFooterHeight;
70 |
71 | private boolean mHasHeaderView;
72 |
73 | private boolean mHasFooterView;
74 |
75 | /**
76 | * indicate whether in debug mode
77 | */
78 | private boolean mDebug;
79 |
80 | private float mDragRatio = DEFAULT_DRAG_RATIO;
81 |
82 | private boolean mAutoLoading;
83 |
84 | /**
85 | * the threshold of the touch event
86 | */
87 | private final int mTouchSlop;
88 |
89 | /**
90 | * status of SwipeToLoadLayout
91 | */
92 | private int mStatus = STATUS.STATUS_DEFAULT;
93 |
94 | /**
95 | * target view top offset
96 | */
97 | private int mHeaderOffset;
98 |
99 | /**
100 | * target offset
101 | */
102 | private int mTargetOffset;
103 |
104 | /**
105 | * target view bottom offset
106 | */
107 | private int mFooterOffset;
108 |
109 | /**
110 | * init touch action down point.y
111 | */
112 | private float mInitDownY;
113 |
114 | /**
115 | * init touch action down point.x
116 | */
117 | private float mInitDownX;
118 |
119 | /**
120 | * last touch point.y
121 | */
122 | private float mLastY;
123 |
124 | /**
125 | * last touch point.x
126 | */
127 | private float mLastX;
128 |
129 | /**
130 | * action touch pointer's id
131 | */
132 | private int mActivePointerId;
133 |
134 | /**
135 | * ATTRIBUTE:
136 | * a switcher indicate whither refresh function is enabled
137 | */
138 | private boolean mRefreshEnabled = true;
139 |
140 | /**
141 | * ATTRIBUTE:
142 | * a switcher indicate whiter load more function is enabled
143 | */
144 | private boolean mLoadMoreEnabled = true;
145 |
146 | /**
147 | * ATTRIBUTE:
148 | * the style default classic
149 | */
150 | private int mStyle = STYLE.CLASSIC;
151 |
152 | /**
153 | * ATTRIBUTE:
154 | * offset to trigger refresh
155 | */
156 | private float mRefreshTriggerOffset;
157 |
158 | /**
159 | * ATTRIBUTE:
160 | * offset to trigger load more
161 | */
162 | private float mLoadMoreTriggerOffset;
163 |
164 | /**
165 | * ATTRIBUTE:
166 | * the max value of top offset
167 | */
168 | private float mRefreshFinalDragOffset;
169 |
170 | /**
171 | * ATTRIBUTE:
172 | * the max value of bottom offset
173 | */
174 | private float mLoadMoreFinalDragOffset;
175 |
176 | /**
177 | * ATTRIBUTE:
178 | * Scrolling duration swiping to refresh -> default
179 | */
180 | private int mSwipingToRefreshToDefaultScrollingDuration = DEFAULT_SWIPING_TO_REFRESH_TO_DEFAULT_SCROLLING_DURATION;
181 |
182 | /**
183 | * ATTRIBUTE:
184 | * Scrolling duration status release to refresh -> refreshing
185 | */
186 | private int mReleaseToRefreshToRefreshingScrollingDuration = DEFAULT_RELEASE_TO_REFRESHING_SCROLLING_DURATION;
187 |
188 | /**
189 | * ATTRIBUTE:
190 | * Refresh complete delay duration
191 | */
192 | private int mRefreshCompleteDelayDuration = DEFAULT_REFRESH_COMPLETE_DELAY_DURATION;
193 |
194 | /**
195 | * ATTRIBUTE:
196 | * Scrolling duration status refresh complete -> default
197 | * {@link #setRefreshing(boolean)} false
198 | */
199 | private int mRefreshCompleteToDefaultScrollingDuration = DEFAULT_REFRESH_COMPLETE_TO_DEFAULT_SCROLLING_DURATION;
200 |
201 | /**
202 | * ATTRIBUTE:
203 | * Scrolling duration status default -> refreshing, mainly for auto refresh
204 | * {@link #setRefreshing(boolean)} true
205 | */
206 | private int mDefaultToRefreshingScrollingDuration = DEFAULT_DEFAULT_TO_REFRESHING_SCROLLING_DURATION;
207 |
208 | /**
209 | * ATTRIBUTE:
210 | * Scrolling duration status release to loading more -> loading more
211 | */
212 | private int mReleaseToLoadMoreToLoadingMoreScrollingDuration = DEFAULT_RELEASE_TO_LOADING_MORE_SCROLLING_DURATION;
213 |
214 |
215 | /**
216 | * ATTRIBUTE:
217 | * Load more complete delay duration
218 | */
219 | private int mLoadMoreCompleteDelayDuration = DEFAULT_LOAD_MORE_COMPLETE_DELAY_DURATION;
220 |
221 | /**
222 | * ATTRIBUTE:
223 | * Scrolling duration status load more complete -> default
224 | * {@link #setLoadingMore(boolean)} false
225 | */
226 | private int mLoadMoreCompleteToDefaultScrollingDuration = DEFAULT_LOAD_MORE_COMPLETE_TO_DEFAULT_SCROLLING_DURATION;
227 |
228 | /**
229 | * ATTRIBUTE:
230 | * Scrolling duration swiping to load more -> default
231 | */
232 | private int mSwipingToLoadMoreToDefaultScrollingDuration = DEFAULT_SWIPING_TO_LOAD_MORE_TO_DEFAULT_SCROLLING_DURATION;
233 |
234 | /**
235 | * ATTRIBUTE:
236 | * Scrolling duration status default -> loading more, mainly for auto load more
237 | * {@link #setLoadingMore(boolean)} true
238 | */
239 | private int mDefaultToLoadingMoreScrollingDuration = DEFAULT_DEFAULT_TO_LOADING_MORE_SCROLLING_DURATION;
240 |
241 | /**
242 | * the style enum
243 | */
244 | public static final class STYLE {
245 | public static final int CLASSIC = 0;
246 | public static final int ABOVE = 1;
247 | public static final int BLEW = 2;
248 | public static final int SCALE = 3;
249 | }
250 |
251 | public SwipeToLoadLayout(Context context) {
252 | this(context, null);
253 | }
254 |
255 | public SwipeToLoadLayout(Context context, AttributeSet attrs) {
256 | this(context, attrs, 0);
257 | }
258 |
259 | public SwipeToLoadLayout(Context context, AttributeSet attrs, int defStyleAttr) {
260 | super(context, attrs, defStyleAttr);
261 | final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeToLoadLayout, defStyleAttr, 0);
262 | try {
263 | final int N = a.getIndexCount();
264 | for (int i = 0; i < N; i++) {
265 | int attr = a.getIndex(i);
266 | if (attr == R.styleable.SwipeToLoadLayout_refresh_enabled) {
267 | setRefreshEnabled(a.getBoolean(attr, true));
268 |
269 | } else if (attr == R.styleable.SwipeToLoadLayout_load_more_enabled) {
270 | setLoadMoreEnabled(a.getBoolean(attr, true));
271 |
272 | } else if (attr == R.styleable.SwipeToLoadLayout_swipe_style) {
273 | setSwipeStyle(a.getInt(attr, STYLE.CLASSIC));
274 |
275 | } else if (attr == R.styleable.SwipeToLoadLayout_drag_ratio) {
276 | setDragRatio(a.getFloat(attr, DEFAULT_DRAG_RATIO));
277 |
278 | } else if (attr == R.styleable.SwipeToLoadLayout_refresh_final_drag_offset) {
279 | setRefreshFinalDragOffset(a.getDimensionPixelOffset(attr, 0));
280 |
281 | } else if (attr == R.styleable.SwipeToLoadLayout_load_more_final_drag_offset) {
282 | setLoadMoreFinalDragOffset(a.getDimensionPixelOffset(attr, 0));
283 |
284 | } else if (attr == R.styleable.SwipeToLoadLayout_refresh_trigger_offset) {
285 | setRefreshTriggerOffset(a.getDimensionPixelOffset(attr, 0));
286 |
287 | } else if (attr == R.styleable.SwipeToLoadLayout_load_more_trigger_offset) {
288 | setLoadMoreTriggerOffset(a.getDimensionPixelOffset(attr, 0));
289 |
290 | } else if (attr == R.styleable.SwipeToLoadLayout_swiping_to_refresh_to_default_scrolling_duration) {
291 | setSwipingToRefreshToDefaultScrollingDuration(a.getInt(attr, DEFAULT_SWIPING_TO_REFRESH_TO_DEFAULT_SCROLLING_DURATION));
292 |
293 | } else if (attr == R.styleable.SwipeToLoadLayout_release_to_refreshing_scrolling_duration) {
294 | setReleaseToRefreshingScrollingDuration(a.getInt(attr, DEFAULT_RELEASE_TO_REFRESHING_SCROLLING_DURATION));
295 |
296 | } else if (attr == R.styleable.SwipeToLoadLayout_refresh_complete_delay_duration) {
297 | setRefreshCompleteDelayDuration(a.getInt(attr, DEFAULT_REFRESH_COMPLETE_DELAY_DURATION));
298 |
299 | } else if (attr == R.styleable.SwipeToLoadLayout_refresh_complete_to_default_scrolling_duration) {
300 | setRefreshCompleteToDefaultScrollingDuration(a.getInt(attr, DEFAULT_REFRESH_COMPLETE_TO_DEFAULT_SCROLLING_DURATION));
301 |
302 | } else if (attr == R.styleable.SwipeToLoadLayout_default_to_refreshing_scrolling_duration) {
303 | setDefaultToRefreshingScrollingDuration(a.getInt(attr, DEFAULT_DEFAULT_TO_REFRESHING_SCROLLING_DURATION));
304 |
305 | } else if (attr == R.styleable.SwipeToLoadLayout_swiping_to_load_more_to_default_scrolling_duration) {
306 | setSwipingToLoadMoreToDefaultScrollingDuration(a.getInt(attr, DEFAULT_SWIPING_TO_LOAD_MORE_TO_DEFAULT_SCROLLING_DURATION));
307 |
308 | } else if (attr == R.styleable.SwipeToLoadLayout_release_to_loading_more_scrolling_duration) {
309 | setReleaseToLoadingMoreScrollingDuration(a.getInt(attr, DEFAULT_RELEASE_TO_LOADING_MORE_SCROLLING_DURATION));
310 |
311 | } else if (attr == R.styleable.SwipeToLoadLayout_load_more_complete_delay_duration) {
312 | setLoadMoreCompleteDelayDuration(a.getInt(attr, DEFAULT_LOAD_MORE_COMPLETE_DELAY_DURATION));
313 |
314 | } else if (attr == R.styleable.SwipeToLoadLayout_load_more_complete_to_default_scrolling_duration) {
315 | setLoadMoreCompleteToDefaultScrollingDuration(a.getInt(attr, DEFAULT_LOAD_MORE_COMPLETE_TO_DEFAULT_SCROLLING_DURATION));
316 |
317 | } else if (attr == R.styleable.SwipeToLoadLayout_default_to_loading_more_scrolling_duration) {
318 | setDefaultToLoadingMoreScrollingDuration(a.getInt(attr, DEFAULT_DEFAULT_TO_LOADING_MORE_SCROLLING_DURATION));
319 |
320 | }
321 | }
322 | } finally {
323 | a.recycle();
324 | }
325 |
326 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
327 | mAutoScroller = new AutoScroller();
328 | }
329 |
330 | @Override
331 | protected void onFinishInflate() {
332 | super.onFinishInflate();
333 | final int childNum = getChildCount();
334 | if (childNum == 0) {
335 | // no child return
336 | return;
337 | } else if (0 < childNum && childNum < 4) {
338 | mHeaderView = findViewById(R.id.swipe_refresh_header);
339 | mTargetView = findViewById(R.id.swipe_target);
340 | mFooterView = findViewById(R.id.swipe_load_more_footer);
341 | } else {
342 | // more than three children: unsupported!
343 | throw new IllegalStateException("Children num must equal or less than 3");
344 | }
345 | if (mTargetView == null) {
346 | return;
347 | }
348 | if (mHeaderView != null && mHeaderView instanceof SwipeTrigger) {
349 | mHeaderView.setVisibility(GONE);
350 | }
351 | if (mFooterView != null && mFooterView instanceof SwipeTrigger) {
352 | mFooterView.setVisibility(GONE);
353 | }
354 | }
355 |
356 | @Override
357 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
358 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
359 | // header
360 | if (mHeaderView != null) {
361 | final View headerView = mHeaderView;
362 | measureChildWithMargins(headerView, widthMeasureSpec, 0, heightMeasureSpec, 0);
363 | MarginLayoutParams lp = ((MarginLayoutParams) headerView.getLayoutParams());
364 | mHeaderHeight = headerView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
365 | if (mRefreshTriggerOffset < mHeaderHeight) {
366 | mRefreshTriggerOffset = mHeaderHeight;
367 | }
368 | }
369 | // target
370 | if (mTargetView != null) {
371 | final View targetView = mTargetView;
372 | measureChildWithMargins(targetView, widthMeasureSpec, 0, heightMeasureSpec, 0);
373 | }
374 | // footer
375 | if (mFooterView != null) {
376 | final View footerView = mFooterView;
377 | measureChildWithMargins(footerView, widthMeasureSpec, 0, heightMeasureSpec, 0);
378 | MarginLayoutParams lp = ((MarginLayoutParams) footerView.getLayoutParams());
379 | mFooterHeight = footerView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
380 | if (mLoadMoreTriggerOffset < mFooterHeight) {
381 | mLoadMoreTriggerOffset = mFooterHeight;
382 | }
383 | }
384 | }
385 |
386 | @Override
387 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
388 | layoutChildren();
389 |
390 | mHasHeaderView = (mHeaderView != null);
391 | mHasFooterView = (mFooterView != null);
392 | }
393 |
394 | /**
395 | * TODO add gravity
396 | * LayoutParams of RefreshLoadMoreLayout
397 | */
398 | public static class LayoutParams extends MarginLayoutParams {
399 |
400 | public LayoutParams(Context c, AttributeSet attrs) {
401 | super(c, attrs);
402 | }
403 |
404 | public LayoutParams(int width, int height) {
405 | super(width, height);
406 | }
407 |
408 | public LayoutParams(MarginLayoutParams source) {
409 | super(source);
410 | }
411 |
412 | public LayoutParams(ViewGroup.LayoutParams source) {
413 | super(source);
414 | }
415 | }
416 |
417 | /**
418 | * {@inheritDoc}
419 | */
420 | @Override
421 | protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
422 | return new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
423 | }
424 |
425 | /**
426 | * {@inheritDoc}
427 | */
428 | @Override
429 | protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
430 | return new LayoutParams(p);
431 | }
432 |
433 | /**
434 | * {@inheritDoc}
435 | */
436 | @Override
437 | public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
438 | return new LayoutParams(getContext(), attrs);
439 | }
440 |
441 | @Override
442 | public boolean dispatchTouchEvent(MotionEvent ev) {
443 | final int action = MotionEventCompat.getActionMasked(ev);
444 | switch (action) {
445 | case MotionEvent.ACTION_CANCEL:
446 | case MotionEvent.ACTION_UP:
447 | // swipeToRefresh -> finger up -> finger down if the status is still swipeToRefresh
448 | // in onInterceptTouchEvent ACTION_DOWN event will stop the scroller
449 | // if the event pass to the child view while ACTION_MOVE(condition is false)
450 | // in onInterceptTouchEvent ACTION_MOVE the ACTION_UP or ACTION_CANCEL will not be
451 | // passed to onInterceptTouchEvent and onTouchEvent. Instead It will be passed to
452 | // child view's onTouchEvent. So we must deal this situation in dispatchTouchEvent
453 | onActivePointerUp();
454 | break;
455 | }
456 | return super.dispatchTouchEvent(ev);
457 | }
458 |
459 | @Override
460 | public boolean onInterceptTouchEvent(MotionEvent event) {
461 | final int action = MotionEventCompat.getActionMasked(event);
462 | switch (action) {
463 | case MotionEvent.ACTION_DOWN:
464 |
465 | mActivePointerId = MotionEventCompat.getPointerId(event, 0);
466 | mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
467 | mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
468 |
469 | // if it isn't an ing status or default status
470 | if (STATUS.isSwipingToRefresh(mStatus) || STATUS.isSwipingToLoadMore(mStatus) ||
471 | STATUS.isReleaseToRefresh(mStatus) || STATUS.isReleaseToLoadMore(mStatus)) {
472 | // abort autoScrolling, not trigger the method #autoScrollFinished()
473 | mAutoScroller.abortIfRunning();
474 | if (mDebug) {
475 | Log.i(TAG, "Another finger down, abort auto scrolling, let the new finger handle");
476 | }
477 | }
478 |
479 | if (STATUS.isSwipingToRefresh(mStatus) || STATUS.isReleaseToRefresh(mStatus)
480 | || STATUS.isSwipingToLoadMore(mStatus) || STATUS.isReleaseToLoadMore(mStatus)) {
481 | return true;
482 | }
483 |
484 | // let children view handle the ACTION_DOWN;
485 |
486 | // 1. children consumed:
487 | // if at least one of children onTouchEvent() ACTION_DOWN return true.
488 | // ACTION_DOWN event will not return to SwipeToLoadLayout#onTouchEvent().
489 | // but the others action can be handled by SwipeToLoadLayout#onInterceptTouchEvent()
490 |
491 | // 2. children not consumed:
492 | // if children onTouchEvent() ACTION_DOWN return false.
493 | // ACTION_DOWN event will return to SwipeToLoadLayout's onTouchEvent().
494 | // SwipeToLoadLayout#onTouchEvent() ACTION_DOWN return true to consume the ACTION_DOWN event.
495 |
496 | // anyway: handle action down in onInterceptTouchEvent() to init is an good option
497 | break;
498 | case MotionEvent.ACTION_MOVE:
499 | if (mActivePointerId == INVALID_POINTER) {
500 | return false;
501 | }
502 | float y = getMotionEventY(event, mActivePointerId);
503 | float x = getMotionEventX(event, mActivePointerId);
504 | final float yInitDiff = y - mInitDownY;
505 | final float xInitDiff = x - mInitDownX;
506 | mLastY = y;
507 | mLastX = x;
508 | boolean moved = Math.abs(yInitDiff) > Math.abs(xInitDiff);
509 | boolean triggerCondition =
510 | // refresh trigger condition
511 | (yInitDiff > 0 && moved && onCheckCanRefresh()) ||
512 | //load more trigger condition
513 | (yInitDiff < 0 && moved && onCheckCanLoadMore());
514 | if (triggerCondition) {
515 | // if the refresh's or load more's trigger condition is true,
516 | // intercept the move action event and pass it to SwipeToLoadLayout#onTouchEvent()
517 | return true;
518 | }
519 | break;
520 | case MotionEvent.ACTION_POINTER_UP: {
521 | onSecondaryPointerUp(event);
522 | mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
523 | mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
524 | break;
525 | }
526 | case MotionEvent.ACTION_UP:
527 | case MotionEvent.ACTION_CANCEL:
528 | mActivePointerId = INVALID_POINTER;
529 | break;
530 | }
531 | return super.onInterceptTouchEvent(event);
532 | }
533 |
534 | @Override
535 | public boolean onTouchEvent(MotionEvent event) {
536 | final int action = MotionEventCompat.getActionMasked(event);
537 |
538 | switch (action) {
539 | case MotionEvent.ACTION_DOWN:
540 | mActivePointerId = MotionEventCompat.getPointerId(event, 0);
541 | return true;
542 |
543 | case MotionEvent.ACTION_MOVE:
544 | // take over the ACTION_MOVE event from SwipeToLoadLayout#onInterceptTouchEvent()
545 | // if condition is true
546 | final float y = getMotionEventY(event, mActivePointerId);
547 | final float x = getMotionEventX(event, mActivePointerId);
548 |
549 | final float yDiff = y - mLastY;
550 | final float xDiff = x - mLastX;
551 | mLastY = y;
552 | mLastX = x;
553 |
554 | if (Math.abs(xDiff) > Math.abs(yDiff) && Math.abs(xDiff) > mTouchSlop) {
555 | return false;
556 | }
557 |
558 | if (STATUS.isStatusDefault(mStatus)) {
559 | if (yDiff > 0 && onCheckCanRefresh()) {
560 | mRefreshCallback.onPrepare();
561 | setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
562 | } else if (yDiff < 0 && onCheckCanLoadMore()) {
563 | mLoadMoreCallback.onPrepare();
564 | setStatus(STATUS.STATUS_SWIPING_TO_LOAD_MORE);
565 | }
566 | } else if (STATUS.isRefreshStatus(mStatus)) {
567 | if (mTargetOffset <= 0) {
568 | setStatus(STATUS.STATUS_DEFAULT);
569 | fixCurrentStatusLayout();
570 | return false;
571 | }
572 | } else if (STATUS.isLoadMoreStatus(mStatus)) {
573 | if (mTargetOffset >= 0) {
574 | setStatus(STATUS.STATUS_DEFAULT);
575 | fixCurrentStatusLayout();
576 | return false;
577 | }
578 | }
579 |
580 | if (STATUS.isRefreshStatus(mStatus)) {
581 | if (STATUS.isSwipingToRefresh(mStatus) || STATUS.isReleaseToRefresh(mStatus)) {
582 | if (mTargetOffset >= mRefreshTriggerOffset) {
583 | setStatus(STATUS.STATUS_RELEASE_TO_REFRESH);
584 | } else {
585 | setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
586 | }
587 | fingerScroll(yDiff);
588 | }
589 | } else if (STATUS.isLoadMoreStatus(mStatus)) {
590 | if (STATUS.isSwipingToLoadMore(mStatus) || STATUS.isReleaseToLoadMore(mStatus)) {
591 | if (-mTargetOffset >= mLoadMoreTriggerOffset) {
592 | setStatus(STATUS.STATUS_RELEASE_TO_LOAD_MORE);
593 | } else {
594 | setStatus(STATUS.STATUS_SWIPING_TO_LOAD_MORE);
595 | }
596 | fingerScroll(yDiff);
597 | }
598 | }
599 | return true;
600 |
601 | case MotionEvent.ACTION_POINTER_DOWN: {
602 | final int pointerIndex = MotionEventCompat.getActionIndex(event);
603 | final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
604 | if (pointerId != INVALID_POINTER) {
605 | mActivePointerId = pointerId;
606 | }
607 | mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
608 | mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
609 | break;
610 | }
611 | case MotionEvent.ACTION_POINTER_UP: {
612 | onSecondaryPointerUp(event);
613 | mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
614 | mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
615 | break;
616 | }
617 | case MotionEvent.ACTION_UP:
618 | case MotionEvent.ACTION_CANCEL:
619 | if (mActivePointerId == INVALID_POINTER) {
620 | return false;
621 | }
622 | mActivePointerId = INVALID_POINTER;
623 | break;
624 | default:
625 | break;
626 | }
627 | return super.onTouchEvent(event);
628 | }
629 |
630 | /**
631 | * set debug mode(default value false)
632 | *
633 | * @param debug if true log on, false log off
634 | */
635 | public void setDebug(boolean debug) {
636 | this.mDebug = debug;
637 | }
638 |
639 | /**
640 | * is refresh function is enabled
641 | *
642 | * @return
643 | */
644 | public boolean isRefreshEnabled() {
645 | return mRefreshEnabled;
646 | }
647 |
648 | /**
649 | * switch refresh function on or off
650 | *
651 | * @param enable
652 | */
653 | public void setRefreshEnabled(boolean enable) {
654 | this.mRefreshEnabled = enable;
655 | }
656 |
657 | /**
658 | * is load more function is enabled
659 | *
660 | * @return
661 | */
662 | public boolean isLoadMoreEnabled() {
663 | return mLoadMoreEnabled;
664 | }
665 |
666 | /**
667 | * switch load more function on or off
668 | *
669 | * @param enable
670 | */
671 | public void setLoadMoreEnabled(boolean enable) {
672 | this.mLoadMoreEnabled = enable;
673 | }
674 |
675 | /**
676 | * is current status refreshing
677 | *
678 | * @return
679 | */
680 | public boolean isRefreshing() {
681 | return STATUS.isRefreshing(mStatus);
682 | }
683 |
684 | /**
685 | * is current status loading more
686 | *
687 | * @return
688 | */
689 | public boolean isLoadingMore() {
690 | return STATUS.isLoadingMore(mStatus);
691 | }
692 |
693 | /**
694 | * set refresh header view, the view must at lease be an implement of {@code SwipeRefreshTrigger}.
695 | * the view can also implement {@code SwipeTrigger} for more extension functions
696 | *
697 | * @param view
698 | */
699 | public void setRefreshHeaderView(View view) {
700 | if (view instanceof SwipeRefreshTrigger) {
701 | if (mHeaderView != null && mHeaderView != view) {
702 | removeView(mHeaderView);
703 | }
704 | if (mHeaderView != view) {
705 | this.mHeaderView = view;
706 | addView(view);
707 | }
708 | } else {
709 | Log.e(TAG, "Refresh header view must be an implement of SwipeRefreshTrigger");
710 | }
711 | }
712 |
713 | /**
714 | * set load more footer view, the view must at least be an implement of SwipeLoadTrigger
715 | * the view can also implement {@code SwipeTrigger} for more extension functions
716 | *
717 | * @param view
718 | */
719 | public void setLoadMoreFooterView(View view) {
720 | if (view instanceof SwipeLoadMoreTrigger) {
721 | if (mFooterView != null && mFooterView != view) {
722 | removeView(mFooterView);
723 | }
724 | if (mFooterView != view) {
725 | this.mFooterView = view;
726 | addView(mFooterView);
727 | }
728 | } else {
729 | Log.e(TAG, "Load more footer view must be an implement of SwipeLoadTrigger");
730 | }
731 | }
732 |
733 | /**
734 | * set the style of the refresh header
735 | *
736 | * @param style
737 | */
738 | public void setSwipeStyle(int style) {
739 | this.mStyle = style;
740 | requestLayout();
741 | }
742 |
743 | /**
744 | * set how hard to drag. bigger easier, smaller harder;
745 | *
746 | * @param dragRatio default value is {@link #DEFAULT_DRAG_RATIO}
747 | */
748 | public void setDragRatio(float dragRatio) {
749 | this.mDragRatio = dragRatio;
750 | }
751 |
752 | /**
753 | * set the value of {@link #mRefreshTriggerOffset}.
754 | * Default value is the refresh header view height {@link #mHeaderHeight}
755 | * If the offset you set is smaller than {@link #mHeaderHeight} or not set,
756 | * using {@link #mHeaderHeight} as default value
757 | *
758 | * @param offset
759 | */
760 | public void setRefreshTriggerOffset(int offset) {
761 | mRefreshTriggerOffset = offset;
762 | }
763 |
764 | /**
765 | * set the value of {@link #mLoadMoreTriggerOffset}.
766 | * Default value is the load more footer view height {@link #mFooterHeight}
767 | * If the offset you set is smaller than {@link #mFooterHeight} or not set,
768 | * using {@link #mFooterHeight} as default value
769 | *
770 | * @param offset
771 | */
772 | public void setLoadMoreTriggerOffset(int offset) {
773 | mLoadMoreTriggerOffset = offset;
774 | }
775 |
776 | /**
777 | * Set the final offset you can swipe to refresh.
778 | * If the offset you set is 0(default value) or smaller than {@link #mRefreshTriggerOffset}
779 | * there no final offset
780 | *
781 | * @param offset
782 | */
783 | public void setRefreshFinalDragOffset(int offset) {
784 | mRefreshFinalDragOffset = offset;
785 | }
786 |
787 | /**
788 | * Set the final offset you can swipe to load more.
789 | * If the offset you set is 0(default value) or smaller than {@link #mLoadMoreTriggerOffset},
790 | * there no final offset
791 | *
792 | * @param offset
793 | */
794 | public void setLoadMoreFinalDragOffset(int offset) {
795 | mLoadMoreFinalDragOffset = offset;
796 | }
797 |
798 | /**
799 | * set {@link #mSwipingToRefreshToDefaultScrollingDuration} in milliseconds
800 | *
801 | * @param duration
802 | */
803 | public void setSwipingToRefreshToDefaultScrollingDuration(int duration) {
804 | this.mSwipingToRefreshToDefaultScrollingDuration = duration;
805 | }
806 |
807 | /**
808 | * set {@link #mReleaseToRefreshToRefreshingScrollingDuration} in milliseconds
809 | *
810 | * @param duration
811 | */
812 | public void setReleaseToRefreshingScrollingDuration(int duration) {
813 | this.mReleaseToRefreshToRefreshingScrollingDuration = duration;
814 | }
815 |
816 | /**
817 | * set {@link #mRefreshCompleteDelayDuration} in milliseconds
818 | *
819 | * @param duration
820 | */
821 | public void setRefreshCompleteDelayDuration(int duration) {
822 | this.mRefreshCompleteDelayDuration = duration;
823 | }
824 |
825 | /**
826 | * set {@link #mRefreshCompleteToDefaultScrollingDuration} in milliseconds
827 | *
828 | * @param duration
829 | */
830 | public void setRefreshCompleteToDefaultScrollingDuration(int duration) {
831 | this.mRefreshCompleteToDefaultScrollingDuration = duration;
832 | }
833 |
834 | /**
835 | * set {@link #mDefaultToRefreshingScrollingDuration} in milliseconds
836 | *
837 | * @param duration
838 | */
839 | public void setDefaultToRefreshingScrollingDuration(int duration) {
840 | this.mDefaultToRefreshingScrollingDuration = duration;
841 | }
842 |
843 | /**
844 | * set {@link @mSwipingToLoadMoreToDefaultScrollingDuration} in milliseconds
845 | *
846 | * @param duration
847 | */
848 | public void setSwipingToLoadMoreToDefaultScrollingDuration(int duration) {
849 | this.mSwipingToLoadMoreToDefaultScrollingDuration = duration;
850 | }
851 |
852 | /**
853 | * set {@link #mReleaseToLoadMoreToLoadingMoreScrollingDuration} in milliseconds
854 | *
855 | * @param duration
856 | */
857 | public void setReleaseToLoadingMoreScrollingDuration(int duration) {
858 | this.mReleaseToLoadMoreToLoadingMoreScrollingDuration = duration;
859 | }
860 |
861 | /**
862 | * set {@link #mLoadMoreCompleteDelayDuration} in milliseconds
863 | *
864 | * @param duration
865 | */
866 | public void setLoadMoreCompleteDelayDuration(int duration) {
867 | this.mLoadMoreCompleteDelayDuration = duration;
868 | }
869 |
870 | /**
871 | * set {@link #mLoadMoreCompleteToDefaultScrollingDuration} in milliseconds
872 | *
873 | * @param duration
874 | */
875 | public void setLoadMoreCompleteToDefaultScrollingDuration(int duration) {
876 | this.mLoadMoreCompleteToDefaultScrollingDuration = duration;
877 | }
878 |
879 | /**
880 | * set {@link #mDefaultToLoadingMoreScrollingDuration} in milliseconds
881 | *
882 | * @param duration
883 | */
884 | public void setDefaultToLoadingMoreScrollingDuration(int duration) {
885 | this.mDefaultToLoadingMoreScrollingDuration = duration;
886 | }
887 |
888 | /**
889 | * set an {@link OnRefreshListener} to listening refresh event
890 | *
891 | * @param listener
892 | */
893 | public void setOnRefreshListener(OnRefreshListener listener) {
894 | this.mRefreshListener = listener;
895 | }
896 |
897 | /**
898 | * set an {@link OnLoadMoreListener} to listening load more event
899 | *
900 | * @param listener
901 | */
902 | public void setOnLoadMoreListener(OnLoadMoreListener listener) {
903 | this.mLoadMoreListener = listener;
904 | }
905 |
906 | /**
907 | * auto refresh or cancel
908 | *
909 | * @param refreshing
910 | */
911 | public void setRefreshing(boolean refreshing) {
912 | if (!isRefreshEnabled() || mHeaderView == null) {
913 | return;
914 | }
915 | this.mAutoLoading = refreshing;
916 | if (refreshing) {
917 | if (STATUS.isStatusDefault(mStatus)) {
918 | setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
919 | scrollDefaultToRefreshing();
920 | }
921 | } else {
922 | if (STATUS.isRefreshing(mStatus)) {
923 | mRefreshCallback.onComplete();
924 | postDelayed(new Runnable() {
925 | @Override
926 | public void run() {
927 | scrollRefreshingToDefault();
928 | }
929 | }, mRefreshCompleteDelayDuration);
930 | }
931 | }
932 | }
933 |
934 | /**
935 | * auto loading more or cancel
936 | *
937 | * @param loadingMore
938 | */
939 | public void setLoadingMore(boolean loadingMore) {
940 | if (!isLoadMoreEnabled() || mFooterView == null) {
941 | return;
942 | }
943 | this.mAutoLoading = loadingMore;
944 | if (loadingMore) {
945 | if (STATUS.isStatusDefault(mStatus)) {
946 | setStatus(STATUS.STATUS_SWIPING_TO_LOAD_MORE);
947 | scrollDefaultToLoadingMore();
948 | }
949 | } else {
950 | if (STATUS.isLoadingMore(mStatus)) {
951 | mLoadMoreCallback.onComplete();
952 | postDelayed(new Runnable() {
953 | @Override
954 | public void run() {
955 | scrollLoadingMoreToDefault();
956 | }
957 | }, mLoadMoreCompleteDelayDuration);
958 | }
959 | }
960 | }
961 |
962 | /**
963 | * copy from {@link android.support.v4.widget.SwipeRefreshLayout#canChildScrollUp()}
964 | *
965 | * @return Whether it is possible for the child view of this layout to
966 | * scroll up. Override this if the child view is a custom view.
967 | */
968 | protected boolean canChildScrollUp() {
969 | if (android.os.Build.VERSION.SDK_INT < 14) {
970 | if (mTargetView instanceof AbsListView) {
971 | final AbsListView absListView = (AbsListView) mTargetView;
972 | return absListView.getChildCount() > 0
973 | && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
974 | .getTop() < absListView.getPaddingTop());
975 | } else {
976 | return ViewCompat.canScrollVertically(mTargetView, -1) || mTargetView.getScrollY() > 0;
977 | }
978 | } else {
979 | return ViewCompat.canScrollVertically(mTargetView, -1);
980 | }
981 | }
982 |
983 | /**
984 | * Whether it is possible for the child view of this layout to
985 | * scroll down. Override this if the child view is a custom view.
986 | *
987 | * @return
988 | */
989 | protected boolean canChildScrollDown() {
990 | if (android.os.Build.VERSION.SDK_INT < 14) {
991 | if (mTargetView instanceof AbsListView) {
992 | final AbsListView absListView = (AbsListView) mTargetView;
993 | return absListView.getChildCount() > 0
994 | && (absListView.getLastVisiblePosition() < absListView.getChildCount() - 1
995 | || absListView.getChildAt(absListView.getChildCount() - 1).getBottom() > absListView.getPaddingBottom());
996 | } else {
997 | return ViewCompat.canScrollVertically(mTargetView, 1) || mTargetView.getScrollY() < 0;
998 | }
999 | } else {
1000 | return ViewCompat.canScrollVertically(mTargetView, 1);
1001 | }
1002 | }
1003 |
1004 | /**
1005 | * @see #onLayout(boolean, int, int, int, int)
1006 | */
1007 | private void layoutChildren() {
1008 | final int width = getMeasuredWidth();
1009 | final int height = getMeasuredHeight();
1010 |
1011 | final int paddingLeft = getPaddingLeft();
1012 | final int paddingTop = getPaddingTop();
1013 | final int paddingRight = getPaddingRight();
1014 | final int paddingBottom = getPaddingBottom();
1015 |
1016 | if (mTargetView == null) {
1017 | return;
1018 | }
1019 |
1020 | // layout header
1021 | if (mHeaderView != null) {
1022 | final View headerView = mHeaderView;
1023 | MarginLayoutParams lp = (MarginLayoutParams) headerView.getLayoutParams();
1024 | final int headerLeft = paddingLeft + lp.leftMargin;
1025 | final int headerTop;
1026 | switch (mStyle) {
1027 | case STYLE.CLASSIC:
1028 | // classic
1029 | headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
1030 | break;
1031 | case STYLE.ABOVE:
1032 | // classic
1033 | headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
1034 | break;
1035 | case STYLE.BLEW:
1036 | // blew
1037 | headerTop = paddingTop + lp.topMargin;
1038 | break;
1039 | case STYLE.SCALE:
1040 | // scale
1041 | headerTop = paddingTop + lp.topMargin - mHeaderHeight / 2 + mHeaderOffset / 2;
1042 | break;
1043 | default:
1044 | // classic
1045 | headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
1046 | break;
1047 | }
1048 | final int headerRight = headerLeft + headerView.getMeasuredWidth();
1049 | final int headerBottom = headerTop + headerView.getMeasuredHeight();
1050 | headerView.layout(headerLeft, headerTop, headerRight, headerBottom);
1051 | }
1052 |
1053 |
1054 | // layout target
1055 | if (mTargetView != null) {
1056 | final View targetView = mTargetView;
1057 | MarginLayoutParams lp = (MarginLayoutParams) targetView.getLayoutParams();
1058 | final int targetLeft = paddingLeft + lp.leftMargin;
1059 | final int targetTop;
1060 |
1061 | switch (mStyle) {
1062 | case STYLE.CLASSIC:
1063 | // classic
1064 | targetTop = paddingTop + lp.topMargin + mTargetOffset;
1065 | break;
1066 | case STYLE.ABOVE:
1067 | // above
1068 | targetTop = paddingTop + lp.topMargin;
1069 | break;
1070 | case STYLE.BLEW:
1071 | // classic
1072 | targetTop = paddingTop + lp.topMargin + mTargetOffset;
1073 | break;
1074 | case STYLE.SCALE:
1075 | // classic
1076 | targetTop = paddingTop + lp.topMargin + mTargetOffset;
1077 | break;
1078 | default:
1079 | // classic
1080 | targetTop = paddingTop + lp.topMargin + mTargetOffset;
1081 | break;
1082 | }
1083 | final int targetRight = targetLeft + targetView.getMeasuredWidth();
1084 | final int targetBottom = targetTop + targetView.getMeasuredHeight();
1085 | targetView.layout(targetLeft, targetTop, targetRight, targetBottom);
1086 | }
1087 |
1088 | // layout footer
1089 | if (mFooterView != null) {
1090 | final View footerView = mFooterView;
1091 | MarginLayoutParams lp = (MarginLayoutParams) footerView.getLayoutParams();
1092 | final int footerLeft = paddingLeft + lp.leftMargin;
1093 | final int footerBottom;
1094 | switch (mStyle) {
1095 | case STYLE.CLASSIC:
1096 | // classic
1097 | footerBottom = height - paddingBottom - lp.bottomMargin + mFooterHeight + mFooterOffset;
1098 | break;
1099 | case STYLE.ABOVE:
1100 | // classic
1101 | footerBottom = height - paddingBottom - lp.bottomMargin + mFooterHeight + mFooterOffset;
1102 | break;
1103 | case STYLE.BLEW:
1104 | // blew
1105 | footerBottom = height - paddingBottom - lp.bottomMargin;
1106 | break;
1107 | case STYLE.SCALE:
1108 | // scale
1109 | footerBottom = height - paddingBottom - lp.bottomMargin + mFooterHeight / 2 + mFooterOffset / 2;
1110 | break;
1111 | default:
1112 | // classic
1113 | footerBottom = height - paddingBottom - lp.bottomMargin + mFooterHeight + mFooterOffset;
1114 | break;
1115 | }
1116 | final int footerTop = footerBottom - footerView.getMeasuredHeight();
1117 | final int footerRight = footerLeft + footerView.getMeasuredWidth();
1118 |
1119 | footerView.layout(footerLeft, footerTop, footerRight, footerBottom);
1120 | }
1121 |
1122 | if (mStyle == STYLE.CLASSIC
1123 | || mStyle == STYLE.ABOVE) {
1124 | if (mHeaderView != null) {
1125 | mHeaderView.bringToFront();
1126 | }
1127 | if (mFooterView != null) {
1128 | mFooterView.bringToFront();
1129 | }
1130 | } else if (mStyle == STYLE.BLEW || mStyle == STYLE.SCALE) {
1131 | if (mTargetView != null) {
1132 | mTargetView.bringToFront();
1133 | }
1134 | }
1135 | }
1136 |
1137 | private void fixCurrentStatusLayout() {
1138 | if (STATUS.isRefreshing(mStatus)) {
1139 | mTargetOffset = (int) (mRefreshTriggerOffset + 0.5f);
1140 | mHeaderOffset = mTargetOffset;
1141 | mFooterOffset = 0;
1142 | layoutChildren();
1143 | invalidate();
1144 | } else if (STATUS.isStatusDefault(mStatus)) {
1145 | mTargetOffset = 0;
1146 | mHeaderOffset = 0;
1147 | mFooterOffset = 0;
1148 | layoutChildren();
1149 | invalidate();
1150 | } else if (STATUS.isLoadingMore(mStatus)) {
1151 | mTargetOffset = -(int) (mLoadMoreTriggerOffset + 0.5f);
1152 | mHeaderOffset = 0;
1153 | mFooterOffset = mTargetOffset;
1154 | layoutChildren();
1155 | invalidate();
1156 | }
1157 | }
1158 |
1159 | /**
1160 | * scrolling by physical touch with your fingers
1161 | *
1162 | * @param yDiff
1163 | */
1164 | private void fingerScroll(final float yDiff) {
1165 | float ratio = mDragRatio;
1166 | float yScrolled = yDiff * ratio;
1167 |
1168 | // make sure (targetOffset>0 -> targetOffset=0 -> default status)
1169 | // or (targetOffset<0 -> targetOffset=0 -> default status)
1170 | // forbidden fling (targetOffset>0 -> targetOffset=0 ->targetOffset<0 -> default status)
1171 | // or (targetOffset<0 -> targetOffset=0 ->targetOffset>0 -> default status)
1172 | // I am so smart :)
1173 |
1174 | float tmpTargetOffset = yScrolled + mTargetOffset;
1175 | if ((tmpTargetOffset > 0 && mTargetOffset < 0)
1176 | || (tmpTargetOffset < 0 && mTargetOffset > 0)) {
1177 | yScrolled = -mTargetOffset;
1178 | }
1179 |
1180 |
1181 | if (mRefreshFinalDragOffset >= mRefreshTriggerOffset && tmpTargetOffset > mRefreshFinalDragOffset) {
1182 | yScrolled = mRefreshFinalDragOffset - mTargetOffset;
1183 | } else if (mLoadMoreFinalDragOffset >= mLoadMoreTriggerOffset && -tmpTargetOffset > mLoadMoreFinalDragOffset) {
1184 | yScrolled = -mLoadMoreFinalDragOffset - mTargetOffset;
1185 | }
1186 |
1187 | if (STATUS.isRefreshStatus(mStatus)) {
1188 | mRefreshCallback.onMove(mTargetOffset, false, false);
1189 | } else if (STATUS.isLoadMoreStatus(mStatus)) {
1190 | mLoadMoreCallback.onMove(mTargetOffset, false, false);
1191 | }
1192 | updateScroll(yScrolled);
1193 | }
1194 |
1195 | private void autoScroll(final float yScrolled) {
1196 |
1197 | if (STATUS.isSwipingToRefresh(mStatus)) {
1198 | mRefreshCallback.onMove(mTargetOffset, false, true);
1199 | } else if (STATUS.isReleaseToRefresh(mStatus)) {
1200 | mRefreshCallback.onMove(mTargetOffset, false, true);
1201 | } else if (STATUS.isRefreshing(mStatus)) {
1202 | mRefreshCallback.onMove(mTargetOffset, true, true);
1203 | } else if (STATUS.isSwipingToLoadMore(mStatus)) {
1204 | mLoadMoreCallback.onMove(mTargetOffset, false, true);
1205 | } else if (STATUS.isReleaseToLoadMore(mStatus)) {
1206 | mLoadMoreCallback.onMove(mTargetOffset, false, true);
1207 | } else if (STATUS.isLoadingMore(mStatus)) {
1208 | mLoadMoreCallback.onMove(mTargetOffset, true, true);
1209 | }
1210 | updateScroll(yScrolled);
1211 | }
1212 |
1213 | /**
1214 | * Process the scrolling(auto or physical) and append the diff values to mTargetOffset
1215 | * I think it's the most busy and core method. :) a ha ha ha ha...
1216 | *
1217 | * @param yScrolled
1218 | */
1219 | private void updateScroll(final float yScrolled) {
1220 | if (yScrolled == 0) {
1221 | return;
1222 | }
1223 | mTargetOffset += yScrolled;
1224 |
1225 | if (STATUS.isRefreshStatus(mStatus)) {
1226 | mHeaderOffset = mTargetOffset;
1227 | mFooterOffset = 0;
1228 | } else if (STATUS.isLoadMoreStatus(mStatus)) {
1229 | mFooterOffset = mTargetOffset;
1230 | mHeaderOffset = 0;
1231 | }
1232 |
1233 | if (mDebug) {
1234 | Log.i(TAG, "mTargetOffset = " + mTargetOffset);
1235 | }
1236 | layoutChildren();
1237 | invalidate();
1238 | }
1239 |
1240 | /**
1241 | * on active finger up
1242 | */
1243 | private void onActivePointerUp() {
1244 | if (STATUS.isSwipingToRefresh(mStatus)) {
1245 | // simply return
1246 | scrollSwipingToRefreshToDefault();
1247 |
1248 | } else if (STATUS.isSwipingToLoadMore(mStatus)) {
1249 | // simply return
1250 | scrollSwipingToLoadMoreToDefault();
1251 |
1252 | } else if (STATUS.isReleaseToRefresh(mStatus)) {
1253 | // return to header height and perform refresh
1254 | mRefreshCallback.onRelease();
1255 | scrollReleaseToRefreshToRefreshing();
1256 |
1257 | } else if (STATUS.isReleaseToLoadMore(mStatus)) {
1258 | // return to footer height and perform loadMore
1259 | mLoadMoreCallback.onRelease();
1260 | scrollReleaseToLoadMoreToLoadingMore();
1261 |
1262 | }
1263 | }
1264 |
1265 | /**
1266 | * on not active finger up
1267 | *
1268 | * @param ev
1269 | */
1270 | private void onSecondaryPointerUp(MotionEvent ev) {
1271 | final int pointerIndex = MotionEventCompat.getActionIndex(ev);
1272 | final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
1273 | if (pointerId == mActivePointerId) {
1274 | // This was our active pointer going up. Choose a new
1275 | // active pointer and adjust accordingly.
1276 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
1277 | mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
1278 | }
1279 | }
1280 |
1281 | private void scrollDefaultToRefreshing() {
1282 | mAutoScroller.autoScroll((int) (mRefreshTriggerOffset + 0.5f), mDefaultToRefreshingScrollingDuration);
1283 | }
1284 |
1285 | private void scrollDefaultToLoadingMore() {
1286 | mAutoScroller.autoScroll(-(int) (mLoadMoreTriggerOffset + 0.5f), mDefaultToLoadingMoreScrollingDuration);
1287 | }
1288 |
1289 | private void scrollSwipingToRefreshToDefault() {
1290 | mAutoScroller.autoScroll(-mHeaderOffset, mSwipingToRefreshToDefaultScrollingDuration);
1291 | }
1292 |
1293 | private void scrollSwipingToLoadMoreToDefault() {
1294 | mAutoScroller.autoScroll(-mFooterOffset, mSwipingToLoadMoreToDefaultScrollingDuration);
1295 | }
1296 |
1297 | private void scrollReleaseToRefreshToRefreshing() {
1298 | mAutoScroller.autoScroll(mHeaderHeight - mHeaderOffset, mReleaseToRefreshToRefreshingScrollingDuration);
1299 | }
1300 |
1301 | private void scrollReleaseToLoadMoreToLoadingMore() {
1302 | mAutoScroller.autoScroll(-mFooterOffset - mFooterHeight, mReleaseToLoadMoreToLoadingMoreScrollingDuration);
1303 | }
1304 |
1305 | private void scrollRefreshingToDefault() {
1306 | mAutoScroller.autoScroll(-mHeaderOffset, mRefreshCompleteToDefaultScrollingDuration);
1307 | }
1308 |
1309 | private void scrollLoadingMoreToDefault() {
1310 | mAutoScroller.autoScroll(-mFooterOffset, mLoadMoreCompleteToDefaultScrollingDuration);
1311 | }
1312 |
1313 | /**
1314 | * invoke when {@link AutoScroller#finish()} is automatic
1315 | */
1316 | private void autoScrollFinished() {
1317 | int mLastStatus = mStatus;
1318 |
1319 | if (STATUS.isReleaseToRefresh(mStatus)) {
1320 | setStatus(STATUS.STATUS_REFRESHING);
1321 | fixCurrentStatusLayout();
1322 | mRefreshCallback.onRefresh();
1323 |
1324 | } else if (STATUS.isRefreshing(mStatus)) {
1325 | setStatus(STATUS.STATUS_DEFAULT);
1326 | fixCurrentStatusLayout();
1327 | mRefreshCallback.onReset();
1328 |
1329 | } else if (STATUS.isSwipingToRefresh(mStatus)) {
1330 | if (mAutoLoading) {
1331 | mAutoLoading = false;
1332 | setStatus(STATUS.STATUS_REFRESHING);
1333 | fixCurrentStatusLayout();
1334 | mRefreshCallback.onRefresh();
1335 | } else {
1336 | setStatus(STATUS.STATUS_DEFAULT);
1337 | fixCurrentStatusLayout();
1338 | mRefreshCallback.onReset();
1339 | }
1340 | } else if (STATUS.isStatusDefault(mStatus)) {
1341 |
1342 | } else if (STATUS.isSwipingToLoadMore(mStatus)) {
1343 | if (mAutoLoading) {
1344 | mAutoLoading = false;
1345 | setStatus(STATUS.STATUS_LOADING_MORE);
1346 | fixCurrentStatusLayout();
1347 | mLoadMoreCallback.onLoadMore();
1348 | } else {
1349 | setStatus(STATUS.STATUS_DEFAULT);
1350 | fixCurrentStatusLayout();
1351 | mLoadMoreCallback.onReset();
1352 | }
1353 | } else if (STATUS.isLoadingMore(mStatus)) {
1354 | setStatus(STATUS.STATUS_DEFAULT);
1355 | fixCurrentStatusLayout();
1356 | mLoadMoreCallback.onReset();
1357 | } else if (STATUS.isReleaseToLoadMore(mStatus)) {
1358 | setStatus(STATUS.STATUS_LOADING_MORE);
1359 | fixCurrentStatusLayout();
1360 | mLoadMoreCallback.onLoadMore();
1361 | } else {
1362 | throw new IllegalStateException("illegal state: " + STATUS.getStatus(mStatus));
1363 | }
1364 |
1365 | if (mDebug) {
1366 | Log.i(TAG, STATUS.getStatus(mLastStatus) + " -> " + STATUS.getStatus(mStatus));
1367 | }
1368 | }
1369 |
1370 | /**
1371 | * check if it can refresh
1372 | *
1373 | * @return
1374 | */
1375 | private boolean onCheckCanRefresh() {
1376 |
1377 | return mRefreshEnabled && !canChildScrollUp() && mHasHeaderView && mRefreshTriggerOffset > 0;
1378 | }
1379 |
1380 | /**
1381 | * check if it can load more
1382 | *
1383 | * @return
1384 | */
1385 | private boolean onCheckCanLoadMore() {
1386 |
1387 | return mLoadMoreEnabled && !canChildScrollDown() && mHasFooterView && mLoadMoreTriggerOffset > 0;
1388 | }
1389 |
1390 | private float getMotionEventY(MotionEvent event, int activePointerId) {
1391 | final int index = MotionEventCompat.findPointerIndex(event, activePointerId);
1392 | if (index < 0) {
1393 | return INVALID_COORDINATE;
1394 | }
1395 | return MotionEventCompat.getY(event, index);
1396 | }
1397 |
1398 | private float getMotionEventX(MotionEvent event, int activePointId) {
1399 | final int index = MotionEventCompat.findPointerIndex(event, activePointId);
1400 | if (index < 0) {
1401 | return INVALID_COORDINATE;
1402 | }
1403 | return MotionEventCompat.getX(event, index);
1404 | }
1405 |
1406 | RefreshCallback mRefreshCallback = new RefreshCallback() {
1407 | @Override
1408 | public void onPrepare() {
1409 | if (mHeaderView != null && mHeaderView instanceof SwipeTrigger && STATUS.isStatusDefault(mStatus)) {
1410 | mHeaderView.setVisibility(VISIBLE);
1411 | ((SwipeTrigger) mHeaderView).onPrepare();
1412 | }
1413 | }
1414 |
1415 | @Override
1416 | public void onMove(int y, boolean isComplete, boolean automatic) {
1417 | if (mHeaderView != null && mHeaderView instanceof SwipeTrigger && STATUS.isRefreshStatus(mStatus)) {
1418 | if (mHeaderView.getVisibility() != VISIBLE) {
1419 | mHeaderView.setVisibility(VISIBLE);
1420 | }
1421 | ((SwipeTrigger) mHeaderView).onMove(y, isComplete, automatic);
1422 | }
1423 | }
1424 |
1425 | @Override
1426 | public void onRelease() {
1427 | if (mHeaderView != null && mHeaderView instanceof SwipeTrigger && STATUS.isReleaseToRefresh(mStatus)) {
1428 | ((SwipeTrigger) mHeaderView).onRelease();
1429 | }
1430 | }
1431 |
1432 | @Override
1433 | public void onRefresh() {
1434 | if (mHeaderView != null && STATUS.isRefreshing(mStatus)) {
1435 | if (mHeaderView instanceof SwipeRefreshTrigger) {
1436 | ((SwipeRefreshTrigger) mHeaderView).onRefresh();
1437 | }
1438 | if (mRefreshListener != null) {
1439 | mRefreshListener.onRefresh();
1440 | }
1441 | }
1442 | }
1443 |
1444 | @Override
1445 | public void onComplete() {
1446 | if (mHeaderView != null && mHeaderView instanceof SwipeTrigger) {
1447 | ((SwipeTrigger) mHeaderView).onComplete();
1448 | }
1449 | }
1450 |
1451 | @Override
1452 | public void onReset() {
1453 | if (mHeaderView != null && mHeaderView instanceof SwipeTrigger && STATUS.isStatusDefault(mStatus)) {
1454 | ((SwipeTrigger) mHeaderView).onReset();
1455 | mHeaderView.setVisibility(GONE);
1456 | }
1457 | }
1458 | };
1459 |
1460 | LoadMoreCallback mLoadMoreCallback = new LoadMoreCallback() {
1461 |
1462 | @Override
1463 | public void onPrepare() {
1464 | if (mFooterView != null && mFooterView instanceof SwipeTrigger && STATUS.isStatusDefault(mStatus)) {
1465 | mFooterView.setVisibility(VISIBLE);
1466 | ((SwipeTrigger) mFooterView).onPrepare();
1467 | }
1468 | }
1469 |
1470 | @Override
1471 | public void onMove(int y, boolean isComplete, boolean automatic) {
1472 | if (mFooterView != null && mFooterView instanceof SwipeTrigger && STATUS.isLoadMoreStatus(mStatus)) {
1473 | if (mFooterView.getVisibility() != VISIBLE) {
1474 | mFooterView.setVisibility(VISIBLE);
1475 | }
1476 | ((SwipeTrigger) mFooterView).onMove(y, isComplete, automatic);
1477 | }
1478 | }
1479 |
1480 | @Override
1481 | public void onRelease() {
1482 | if (mFooterView != null && mFooterView instanceof SwipeTrigger && STATUS.isReleaseToLoadMore(mStatus)) {
1483 | ((SwipeTrigger) mFooterView).onRelease();
1484 | }
1485 | }
1486 |
1487 | @Override
1488 | public void onLoadMore() {
1489 | if (mFooterView != null && STATUS.isLoadingMore(mStatus)) {
1490 | if (mFooterView instanceof SwipeLoadMoreTrigger) {
1491 | ((SwipeLoadMoreTrigger) mFooterView).onLoadMore();
1492 | }
1493 | if (mLoadMoreListener != null) {
1494 | mLoadMoreListener.onLoadMore();
1495 | }
1496 | }
1497 | }
1498 |
1499 | @Override
1500 | public void onComplete() {
1501 | if (mFooterView != null && mFooterView instanceof SwipeTrigger) {
1502 | ((SwipeTrigger) mFooterView).onComplete();
1503 | }
1504 | }
1505 |
1506 | @Override
1507 | public void onReset() {
1508 | if (mFooterView != null && mFooterView instanceof SwipeTrigger && STATUS.isStatusDefault(mStatus)) {
1509 | ((SwipeTrigger) mFooterView).onReset();
1510 | mFooterView.setVisibility(GONE);
1511 | }
1512 | }
1513 | };
1514 |
1515 | /**
1516 | * refresh event callback
1517 | */
1518 | abstract class RefreshCallback implements SwipeTrigger, SwipeRefreshTrigger {
1519 | }
1520 |
1521 | /**
1522 | * load more event callback
1523 | */
1524 | abstract class LoadMoreCallback implements SwipeTrigger, SwipeLoadMoreTrigger {
1525 | }
1526 |
1527 | private class AutoScroller implements Runnable {
1528 |
1529 | private Scroller mScroller;
1530 |
1531 | private int mmLastY;
1532 |
1533 | private boolean mRunning = false;
1534 |
1535 | private boolean mAbort = false;
1536 |
1537 | public AutoScroller() {
1538 | mScroller = new Scroller(getContext());
1539 | }
1540 |
1541 | @Override
1542 | public void run() {
1543 | boolean finish = !mScroller.computeScrollOffset() || mScroller.isFinished();
1544 | int currY = mScroller.getCurrY();
1545 | int yDiff = currY - mmLastY;
1546 | if (finish) {
1547 | finish();
1548 | } else {
1549 | mmLastY = currY;
1550 | SwipeToLoadLayout.this.autoScroll(yDiff);
1551 | post(this);
1552 | }
1553 | }
1554 |
1555 | /**
1556 | * remove the post callbacks and reset default values
1557 | */
1558 | private void finish() {
1559 | mmLastY = 0;
1560 | mRunning = false;
1561 | removeCallbacks(this);
1562 | // if abort by user, don't call
1563 | if (!mAbort) {
1564 | autoScrollFinished();
1565 | }
1566 | }
1567 |
1568 | /**
1569 | * abort scroll if it is scrolling
1570 | */
1571 | public void abortIfRunning() {
1572 | if (mRunning) {
1573 | if (!mScroller.isFinished()) {
1574 | mAbort = true;
1575 | mScroller.forceFinished(true);
1576 | }
1577 | finish();
1578 | mAbort = false;
1579 | }
1580 | }
1581 |
1582 | /**
1583 | * The param yScrolled here isn't final pos of y.
1584 | * It's just like the yScrolled param in the
1585 | * {@link #updateScroll(float yScrolled)}
1586 | *
1587 | * @param yScrolled
1588 | * @param duration
1589 | */
1590 | private void autoScroll(int yScrolled, int duration) {
1591 | removeCallbacks(this);
1592 | mmLastY = 0;
1593 | if (!mScroller.isFinished()) {
1594 | mScroller.forceFinished(true);
1595 | }
1596 | mScroller.startScroll(0, 0, 0, yScrolled, duration);
1597 | post(this);
1598 | mRunning = true;
1599 | }
1600 | }
1601 |
1602 | /**
1603 | * Set the current status for better control
1604 | *
1605 | * @param status
1606 | */
1607 | private void setStatus(int status) {
1608 | mStatus = status;
1609 | if (mDebug) {
1610 | STATUS.printStatus(status);
1611 | }
1612 | }
1613 |
1614 | /**
1615 | * an inner util class.
1616 | * enum of status
1617 | */
1618 | private final static class STATUS {
1619 | private static final int STATUS_REFRESH_RETURNING = -4;
1620 | private static final int STATUS_REFRESHING = -3;
1621 | private static final int STATUS_RELEASE_TO_REFRESH = -2;
1622 | private static final int STATUS_SWIPING_TO_REFRESH = -1;
1623 | private static final int STATUS_DEFAULT = 0;
1624 | private static final int STATUS_SWIPING_TO_LOAD_MORE = 1;
1625 | private static final int STATUS_RELEASE_TO_LOAD_MORE = 2;
1626 | private static final int STATUS_LOADING_MORE = 3;
1627 | private static final int STATUS_LOAD_MORE_RETURNING = 4;
1628 |
1629 | private static boolean isRefreshing(final int status) {
1630 | return status == STATUS.STATUS_REFRESHING;
1631 | }
1632 |
1633 | private static boolean isLoadingMore(final int status) {
1634 | return status == STATUS.STATUS_LOADING_MORE;
1635 | }
1636 |
1637 | private static boolean isReleaseToRefresh(final int status) {
1638 | return status == STATUS.STATUS_RELEASE_TO_REFRESH;
1639 | }
1640 |
1641 | private static boolean isReleaseToLoadMore(final int status) {
1642 | return status == STATUS.STATUS_RELEASE_TO_LOAD_MORE;
1643 | }
1644 |
1645 | private static boolean isSwipingToRefresh(final int status) {
1646 | return status == STATUS.STATUS_SWIPING_TO_REFRESH;
1647 | }
1648 |
1649 | private static boolean isSwipingToLoadMore(final int status) {
1650 | return status == STATUS.STATUS_SWIPING_TO_LOAD_MORE;
1651 | }
1652 |
1653 | private static boolean isRefreshStatus(final int status) {
1654 | return status < STATUS.STATUS_DEFAULT;
1655 | }
1656 |
1657 | public static boolean isLoadMoreStatus(final int status) {
1658 | return status > STATUS.STATUS_DEFAULT;
1659 | }
1660 |
1661 | private static boolean isStatusDefault(final int status) {
1662 | return status == STATUS.STATUS_DEFAULT;
1663 | }
1664 |
1665 | private static String getStatus(int status) {
1666 | final String statusInfo;
1667 | switch (status) {
1668 | case STATUS_REFRESH_RETURNING:
1669 | statusInfo = "status_refresh_returning";
1670 | break;
1671 | case STATUS_REFRESHING:
1672 | statusInfo = "status_refreshing";
1673 | break;
1674 | case STATUS_RELEASE_TO_REFRESH:
1675 | statusInfo = "status_release_to_refresh";
1676 | break;
1677 | case STATUS_SWIPING_TO_REFRESH:
1678 | statusInfo = "status_swiping_to_refresh";
1679 | break;
1680 | case STATUS_DEFAULT:
1681 | statusInfo = "status_default";
1682 | break;
1683 | case STATUS_SWIPING_TO_LOAD_MORE:
1684 | statusInfo = "status_swiping_to_load_more";
1685 | break;
1686 | case STATUS_RELEASE_TO_LOAD_MORE:
1687 | statusInfo = "status_release_to_load_more";
1688 | break;
1689 | case STATUS_LOADING_MORE:
1690 | statusInfo = "status_loading_more";
1691 | break;
1692 | case STATUS_LOAD_MORE_RETURNING:
1693 | statusInfo = "status_load_more_returning";
1694 | break;
1695 | default:
1696 | statusInfo = "status_illegal!";
1697 | break;
1698 | }
1699 | return statusInfo;
1700 | }
1701 |
1702 | private static void printStatus(int status) {
1703 | Log.i(TAG, "printStatus:" + getStatus(status));
1704 | }
1705 | }
1706 | }
1707 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/liangmutian/airrecyclerview/swipetoloadlayout/SwipeTrigger.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview.swipetoloadlayout;
2 |
3 | /**
4 | * Created by Aspsine on 2015/8/17.
5 | */
6 | public interface SwipeTrigger {
7 | void onPrepare();
8 |
9 | void onMove(int y, boolean isComplete, boolean automatic);
10 |
11 | void onRelease();
12 |
13 | void onComplete();
14 |
15 | void onReset();
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/anim_refresh.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_progressbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 | ]
19 |
20 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_choose_act_type.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
19 |
20 |
21 |
29 |
30 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_choose_act_type2.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
20 |
21 |
22 |
31 |
32 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_footer_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_refresh_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
15 |
16 |
21 |
22 |
23 |
30 |
31 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_super_recycler.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
14 |
15 |
20 |
21 |
22 |
27 |
28 |
35 |
36 |
37 |
42 |
43 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_super_refresh_recycler.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
16 |
17 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
36 |
37 |
44 |
45 |
46 |
51 |
52 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/bg_loading_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/bg_loading_circle.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpf.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpg.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gph.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpi.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpj.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpk.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpl.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpm.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpn.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpo.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpq.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/gpr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/gpr.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/icon_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/icon_refresh.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/n1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/n1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/n2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/n2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/n3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/n3.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/n4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/n4.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/n5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxhdpi/n5.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/attrs.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AirRecyclerView
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/liangmutian/airrecyclerview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.liangmutian.airrecyclerview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidMsky/GlideScrollRecyclerView/4ad14e6ef05b0ab32dc447bc41f73d41fa489e78/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------