├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── assets
│ │ │ └── squirrel.gif
│ │ ├── res
│ │ │ ├── drawable-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── strings.xml
│ │ │ ├── menu
│ │ │ │ └── my.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ ├── eating_item.xml
│ │ │ │ ├── squirrel_item.xml
│ │ │ │ ├── activity_eating.xml
│ │ │ │ ├── activity_squirrel.xml
│ │ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── bettycc
│ │ │ └── com
│ │ │ └── animatepulltorefresh
│ │ │ ├── MainActivity.java
│ │ │ └── MyActivity.java
│ └── androidTest
│ │ └── java
│ │ └── bettycc
│ │ └── com
│ │ └── animatepulltorefresh
│ │ └── ApplicationTest.java
├── build.gradle
└── proguard-rules.pro
├── library
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── ids.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── pull_refresh_strings.xml
│ │ │ │ └── attrs.xml
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── ok.png
│ │ │ │ ├── loading.png
│ │ │ │ ├── gif_loading1.gif
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── default_ptr_flip.png
│ │ │ │ ├── dropdown_anim_00.png
│ │ │ │ ├── dropdown_anim_01.png
│ │ │ │ ├── dropdown_anim_02.png
│ │ │ │ ├── dropdown_anim_03.png
│ │ │ │ ├── dropdown_anim_04.png
│ │ │ │ ├── dropdown_anim_05.png
│ │ │ │ ├── dropdown_anim_06.png
│ │ │ │ ├── dropdown_anim_07.png
│ │ │ │ ├── dropdown_anim_08.png
│ │ │ │ ├── dropdown_anim_09.png
│ │ │ │ ├── dropdown_anim_10.png
│ │ │ │ ├── indicator_arrow.png
│ │ │ │ ├── default_ptr_rotate.png
│ │ │ │ ├── dropdown_loading_00.png
│ │ │ │ ├── dropdown_loading_01.png
│ │ │ │ └── dropdown_loading_02.png
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── indicator_arrow.png
│ │ │ │ ├── default_ptr_flip.png
│ │ │ │ └── default_ptr_rotate.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── indicator_arrow.png
│ │ │ │ ├── default_ptr_flip.png
│ │ │ │ └── default_ptr_rotate.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values-zh
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-ja
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-he
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-iw
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-ko
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-ar
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-es
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-cs
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-de
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-fr
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-it
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-nl
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-pl
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-pt-rBR
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-pt
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-ru
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── values-ro
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── drawable
│ │ │ │ ├── indicator_bg_top.xml
│ │ │ │ └── indicator_bg_bottom.xml
│ │ │ ├── values-fi
│ │ │ │ └── pull_refresh_strings.xml
│ │ │ ├── anim
│ │ │ │ ├── slide_out_to_top.xml
│ │ │ │ ├── slide_in_from_bottom.xml
│ │ │ │ ├── slide_in_from_top.xml
│ │ │ │ └── slide_out_to_bottom.xml
│ │ │ └── layout
│ │ │ │ ├── pull_to_refresh_header_horizontal.xml
│ │ │ │ └── pull_to_refresh_header_vertical.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── handmark
│ │ │ └── pulltorefresh
│ │ │ └── library
│ │ │ ├── internal
│ │ │ ├── Utils.java
│ │ │ ├── GifAnimation.java
│ │ │ ├── EmptyViewMethodAccessor.java
│ │ │ ├── ViewCompat.java
│ │ │ ├── GifLoadingLayout.java
│ │ │ ├── RotateLoadingLayout.java
│ │ │ ├── FlipLoadingLayout.java
│ │ │ ├── IndicatorLayout.java
│ │ │ └── LoadingLayout.java
│ │ │ ├── ILoadingLayout.java
│ │ │ ├── LoadingLayoutProxy.java
│ │ │ ├── extras
│ │ │ ├── SoundPullEventListener.java
│ │ │ └── PullToRefreshWebView2.java
│ │ │ ├── PullToRefreshGridView.java
│ │ │ ├── PullToRefreshExpandableListView.java
│ │ │ ├── PullToRefreshScrollView.java
│ │ │ ├── PullToRefreshHorizontalScrollView.java
│ │ │ ├── PullToRefreshWebView.java
│ │ │ ├── OverscrollHelper.java
│ │ │ ├── IPullToRefresh.java
│ │ │ ├── PullToRefreshListView.java
│ │ │ └── PullToRefreshAdapterViewBase.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── bettycc
│ │ └── animatepulltorefresh
│ │ └── library
│ │ └── ApplicationTest.java
├── build.gradle
└── proguard-rules.pro
├── settings.gradle
├── .gitignore
├── slide.gif
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.md
├── gradle.properties
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | .DS_Store
5 | /build
6 |
--------------------------------------------------------------------------------
/slide.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/slide.gif
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | My Module
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/assets/squirrel.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/app/src/main/assets/squirrel.gif
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/ok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/ok.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/loading.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/gif_loading1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/gif_loading1.gif
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/indicator_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-hdpi/indicator_arrow.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/indicator_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-mdpi/indicator_arrow.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/default_ptr_flip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-hdpi/default_ptr_flip.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/default_ptr_rotate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-hdpi/default_ptr_rotate.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/default_ptr_flip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-mdpi/default_ptr_flip.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-mdpi/default_ptr_rotate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-mdpi/default_ptr_rotate.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/default_ptr_flip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/default_ptr_flip.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_00.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_01.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_02.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_03.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_04.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_05.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_06.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_07.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_08.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_09.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_anim_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_anim_10.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/indicator_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/indicator_arrow.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/default_ptr_rotate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/default_ptr_rotate.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_loading_00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_loading_00.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_loading_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_loading_01.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/dropdown_loading_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ufo22940268/Android-AnimatePullToRefreshListView/HEAD/library/src/main/res/drawable-xhdpi/dropdown_loading_02.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #99cc00
4 | #33b5be
5 |
--------------------------------------------------------------------------------
/library/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AnimatePullToRefresh
5 | Hello world!
6 | Settings
7 |
8 |
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-zh/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 下拉刷新…
4 | 放开以刷新…
5 | 正在载入…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-ja/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 画面を引っ張って…
4 | 指を離して更新…
5 | 読み込み中…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-he/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | משוך לרענון…
4 | שחרר לרענון…
5 | טוען…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-iw/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | משוך לרענון…
4 | שחרר לרענון…
5 | טוען…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-ko/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 당겨서 새로 고침…
4 | 놓아서 새로 고침…
5 | 로드 중…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-ar/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | اسحب للتحديث…
4 | اترك للتحديث…
5 | تحميل…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-es/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Tirar para actualizar…
4 | Soltar para actualizar…
5 | Cargando…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-cs/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Tažením aktualizujete…
4 | Uvolněním aktualizujete…
5 | Načítání…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-de/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Ziehen zum Aktualisieren…
4 | Loslassen zum Aktualisieren…
5 | Laden…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-fr/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Tirez pour rafraîchir…
4 | Relâcher pour rafraîchir…
5 | Chargement…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-it/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Tira per aggiornare…
4 | Rilascia per aggionare…
5 | Caricamento…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-nl/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sleep om te vernieuwen…
4 | Loslaten om te vernieuwen…
5 | Laden…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-pl/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Pociągnij, aby odświeżyć…
4 | Puść, aby odświeżyć…
5 | Wczytywanie…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-pt-rBR/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Puxe para atualizar…
4 | Libere para atualizar…
5 | Carregando…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-pt/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Puxe para atualizar…
4 | Liberação para atualizar…
5 | A carregar…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values-ru/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Потяните для обновления…
4 | Отпустите для обновления…
5 | Загрузка…
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/my.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/library/src/main/res/values-ro/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Trage pentru a reîmprospăta…
4 | Eliberează pentru a reîmprospăta…
5 | Încărcare…
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 10dp
5 | 12dp
6 | 4dp
7 | 24dp
8 | 12dp
9 |
10 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/Utils.java:
--------------------------------------------------------------------------------
1 | package com.handmark.pulltorefresh.library.internal;
2 |
3 | import android.util.Log;
4 |
5 | public class Utils {
6 |
7 | static final String LOG_TAG = "PullToRefresh";
8 |
9 | public static void warnDeprecation(String depreacted, String replacement) {
10 | Log.w(LOG_TAG, "You're using the deprecated " + depreacted + " attr, please switch over to " + replacement);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/eating_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/bettycc/com/animatepulltorefresh/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package bettycc.com.animatepulltorefresh;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/squirrel_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/bettycc/animatepulltorefresh/library/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.bettycc.animatepulltorefresh.library;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_eating.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 19
5 | buildToolsVersion "19.1.0"
6 |
7 | defaultConfig {
8 | applicationId "bettycc.com.animatepulltorefresh"
9 | minSdkVersion 14
10 | targetSdkVersion 19
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | runProguard false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile project(':library')
25 | }
26 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/indicator_bg_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/indicator_bg_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 19
5 | buildToolsVersion "19.1.0"
6 |
7 | defaultConfig {
8 | applicationId "com.bettycc.animatepulltorefresh.library"
9 | minSdkVersion 9
10 | targetSdkVersion 19
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | runProguard false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'pl.droidsonroids.gif:android-gif-drawable:1.0.+'
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_squirrel.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/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/ccheng/program/adt-bundle-mac-x86_64-20130219/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 |
--------------------------------------------------------------------------------
/library/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/ccheng/program/adt-bundle-mac-x86_64-20130219/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 |
--------------------------------------------------------------------------------
/library/src/main/res/values/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pull to refresh…
5 | Release to refresh…
6 | Loading…
7 |
8 |
9 | @string/pull_to_refresh_pull_label
10 | @string/pull_to_refresh_release_label
11 | @string/pull_to_refresh_refreshing_label
12 |
13 |
--------------------------------------------------------------------------------
/library/src/main/res/values-fi/pull_refresh_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Päivitä vetämällä alas…
5 | Päivitä vapauttamalla…
6 | Päivitetään…
7 |
8 |
9 | Päivitä vetämällä ylös…
10 | @string/pull_to_refresh_release_label
11 | @string/pull_to_refresh_refreshing_label
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #AnimatePullToRefresh
2 |
3 | 这是一个各种下拉刷新动画的合集.项目是基于[chrisbanes的PullToRefresh](https://github.com/chrisbanes/Android-PullToRefresh)完成的。
4 |
5 | #吃包子动画
6 |
7 | 一个变拉边吃的listview, 动画师由多张图片切换完成的,模仿“大众点评”
8 |
9 | 
10 |
11 | ###使用方法
12 |
13 | 使用默认的chrisbanes的PullToRefresh即可.
14 |
15 | #自定义GIF动画
16 |
17 | 使用自己的gif文件作为动画。
18 |
19 | ### 使用方法
20 |
21 | 1. 把gif文件放到asset文件夹下.
22 | 2. 配置xml文件,加入gif文件名.
23 |
24 | ```xml
25 |
34 | ```
35 |
36 | #TODO
37 |
38 | 添加更多动画
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Settings specified in this file will override any Gradle settings
5 | # configured through the IDE.
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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/java/bettycc/com/animatepulltorefresh/MainActivity.java:
--------------------------------------------------------------------------------
1 | package bettycc.com.animatepulltorefresh;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 |
8 | /**
9 | * Created by ccheng on 8/4/14.
10 | */
11 | public class MainActivity extends Activity {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 | }
18 |
19 | public void onEating(View view) {
20 | launchItem(MyActivity.TYPE_EATING);
21 | }
22 |
23 | public void onSqurriel(View view) {
24 | launchItem(MyActivity.TYPE_SQUIRRIEL);
25 | }
26 |
27 | private void launchItem(int type) {
28 | Intent intent = new Intent(this, MyActivity.class);
29 | intent.putExtra("type", type);
30 | startActivity(intent);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/slide_out_to_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/slide_in_from_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/slide_in_from_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/slide_out_to_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/pull_to_refresh_header_horizontal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
18 |
19 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
21 |
22 |
34 |
35 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/GifAnimation.java:
--------------------------------------------------------------------------------
1 | package com.handmark.pulltorefresh.library.internal;
2 |
3 | import android.os.Handler;
4 | import android.os.Message;
5 | import android.widget.ImageView;
6 |
7 | /**
8 | * Created by ccheng on 8/4/14.
9 | */
10 | public class GifAnimation implements Handler.Callback {
11 |
12 | public static final int DELAY_MILLIS = 200;
13 | private final ImageView mHeaderImage;
14 | private final int[] mGifReses;
15 | private final Handler mHandler;
16 | private int mIndex;
17 | private boolean mStart;
18 |
19 | public GifAnimation(ImageView headerImage, int[] gifRes) {
20 | mHeaderImage = headerImage;
21 | mGifReses = gifRes;
22 |
23 | mHandler = new Handler(headerImage.getContext().getMainLooper(), this);
24 | }
25 |
26 | public void start() {
27 | if (!mStart) {
28 | mStart = true;
29 | mIndex = 0;
30 |
31 | nextImage();
32 | mHandler.sendEmptyMessageDelayed(0, DELAY_MILLIS);
33 | }
34 | }
35 |
36 | private void nextImage() {
37 | mHeaderImage.setImageResource(mGifReses[mIndex]);
38 | mIndex = (mIndex + 1) % 3;
39 | }
40 |
41 | @Override
42 | public boolean handleMessage(Message msg) {
43 | if (!mStart) {
44 | return true;
45 | }
46 |
47 | nextImage();
48 | mHandler.sendEmptyMessageDelayed(0, DELAY_MILLIS);
49 | return true;
50 | }
51 |
52 | public void stop() {
53 | mStart = false;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/EmptyViewMethodAccessor.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library.internal;
17 |
18 | import android.view.View;
19 |
20 | /**
21 | * Interface that allows PullToRefreshBase to hijack the call to
22 | * AdapterView.setEmptyView()
23 | *
24 | * @author chris
25 | */
26 | public interface EmptyViewMethodAccessor {
27 |
28 | /**
29 | * Calls upto AdapterView.setEmptyView()
30 | *
31 | * @param emptyView - to set as Empty View
32 | */
33 | public void setEmptyViewInternal(View emptyView);
34 |
35 | /**
36 | * Should call PullToRefreshBase.setEmptyView() which will then
37 | * automatically call through to setEmptyViewInternal()
38 | *
39 | * @param emptyView - to set as Empty View
40 | */
41 | public void setEmptyView(View emptyView);
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/ILoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.handmark.pulltorefresh.library;
2 |
3 | import android.graphics.Typeface;
4 | import android.graphics.drawable.Drawable;
5 |
6 | public interface ILoadingLayout {
7 |
8 | /**
9 | * Set the Last Updated Text. This displayed under the main label when
10 | * Pulling
11 | *
12 | * @param label - Label to set
13 | */
14 | public void setLastUpdatedLabel(CharSequence label);
15 |
16 | /**
17 | * Set the drawable used in the loading layout. This is the same as calling
18 | * setLoadingDrawable(drawable, Mode.BOTH)
19 | *
20 | * @param drawable - Drawable to display
21 | */
22 | public void setLoadingDrawable(Drawable drawable);
23 |
24 | /**
25 | * Set Text to show when the Widget is being Pulled
26 | * setPullLabel(releaseLabel, Mode.BOTH)
27 | *
28 | * @param pullLabel - CharSequence to display
29 | */
30 | public void setPullLabel(CharSequence pullLabel);
31 |
32 | /**
33 | * Set Text to show when the Widget is refreshing
34 | * setRefreshingLabel(releaseLabel, Mode.BOTH)
35 | *
36 | * @param refreshingLabel - CharSequence to display
37 | */
38 | public void setRefreshingLabel(CharSequence refreshingLabel);
39 |
40 | /**
41 | * Set Text to show when the Widget is being pulled, and will refresh when
42 | * released. This is the same as calling
43 | * setReleaseLabel(releaseLabel, Mode.BOTH)
44 | *
45 | * @param releaseLabel - CharSequence to display
46 | */
47 | public void setReleaseLabel(CharSequence releaseLabel);
48 |
49 | /**
50 | * Set's the Sets the typeface and style in which the text should be
51 | * displayed. Please see
52 | * {@link android.widget.TextView#setTypeface(Typeface)
53 | * TextView#setTypeface(Typeface)}.
54 | */
55 | public void setTextTypeface(Typeface tf);
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/LoadingLayoutProxy.java:
--------------------------------------------------------------------------------
1 | package com.handmark.pulltorefresh.library;
2 |
3 | import android.graphics.Typeface;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import com.handmark.pulltorefresh.library.internal.LoadingLayout;
7 |
8 | import java.util.HashSet;
9 |
10 | public class LoadingLayoutProxy implements ILoadingLayout {
11 |
12 | private final HashSet mLoadingLayouts;
13 |
14 | LoadingLayoutProxy() {
15 | mLoadingLayouts = new HashSet();
16 | }
17 |
18 | /**
19 | * This allows you to add extra LoadingLayout instances to this proxy. This
20 | * is only necessary if you keep your own instances, and want to have them
21 | * included in any
22 | * {@link PullToRefreshBase#createLoadingLayoutProxy(boolean, boolean)
23 | * createLoadingLayoutProxy(...)} calls.
24 | *
25 | * @param layout - LoadingLayout to have included.
26 | */
27 | public void addLayout(LoadingLayout layout) {
28 | if (null != layout) {
29 | mLoadingLayouts.add(layout);
30 | }
31 | }
32 |
33 | @Override
34 | public void setLastUpdatedLabel(CharSequence label) {
35 | for (LoadingLayout layout : mLoadingLayouts) {
36 | layout.setLastUpdatedLabel(label);
37 | }
38 | }
39 |
40 | @Override
41 | public void setLoadingDrawable(Drawable drawable) {
42 | for (LoadingLayout layout : mLoadingLayouts) {
43 | layout.setLoadingDrawable(drawable);
44 | }
45 | }
46 |
47 | @Override
48 | public void setRefreshingLabel(CharSequence refreshingLabel) {
49 | for (LoadingLayout layout : mLoadingLayouts) {
50 | layout.setRefreshingLabel(refreshingLabel);
51 | }
52 | }
53 |
54 | @Override
55 | public void setPullLabel(CharSequence label) {
56 | for (LoadingLayout layout : mLoadingLayouts) {
57 | layout.setPullLabel(label);
58 | }
59 | }
60 |
61 | @Override
62 | public void setReleaseLabel(CharSequence label) {
63 | for (LoadingLayout layout : mLoadingLayouts) {
64 | layout.setReleaseLabel(label);
65 | }
66 | }
67 |
68 | public void setTextTypeface(Typeface tf) {
69 | for (LoadingLayout layout : mLoadingLayouts) {
70 | layout.setTextTypeface(tf);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/ViewCompat.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library.internal;
17 |
18 | import android.annotation.TargetApi;
19 | import android.graphics.drawable.Drawable;
20 | import android.os.Build.VERSION;
21 | import android.os.Build.VERSION_CODES;
22 | import android.view.View;
23 |
24 | @SuppressWarnings("deprecation")
25 | public class ViewCompat {
26 |
27 | public static void postOnAnimation(View view, Runnable runnable) {
28 | if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
29 | SDK16.postOnAnimation(view, runnable);
30 | } else {
31 | view.postDelayed(runnable, 16);
32 | }
33 | }
34 |
35 | public static void setBackground(View view, Drawable background) {
36 | if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
37 | SDK16.setBackground(view, background);
38 | } else {
39 | view.setBackgroundDrawable(background);
40 | }
41 | }
42 |
43 | public static void setLayerType(View view, int layerType) {
44 | if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
45 | SDK11.setLayerType(view, layerType);
46 | }
47 | }
48 |
49 | @TargetApi(11)
50 | static class SDK11 {
51 |
52 | public static void setLayerType(View view, int layerType) {
53 | view.setLayerType(layerType, null);
54 | }
55 | }
56 |
57 | @TargetApi(16)
58 | static class SDK16 {
59 |
60 | public static void postOnAnimation(View view, Runnable runnable) {
61 | view.postOnAnimation(runnable);
62 | }
63 |
64 | public static void setBackground(View view, Drawable background) {
65 | view.setBackground(background);
66 | }
67 |
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/pull_to_refresh_header_vertical.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
18 |
19 |
24 |
25 |
33 |
34 |
41 |
42 |
43 |
44 |
51 |
52 |
59 |
60 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/extras/SoundPullEventListener.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library.extras;
17 |
18 | import android.content.Context;
19 | import android.media.MediaPlayer;
20 | import android.view.View;
21 |
22 | import com.handmark.pulltorefresh.library.PullToRefreshBase;
23 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
24 | import com.handmark.pulltorefresh.library.PullToRefreshBase.State;
25 |
26 | import java.util.HashMap;
27 |
28 | public class SoundPullEventListener implements PullToRefreshBase.OnPullEventListener {
29 |
30 | private final Context mContext;
31 | private final HashMap mSoundMap;
32 |
33 | private MediaPlayer mCurrentMediaPlayer;
34 |
35 | /**
36 | * Constructor
37 | *
38 | * @param context - Context
39 | */
40 | public SoundPullEventListener(Context context) {
41 | mContext = context;
42 | mSoundMap = new HashMap();
43 | }
44 |
45 | @Override
46 | public final void onPullEvent(PullToRefreshBase refreshView, State event, Mode direction) {
47 | Integer soundResIdObj = mSoundMap.get(event);
48 | if (null != soundResIdObj) {
49 | playSound(soundResIdObj.intValue());
50 | }
51 | }
52 |
53 | /**
54 | * Set the Sounds to be played when a Pull Event happens. You specify which
55 | * sound plays for which events by calling this method multiple times for
56 | * each event.
57 | *
58 | * If you've already set a sound for a certain event, and add another sound
59 | * for that event, only the new sound will be played.
60 | *
61 | * @param event - The event for which the sound will be played.
62 | * @param resId - Resource Id of the sound file to be played (e.g.
63 | * R.raw.pull_sound)
64 | */
65 | public void addSoundEvent(State event, int resId) {
66 | mSoundMap.put(event, resId);
67 | }
68 |
69 | /**
70 | * Clears all of the previously set sounds and events.
71 | */
72 | public void clearSounds() {
73 | mSoundMap.clear();
74 | }
75 |
76 | /**
77 | * Gets the current (or last) MediaPlayer instance.
78 | */
79 | public MediaPlayer getCurrentMediaPlayer() {
80 | return mCurrentMediaPlayer;
81 | }
82 |
83 | private void playSound(int resId) {
84 | // Stop current player, if there's one playing
85 | if (null != mCurrentMediaPlayer) {
86 | mCurrentMediaPlayer.stop();
87 | mCurrentMediaPlayer.release();
88 | }
89 |
90 | mCurrentMediaPlayer = MediaPlayer.create(mContext, resId);
91 | if (null != mCurrentMediaPlayer) {
92 | mCurrentMediaPlayer.start();
93 | }
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/PullToRefreshGridView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.os.Build.VERSION;
21 | import android.os.Build.VERSION_CODES;
22 | import android.util.AttributeSet;
23 | import android.view.View;
24 | import android.widget.GridView;
25 |
26 | import com.bettycc.animatepulltorefresh.library.R;
27 | import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor;
28 |
29 | public class PullToRefreshGridView extends PullToRefreshAdapterViewBase {
30 |
31 | public PullToRefreshGridView(Context context) {
32 | super(context);
33 | }
34 |
35 | public PullToRefreshGridView(Context context, AttributeSet attrs) {
36 | super(context, attrs);
37 | }
38 |
39 | public PullToRefreshGridView(Context context, Mode mode) {
40 | super(context, mode);
41 | }
42 |
43 | public PullToRefreshGridView(Context context, Mode mode, AnimationStyle style) {
44 | super(context, mode, style);
45 | }
46 |
47 | @Override
48 | public final Orientation getPullToRefreshScrollDirection() {
49 | return Orientation.VERTICAL;
50 | }
51 |
52 | @Override
53 | protected final GridView createRefreshableView(Context context, AttributeSet attrs) {
54 | final GridView gv;
55 | if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
56 | gv = new InternalGridViewSDK9(context, attrs);
57 | } else {
58 | gv = new InternalGridView(context, attrs);
59 | }
60 |
61 | // Use Generated ID (from res/values/ids.xml)
62 | gv.setId(R.id.gridview);
63 | return gv;
64 | }
65 |
66 | class InternalGridView extends GridView implements EmptyViewMethodAccessor {
67 |
68 | public InternalGridView(Context context, AttributeSet attrs) {
69 | super(context, attrs);
70 | }
71 |
72 | @Override
73 | public void setEmptyView(View emptyView) {
74 | PullToRefreshGridView.this.setEmptyView(emptyView);
75 | }
76 |
77 | @Override
78 | public void setEmptyViewInternal(View emptyView) {
79 | super.setEmptyView(emptyView);
80 | }
81 | }
82 |
83 | @TargetApi(9)
84 | final class InternalGridViewSDK9 extends InternalGridView {
85 |
86 | public InternalGridViewSDK9(Context context, AttributeSet attrs) {
87 | super(context, attrs);
88 | }
89 |
90 | @Override
91 | protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
92 | int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
93 |
94 | final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
95 | scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
96 |
97 | // Does all of the hard work...
98 | OverscrollHelper.overScrollBy(PullToRefreshGridView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent);
99 |
100 | return returnValue;
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/GifLoadingLayout.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library.internal;
17 |
18 | import android.content.Context;
19 | import android.content.res.TypedArray;
20 | import android.graphics.Matrix;
21 | import android.graphics.drawable.Drawable;
22 | import android.widget.ImageView.ScaleType;
23 |
24 | import com.bettycc.animatepulltorefresh.library.R;
25 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
26 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
27 |
28 | import java.io.IOException;
29 |
30 | import pl.droidsonroids.gif.GifDrawable;
31 |
32 | public class GifLoadingLayout extends LoadingLayout {
33 |
34 | static final int ROTATION_ANIMATION_DURATION = 1200;
35 |
36 | private final Matrix mHeaderImageMatrix;
37 |
38 | private final boolean mRotateDrawableWhilePulling;
39 | private GifAnimation mGifAnimation;
40 |
41 | private int[] mGifRes = {
42 | R.drawable.dropdown_loading_00,
43 | R.drawable.dropdown_loading_01,
44 | R.drawable.dropdown_loading_02,
45 | };
46 |
47 | private GifDrawable mGifDrawable;
48 | private final String mAssetFile;
49 |
50 | public GifLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) {
51 | super(context, mode, scrollDirection, attrs);
52 |
53 | mRotateDrawableWhilePulling = attrs.getBoolean(R.styleable.PullToRefresh_ptrRotateDrawableWhilePulling, true);
54 | mAssetFile = attrs.getString(R.styleable.PullToRefresh_ptrGifAsset);
55 |
56 | mHeaderImage.setScaleType(ScaleType.MATRIX);
57 | mHeaderImageMatrix = new Matrix();
58 | mHeaderImage.setImageMatrix(mHeaderImageMatrix);
59 | try {
60 | mGifDrawable = new GifDrawable(context.getAssets(), mAssetFile);
61 | mHeaderImage.setImageDrawable(mGifDrawable);
62 | } catch (IOException e) {
63 | e.printStackTrace();
64 | }
65 | }
66 |
67 | public void onLoadingDrawableSet(Drawable imageDrawable) {
68 | }
69 |
70 | int mPrevIndex = -1;
71 | protected void onPullImpl(float scaleOfLayout) {
72 | if (mPrevIndex == -1 && scaleOfLayout > 0.3) {
73 | mGifDrawable.pause();
74 | mPrevIndex = 0;
75 | }
76 | }
77 |
78 | @Override
79 | protected void refreshingImpl() {
80 | if (!mGifDrawable.isPlaying()) {
81 | mGifDrawable.start();
82 | }
83 | }
84 |
85 | @Override
86 | protected void resetImpl() {
87 | pauseGif();
88 | }
89 |
90 | private void pauseGif() {
91 | if (mGifDrawable != null && mGifDrawable.isPlaying()) {
92 | mGifDrawable.pause();
93 | }
94 | }
95 |
96 | @Override
97 | protected void pullToRefreshImpl() {
98 | // NO-OP
99 | }
100 |
101 | @Override
102 | protected void releaseToRefreshImpl() {
103 | // NO-OP
104 | }
105 |
106 | @Override
107 | protected int getDefaultDrawableResId() {
108 | return R.drawable.default_ptr_rotate;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/PullToRefreshExpandableListView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.os.Build.VERSION;
21 | import android.os.Build.VERSION_CODES;
22 | import android.util.AttributeSet;
23 | import android.view.View;
24 | import android.widget.ExpandableListView;
25 |
26 | import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor;
27 |
28 | public class PullToRefreshExpandableListView extends PullToRefreshAdapterViewBase {
29 |
30 | public PullToRefreshExpandableListView(Context context) {
31 | super(context);
32 | }
33 |
34 | public PullToRefreshExpandableListView(Context context, AttributeSet attrs) {
35 | super(context, attrs);
36 | }
37 |
38 | public PullToRefreshExpandableListView(Context context, Mode mode) {
39 | super(context, mode);
40 | }
41 |
42 | public PullToRefreshExpandableListView(Context context, Mode mode, AnimationStyle style) {
43 | super(context, mode, style);
44 | }
45 |
46 | @Override
47 | public final Orientation getPullToRefreshScrollDirection() {
48 | return Orientation.VERTICAL;
49 | }
50 |
51 | @Override
52 | protected ExpandableListView createRefreshableView(Context context, AttributeSet attrs) {
53 | final ExpandableListView lv;
54 | if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
55 | lv = new InternalExpandableListViewSDK9(context, attrs);
56 | } else {
57 | lv = new InternalExpandableListView(context, attrs);
58 | }
59 |
60 | // Set it to this so it can be used in ListActivity/ListFragment
61 | lv.setId(android.R.id.list);
62 | return lv;
63 | }
64 |
65 | class InternalExpandableListView extends ExpandableListView implements EmptyViewMethodAccessor {
66 |
67 | public InternalExpandableListView(Context context, AttributeSet attrs) {
68 | super(context, attrs);
69 | }
70 |
71 | @Override
72 | public void setEmptyView(View emptyView) {
73 | PullToRefreshExpandableListView.this.setEmptyView(emptyView);
74 | }
75 |
76 | @Override
77 | public void setEmptyViewInternal(View emptyView) {
78 | super.setEmptyView(emptyView);
79 | }
80 | }
81 |
82 | @TargetApi(9)
83 | final class InternalExpandableListViewSDK9 extends InternalExpandableListView {
84 |
85 | public InternalExpandableListViewSDK9(Context context, AttributeSet attrs) {
86 | super(context, attrs);
87 | }
88 |
89 | @Override
90 | protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
91 | int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
92 |
93 | final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
94 | scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
95 |
96 | // Does all of the hard work...
97 | OverscrollHelper.overScrollBy(PullToRefreshExpandableListView.this, deltaX, scrollX, deltaY, scrollY,
98 | isTouchEvent);
99 |
100 | return returnValue;
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/library/src/main/res/values/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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
69 |
70 |
71 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/PullToRefreshScrollView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.os.Build.VERSION;
21 | import android.os.Build.VERSION_CODES;
22 | import android.util.AttributeSet;
23 | import android.view.View;
24 | import android.widget.ScrollView;
25 |
26 | import com.bettycc.animatepulltorefresh.library.R;
27 |
28 | public class PullToRefreshScrollView extends PullToRefreshBase {
29 |
30 | public PullToRefreshScrollView(Context context) {
31 | super(context);
32 | }
33 |
34 | public PullToRefreshScrollView(Context context, AttributeSet attrs) {
35 | super(context, attrs);
36 | }
37 |
38 | public PullToRefreshScrollView(Context context, Mode mode) {
39 | super(context, mode);
40 | }
41 |
42 | public PullToRefreshScrollView(Context context, Mode mode, AnimationStyle style) {
43 | super(context, mode, style);
44 | }
45 |
46 | @Override
47 | public final Orientation getPullToRefreshScrollDirection() {
48 | return Orientation.VERTICAL;
49 | }
50 |
51 | @Override
52 | protected ScrollView createRefreshableView(Context context, AttributeSet attrs) {
53 | ScrollView scrollView;
54 | if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
55 | scrollView = new InternalScrollViewSDK9(context, attrs);
56 | } else {
57 | scrollView = new ScrollView(context, attrs);
58 | }
59 |
60 | scrollView.setId(R.id.scrollview);
61 | return scrollView;
62 | }
63 |
64 | @Override
65 | protected boolean isReadyForPullStart() {
66 | return mRefreshableView.getScrollY() == 0;
67 | }
68 |
69 | @Override
70 | protected boolean isReadyForPullEnd() {
71 | View scrollViewChild = mRefreshableView.getChildAt(0);
72 | if (null != scrollViewChild) {
73 | return mRefreshableView.getScrollY() >= (scrollViewChild.getHeight() - getHeight());
74 | }
75 | return false;
76 | }
77 |
78 | @TargetApi(9)
79 | final class InternalScrollViewSDK9 extends ScrollView {
80 |
81 | public InternalScrollViewSDK9(Context context, AttributeSet attrs) {
82 | super(context, attrs);
83 | }
84 |
85 | @Override
86 | protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
87 | int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
88 |
89 | final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
90 | scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
91 |
92 | // Does all of the hard work...
93 | OverscrollHelper.overScrollBy(PullToRefreshScrollView.this, deltaX, scrollX, deltaY, scrollY,
94 | getScrollRange(), isTouchEvent);
95 |
96 | return returnValue;
97 | }
98 |
99 | /**
100 | * Taken from the AOSP ScrollView source
101 | */
102 | private int getScrollRange() {
103 | int scrollRange = 0;
104 | if (getChildCount() > 0) {
105 | View child = getChildAt(0);
106 | scrollRange = Math.max(0, child.getHeight() - (getHeight() - getPaddingBottom() - getPaddingTop()));
107 | }
108 | return scrollRange;
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/PullToRefreshHorizontalScrollView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.os.Build.VERSION;
21 | import android.os.Build.VERSION_CODES;
22 | import android.util.AttributeSet;
23 | import android.view.View;
24 | import android.widget.HorizontalScrollView;
25 |
26 | import com.bettycc.animatepulltorefresh.library.R;
27 |
28 | public class PullToRefreshHorizontalScrollView extends PullToRefreshBase {
29 |
30 | public PullToRefreshHorizontalScrollView(Context context) {
31 | super(context);
32 | }
33 |
34 | public PullToRefreshHorizontalScrollView(Context context, AttributeSet attrs) {
35 | super(context, attrs);
36 | }
37 |
38 | public PullToRefreshHorizontalScrollView(Context context, Mode mode) {
39 | super(context, mode);
40 | }
41 |
42 | public PullToRefreshHorizontalScrollView(Context context, Mode mode, AnimationStyle style) {
43 | super(context, mode, style);
44 | }
45 |
46 | @Override
47 | public final Orientation getPullToRefreshScrollDirection() {
48 | return Orientation.HORIZONTAL;
49 | }
50 |
51 | @Override
52 | protected HorizontalScrollView createRefreshableView(Context context, AttributeSet attrs) {
53 | HorizontalScrollView scrollView;
54 |
55 | if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
56 | scrollView = new InternalHorizontalScrollViewSDK9(context, attrs);
57 | } else {
58 | scrollView = new HorizontalScrollView(context, attrs);
59 | }
60 |
61 | scrollView.setId(R.id.scrollview);
62 | return scrollView;
63 | }
64 |
65 | @Override
66 | protected boolean isReadyForPullStart() {
67 | return mRefreshableView.getScrollX() == 0;
68 | }
69 |
70 | @Override
71 | protected boolean isReadyForPullEnd() {
72 | View scrollViewChild = mRefreshableView.getChildAt(0);
73 | if (null != scrollViewChild) {
74 | return mRefreshableView.getScrollX() >= (scrollViewChild.getWidth() - getWidth());
75 | }
76 | return false;
77 | }
78 |
79 | @TargetApi(9)
80 | final class InternalHorizontalScrollViewSDK9 extends HorizontalScrollView {
81 |
82 | public InternalHorizontalScrollViewSDK9(Context context, AttributeSet attrs) {
83 | super(context, attrs);
84 | }
85 |
86 | @Override
87 | protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
88 | int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
89 |
90 | final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
91 | scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
92 |
93 | // Does all of the hard work...
94 | OverscrollHelper.overScrollBy(PullToRefreshHorizontalScrollView.this, deltaX, scrollX, deltaY, scrollY,
95 | getScrollRange(), isTouchEvent);
96 |
97 | return returnValue;
98 | }
99 |
100 | /**
101 | * Taken from the AOSP ScrollView source
102 | */
103 | private int getScrollRange() {
104 | int scrollRange = 0;
105 | if (getChildCount() > 0) {
106 | View child = getChildAt(0);
107 | scrollRange = Math.max(0, child.getWidth() - (getWidth() - getPaddingLeft() - getPaddingRight()));
108 | }
109 | return scrollRange;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/RotateLoadingLayout.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library.internal;
17 |
18 | import android.content.Context;
19 | import android.content.res.TypedArray;
20 | import android.graphics.Bitmap;
21 | import android.graphics.BitmapFactory;
22 | import android.graphics.Matrix;
23 | import android.graphics.drawable.Drawable;
24 | import android.widget.ImageView.ScaleType;
25 |
26 | import com.bettycc.animatepulltorefresh.library.R;
27 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
28 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
29 |
30 |
31 | public class RotateLoadingLayout extends LoadingLayout {
32 |
33 | static final int ROTATION_ANIMATION_DURATION = 1200;
34 |
35 | private final Matrix mHeaderImageMatrix;
36 |
37 | private float mRotationPivotX, mRotationPivotY;
38 |
39 | private final boolean mRotateDrawableWhilePulling;
40 | private GifAnimation mGifAnimation;
41 |
42 | private int[] mGifRes = {
43 | R.drawable.dropdown_loading_00,
44 | R.drawable.dropdown_loading_01,
45 | R.drawable.dropdown_loading_02,
46 | };
47 |
48 | public RotateLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) {
49 | super(context, mode, scrollDirection, attrs);
50 |
51 | mRotateDrawableWhilePulling = attrs.getBoolean(R.styleable.PullToRefresh_ptrRotateDrawableWhilePulling, true);
52 |
53 | mHeaderImage.setScaleType(ScaleType.MATRIX);
54 | mHeaderImageMatrix = new Matrix();
55 | mHeaderImage.setImageMatrix(mHeaderImageMatrix);
56 | }
57 |
58 | public void onLoadingDrawableSet(Drawable imageDrawable) {
59 | System.out.println("RotateLoadingLayout.onLoadingDrawableSet");
60 | if (null != imageDrawable) {
61 | mRotationPivotX = Math.round(imageDrawable.getIntrinsicWidth() / 2f);
62 | mRotationPivotY = Math.round(imageDrawable.getIntrinsicHeight() / 2f);
63 | }
64 | }
65 |
66 | int mPrevIndex = -1;
67 | protected void onPullImpl(float scaleOfLayout) {
68 | float angle;
69 | if (mRotateDrawableWhilePulling) {
70 | angle = scaleOfLayout * 90f;
71 | } else {
72 | angle = Math.max(0f, Math.min(180f, scaleOfLayout * 360f - 180f));
73 | }
74 |
75 | float max = 1.7f;
76 | int index = (int) (scaleOfLayout / 1f * 10);
77 | if (index == mPrevIndex) {
78 | return;
79 | } else {
80 | if (index > 10) {
81 | index = 10;
82 | }
83 | int res = getResources().getIdentifier(String.format("dropdown_anim_%02d",
84 | index), "drawable", getContext().getPackageName());
85 | // Bitmap scaledBitmap = getScaledBitmap(res, index);
86 | // mHeaderImage.setImageBitmap(scaledBitmap);
87 | mHeaderImage.setImageResource(res);
88 | mPrevIndex = index;
89 | }
90 | }
91 |
92 | private Bitmap getScaledBitmap(int res, int index) {
93 | float p = ((float) index/10*7 + 3)/10;
94 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), res);
95 | return Bitmap.createScaledBitmap(bitmap, (int)(mHeaderImage.getWidth()*p), (int)(mHeaderImage.getHeight()*p), false);
96 | }
97 |
98 | @Override
99 | protected void refreshingImpl() {
100 | if (mGifAnimation == null) {
101 | mGifAnimation = new GifAnimation(mHeaderImage, mGifRes);
102 | }
103 | mGifAnimation.start();
104 | }
105 |
106 | @Override
107 | protected void resetImpl() {
108 | mHeaderImage.clearAnimation();
109 | if (mGifAnimation != null) {
110 | mGifAnimation.stop();
111 | }
112 | }
113 |
114 | @Override
115 | protected void pullToRefreshImpl() {
116 | // NO-OP
117 | }
118 |
119 | @Override
120 | protected void releaseToRefreshImpl() {
121 | // NO-OP
122 | }
123 |
124 | @Override
125 | protected int getDefaultDrawableResId() {
126 | return R.drawable.default_ptr_rotate;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/bettycc/com/animatepulltorefresh/MyActivity.java:
--------------------------------------------------------------------------------
1 | package bettycc.com.animatepulltorefresh;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 | import android.os.Bundle;
7 | import android.view.Menu;
8 | import android.view.MenuItem;
9 | import android.widget.ArrayAdapter;
10 | import android.widget.ListView;
11 |
12 | import com.handmark.pulltorefresh.library.PullToRefreshBase;
13 | import com.handmark.pulltorefresh.library.PullToRefreshListView;
14 |
15 |
16 | public class MyActivity extends Activity {
17 |
18 | public static final int TYPE_EATING = 0;
19 | public static final int TYPE_SQUIRRIEL = 1;
20 |
21 | private PullToRefreshListView mRefreshListView;
22 | private ListView mListView;
23 | private String[] mDemoStrs = new String[]{
24 | "妈妈",
25 | "再也",
26 | "不用",
27 | "担心我的列",
28 | "表没有",
29 | "动画",
30 | "了",
31 | };
32 | private int mType;
33 | private ResourceChooser mRc;
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | mType = getIntent().getIntExtra("type", TYPE_EATING);
39 | mRc = new ResourceChooser(this, mType);
40 | setContentView(mRc.getMainLayout());
41 | mRefreshListView = (PullToRefreshListView) findViewById(R.id.pull_to_refresh_listview);
42 | mListView = mRefreshListView.getRefreshableView();
43 | ArrayAdapter adapter = new ArrayAdapter(this, mRc.getItemLayout(), mDemoStrs);
44 | mListView.setAdapter(adapter);
45 | mRefreshListView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2() {
46 | @Override
47 | public void onPullDownToRefresh(PullToRefreshBase refreshView) {
48 | new Thread(new Runnable() {
49 | @Override
50 | public void run() {
51 | try {
52 | Thread.sleep(3000);
53 | runOnUiThread(new Runnable() {
54 | @Override
55 | public void run() {
56 | mRefreshListView.onRefreshComplete();
57 | }
58 | });
59 | } catch (InterruptedException e) {
60 | e.printStackTrace();
61 | }
62 | }
63 | }).start();
64 | }
65 |
66 | @Override
67 | public void onPullUpToRefresh(PullToRefreshBase refreshView) {
68 |
69 | }
70 | });
71 | }
72 |
73 |
74 | @Override
75 | public boolean onCreateOptionsMenu(Menu menu) {
76 | // Inflate the menu; this adds items to the action bar if it is present.
77 | getMenuInflater().inflate(R.menu.my, menu);
78 | return true;
79 | }
80 |
81 | @Override
82 | public boolean onOptionsItemSelected(MenuItem item) {
83 | // Handle action bar item clicks here. The action bar will
84 | // automatically handle clicks on the Home/Up button, so long
85 | // as you specify a parent activity in AndroidManifest.xml.
86 | int id = item.getItemId();
87 | if (id == R.id.action_settings) {
88 | return true;
89 | }
90 | return super.onOptionsItemSelected(item);
91 | }
92 |
93 | private static class ResourceChooser {
94 | private final Resources mRes;
95 | private Context mContext;
96 | private int mType;
97 |
98 | public ResourceChooser(Context context, int type) {
99 | mContext = context;
100 | mType = type;
101 | mRes = mContext.getResources();
102 | }
103 |
104 | private int getMainLayout() {
105 | int layout;
106 | switch (mType) {
107 | case TYPE_EATING:
108 | default:
109 | layout = R.layout.activity_eating;
110 | break;
111 |
112 | case TYPE_SQUIRRIEL:
113 | layout = R.layout.activity_squirrel;
114 | break;
115 | }
116 | return layout;
117 | }
118 |
119 | private int getItemLayout() {
120 | int layout;
121 | switch (mType) {
122 | case TYPE_EATING:
123 | default:
124 | layout = R.layout.eating_item;
125 | break;
126 |
127 | case TYPE_SQUIRRIEL:
128 | layout = R.layout.squirrel_item;
129 | break;
130 | }
131 | return layout;
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/extras/PullToRefreshWebView2.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 |
17 | package com.handmark.pulltorefresh.library.extras;
18 |
19 | import android.content.Context;
20 | import android.util.AttributeSet;
21 | import android.webkit.WebView;
22 |
23 | import com.handmark.pulltorefresh.library.PullToRefreshWebView;
24 |
25 | import java.util.concurrent.atomic.AtomicBoolean;
26 |
27 | /**
28 | * An advanced version of {@link PullToRefreshWebView} which delegates the
29 | * triggering of the PullToRefresh gesture to the Javascript running within the
30 | * WebView. This means that you should only use this class if:
31 | *
32 | *
33 | * - {@link PullToRefreshWebView} doesn't work correctly because you're using
34 | *
overflow:scroll or something else which means
35 | * {@link WebView#getScrollY()} doesn't return correct values.
36 | * - You control the web content being displayed, as you need to write some
37 | * Javascript callbacks.
38 | *
39 | *
40 | *
41 | * The way this call works is that when a PullToRefresh gesture is in action,
42 | * the following Javascript methods will be called:
43 | * isReadyForPullDown() and isReadyForPullUp(), it is
44 | * your job to calculate whether the view is in a state where a PullToRefresh
45 | * can happen, and return the result via the callback mechanism. An example can
46 | * be seen below:
47 | *
48 | *
49 | *
50 | * function isReadyForPullDown() {
51 | * var result = ... // Probably using the .scrollTop DOM attribute
52 | * ptr.isReadyForPullDownResponse(result);
53 | * }
54 | *
55 | * function isReadyForPullUp() {
56 | * var result = ... // Probably using the .scrollBottom DOM attribute
57 | * ptr.isReadyForPullUpResponse(result);
58 | * }
59 | *
60 | *
61 | * @author Chris Banes
62 | */
63 | public class PullToRefreshWebView2 extends PullToRefreshWebView {
64 |
65 | static final String JS_INTERFACE_PKG = "ptr";
66 | static final String DEF_JS_READY_PULL_DOWN_CALL = "javascript:isReadyForPullDown();";
67 | static final String DEF_JS_READY_PULL_UP_CALL = "javascript:isReadyForPullUp();";
68 |
69 | public PullToRefreshWebView2(Context context) {
70 | super(context);
71 | }
72 |
73 | public PullToRefreshWebView2(Context context, AttributeSet attrs) {
74 | super(context, attrs);
75 | }
76 |
77 | public PullToRefreshWebView2(Context context, Mode mode) {
78 | super(context, mode);
79 | }
80 |
81 | private JsValueCallback mJsCallback;
82 | private final AtomicBoolean mIsReadyForPullDown = new AtomicBoolean(false);
83 | private final AtomicBoolean mIsReadyForPullUp = new AtomicBoolean(false);
84 |
85 | @Override
86 | protected WebView createRefreshableView(Context context, AttributeSet attrs) {
87 | WebView webView = super.createRefreshableView(context, attrs);
88 |
89 | // Need to add JS Interface so we can get the response back
90 | mJsCallback = new JsValueCallback();
91 | webView.addJavascriptInterface(mJsCallback, JS_INTERFACE_PKG);
92 |
93 | return webView;
94 | }
95 |
96 | @Override
97 | protected boolean isReadyForPullStart() {
98 | // Call Javascript...
99 | getRefreshableView().loadUrl(DEF_JS_READY_PULL_DOWN_CALL);
100 |
101 | // Response will be given to JsValueCallback, which will update
102 | // mIsReadyForPullDown
103 |
104 | return mIsReadyForPullDown.get();
105 | }
106 |
107 | @Override
108 | protected boolean isReadyForPullEnd() {
109 | // Call Javascript...
110 | getRefreshableView().loadUrl(DEF_JS_READY_PULL_UP_CALL);
111 |
112 | // Response will be given to JsValueCallback, which will update
113 | // mIsReadyForPullUp
114 |
115 | return mIsReadyForPullUp.get();
116 | }
117 |
118 | /**
119 | * Used for response from Javascript
120 | *
121 | * @author Chris Banes
122 | */
123 | final class JsValueCallback {
124 |
125 | public void isReadyForPullUpResponse(boolean response) {
126 | mIsReadyForPullUp.set(response);
127 | }
128 |
129 | public void isReadyForPullDownResponse(boolean response) {
130 | mIsReadyForPullDown.set(response);
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/FlipLoadingLayout.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library.internal;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.content.Context;
20 | import android.content.res.TypedArray;
21 | import android.graphics.Matrix;
22 | import android.graphics.drawable.Drawable;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 | import android.view.animation.Animation;
26 | import android.view.animation.RotateAnimation;
27 | import android.widget.ImageView.ScaleType;
28 |
29 | import com.bettycc.animatepulltorefresh.library.R;
30 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
31 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
32 |
33 | ;
34 |
35 | @SuppressLint("ViewConstructor")
36 | public class FlipLoadingLayout extends LoadingLayout {
37 |
38 | static final int FLIP_ANIMATION_DURATION = 150;
39 |
40 | private final Animation mRotateAnimation, mResetRotateAnimation;
41 |
42 | public FlipLoadingLayout(Context context, final Mode mode, final Orientation scrollDirection, TypedArray attrs) {
43 | super(context, mode, scrollDirection, attrs);
44 |
45 | final int rotateAngle = mode == Mode.PULL_FROM_START ? -180 : 180;
46 |
47 | mRotateAnimation = new RotateAnimation(0, rotateAngle, Animation.RELATIVE_TO_SELF, 0.5f,
48 | Animation.RELATIVE_TO_SELF, 0.5f);
49 | mRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR);
50 | mRotateAnimation.setDuration(FLIP_ANIMATION_DURATION);
51 | mRotateAnimation.setFillAfter(true);
52 |
53 | mResetRotateAnimation = new RotateAnimation(rotateAngle, 0, Animation.RELATIVE_TO_SELF, 0.5f,
54 | Animation.RELATIVE_TO_SELF, 0.5f);
55 | mResetRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR);
56 | mResetRotateAnimation.setDuration(FLIP_ANIMATION_DURATION);
57 | mResetRotateAnimation.setFillAfter(true);
58 | }
59 |
60 | @Override
61 | protected void onLoadingDrawableSet(Drawable imageDrawable) {
62 | if (null != imageDrawable) {
63 | final int dHeight = imageDrawable.getIntrinsicHeight();
64 | final int dWidth = imageDrawable.getIntrinsicWidth();
65 |
66 | /**
67 | * We need to set the width/height of the ImageView so that it is
68 | * square with each side the size of the largest drawable dimension.
69 | * This is so that it doesn't clip when rotated.
70 | */
71 | ViewGroup.LayoutParams lp = mHeaderImage.getLayoutParams();
72 | lp.width = lp.height = Math.max(dHeight, dWidth);
73 | mHeaderImage.requestLayout();
74 |
75 | /**
76 | * We now rotate the Drawable so that is at the correct rotation,
77 | * and is centered.
78 | */
79 | mHeaderImage.setScaleType(ScaleType.MATRIX);
80 | Matrix matrix = new Matrix();
81 | matrix.postTranslate((lp.width - dWidth) / 2f, (lp.height - dHeight) / 2f);
82 | matrix.postRotate(getDrawableRotationAngle(), lp.width / 2f, lp.height / 2f);
83 | mHeaderImage.setImageMatrix(matrix);
84 | }
85 | }
86 |
87 | @Override
88 | protected void onPullImpl(float scaleOfLayout) {
89 | // NO-OP
90 | }
91 |
92 | @Override
93 | protected void pullToRefreshImpl() {
94 | // Only start reset Animation, we've previously show the rotate anim
95 | // if (mRotateAnimation == mHeaderImage.getAnimation()) {
96 | // mHeaderImage.startAnimation(mResetRotateAnimation);
97 | // }
98 | }
99 |
100 | @Override
101 | protected void refreshingImpl() {
102 | mHeaderImage.clearAnimation();
103 | mHeaderImage.setVisibility(View.INVISIBLE);
104 | mHeaderProgress.setVisibility(View.VISIBLE);
105 | }
106 |
107 | @Override
108 | protected void releaseToRefreshImpl() {
109 | // mHeaderImage.startAnimation(mRotateAnimation);
110 | }
111 |
112 | @Override
113 | protected void resetImpl() {
114 | mHeaderImage.clearAnimation();
115 | mHeaderProgress.setVisibility(View.GONE);
116 | mHeaderImage.setVisibility(View.VISIBLE);
117 | }
118 |
119 | @Override
120 | protected int getDefaultDrawableResId() {
121 | return R.drawable.default_ptr_flip;
122 | }
123 |
124 | private float getDrawableRotationAngle() {
125 | float angle = 0f;
126 | switch (mMode) {
127 | case PULL_FROM_END:
128 | if (mScrollDirection == Orientation.HORIZONTAL) {
129 | angle = 90f;
130 | } else {
131 | angle = 180f;
132 | }
133 | break;
134 |
135 | case PULL_FROM_START:
136 | if (mScrollDirection == Orientation.HORIZONTAL) {
137 | angle = 270f;
138 | }
139 | break;
140 |
141 | default:
142 | break;
143 | }
144 |
145 | return angle;
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/IndicatorLayout.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library.internal;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.content.Context;
20 | import android.graphics.Matrix;
21 | import android.graphics.drawable.Drawable;
22 | import android.view.View;
23 | import android.view.animation.Animation;
24 | import android.view.animation.Animation.AnimationListener;
25 | import android.view.animation.AnimationUtils;
26 | import android.view.animation.Interpolator;
27 | import android.view.animation.LinearInterpolator;
28 | import android.view.animation.RotateAnimation;
29 | import android.widget.FrameLayout;
30 | import android.widget.ImageView;
31 | import android.widget.ImageView.ScaleType;
32 |
33 | import com.bettycc.animatepulltorefresh.library.R;
34 | import com.handmark.pulltorefresh.library.PullToRefreshBase;
35 |
36 | @SuppressLint("ViewConstructor")
37 | public class IndicatorLayout extends FrameLayout implements AnimationListener {
38 |
39 | static final int DEFAULT_ROTATION_ANIMATION_DURATION = 150;
40 |
41 | private Animation mInAnim, mOutAnim;
42 | private ImageView mArrowImageView;
43 |
44 | private final Animation mRotateAnimation, mResetRotateAnimation;
45 |
46 | public IndicatorLayout(Context context, PullToRefreshBase.Mode mode) {
47 | super(context);
48 | mArrowImageView = new ImageView(context);
49 |
50 | Drawable arrowD = getResources().getDrawable(R.drawable.indicator_arrow);
51 | mArrowImageView.setImageDrawable(arrowD);
52 |
53 | final int padding = getResources().getDimensionPixelSize(R.dimen.indicator_internal_padding);
54 | mArrowImageView.setPadding(padding, padding, padding, padding);
55 | addView(mArrowImageView);
56 |
57 | int inAnimResId, outAnimResId;
58 | switch (mode) {
59 | case PULL_FROM_END:
60 | inAnimResId = R.anim.slide_in_from_bottom;
61 | outAnimResId = R.anim.slide_out_to_bottom;
62 | setBackgroundResource(R.drawable.indicator_bg_bottom);
63 |
64 | // Rotate Arrow so it's pointing the correct way
65 | mArrowImageView.setScaleType(ScaleType.MATRIX);
66 | Matrix matrix = new Matrix();
67 | matrix.setRotate(180f, arrowD.getIntrinsicWidth() / 2f, arrowD.getIntrinsicHeight() / 2f);
68 | mArrowImageView.setImageMatrix(matrix);
69 | break;
70 | default:
71 | case PULL_FROM_START:
72 | inAnimResId = R.anim.slide_in_from_top;
73 | outAnimResId = R.anim.slide_out_to_top;
74 | setBackgroundResource(R.drawable.indicator_bg_top);
75 | break;
76 | }
77 |
78 | mInAnim = AnimationUtils.loadAnimation(context, inAnimResId);
79 | mInAnim.setAnimationListener(this);
80 |
81 | mOutAnim = AnimationUtils.loadAnimation(context, outAnimResId);
82 | mOutAnim.setAnimationListener(this);
83 |
84 | final Interpolator interpolator = new LinearInterpolator();
85 | mRotateAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
86 | 0.5f);
87 | mRotateAnimation.setInterpolator(interpolator);
88 | mRotateAnimation.setDuration(DEFAULT_ROTATION_ANIMATION_DURATION);
89 | mRotateAnimation.setFillAfter(true);
90 |
91 | mResetRotateAnimation = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f,
92 | Animation.RELATIVE_TO_SELF, 0.5f);
93 | mResetRotateAnimation.setInterpolator(interpolator);
94 | mResetRotateAnimation.setDuration(DEFAULT_ROTATION_ANIMATION_DURATION);
95 | mResetRotateAnimation.setFillAfter(true);
96 |
97 | }
98 |
99 | public final boolean isVisible() {
100 | Animation currentAnim = getAnimation();
101 | if (null != currentAnim) {
102 | return mInAnim == currentAnim;
103 | }
104 |
105 | return getVisibility() == View.VISIBLE;
106 | }
107 |
108 | public void hide() {
109 | startAnimation(mOutAnim);
110 | }
111 |
112 | public void show() {
113 | mArrowImageView.clearAnimation();
114 | startAnimation(mInAnim);
115 | }
116 |
117 | @Override
118 | public void onAnimationEnd(Animation animation) {
119 | if (animation == mOutAnim) {
120 | mArrowImageView.clearAnimation();
121 | setVisibility(View.GONE);
122 | } else if (animation == mInAnim) {
123 | setVisibility(View.VISIBLE);
124 | }
125 |
126 | clearAnimation();
127 | }
128 |
129 | @Override
130 | public void onAnimationRepeat(Animation animation) {
131 | // NO-OP
132 | }
133 |
134 | @Override
135 | public void onAnimationStart(Animation animation) {
136 | setVisibility(View.VISIBLE);
137 | }
138 |
139 | public void releaseToRefresh() {
140 | mArrowImageView.startAnimation(mRotateAnimation);
141 | }
142 |
143 | public void pullToRefresh() {
144 | mArrowImageView.startAnimation(mResetRotateAnimation);
145 | }
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/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 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/PullToRefreshWebView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.os.Build.VERSION;
21 | import android.os.Build.VERSION_CODES;
22 | import android.os.Bundle;
23 | import android.util.AttributeSet;
24 | import android.util.FloatMath;
25 | import android.webkit.WebChromeClient;
26 | import android.webkit.WebView;
27 |
28 | import com.bettycc.animatepulltorefresh.library.R;
29 |
30 | public class PullToRefreshWebView extends PullToRefreshBase {
31 |
32 | private static final OnRefreshListener defaultOnRefreshListener = new OnRefreshListener() {
33 |
34 | @Override
35 | public void onRefresh(PullToRefreshBase refreshView) {
36 | refreshView.getRefreshableView().reload();
37 | }
38 |
39 | };
40 |
41 | private final WebChromeClient defaultWebChromeClient = new WebChromeClient() {
42 |
43 | @Override
44 | public void onProgressChanged(WebView view, int newProgress) {
45 | if (newProgress == 100) {
46 | onRefreshComplete();
47 | }
48 | }
49 |
50 | };
51 |
52 | public PullToRefreshWebView(Context context) {
53 | super(context);
54 |
55 | /**
56 | * Added so that by default, Pull-to-Refresh refreshes the page
57 | */
58 | setOnRefreshListener(defaultOnRefreshListener);
59 | mRefreshableView.setWebChromeClient(defaultWebChromeClient);
60 | }
61 |
62 | public PullToRefreshWebView(Context context, AttributeSet attrs) {
63 | super(context, attrs);
64 |
65 | /**
66 | * Added so that by default, Pull-to-Refresh refreshes the page
67 | */
68 | setOnRefreshListener(defaultOnRefreshListener);
69 | mRefreshableView.setWebChromeClient(defaultWebChromeClient);
70 | }
71 |
72 | public PullToRefreshWebView(Context context, Mode mode) {
73 | super(context, mode);
74 |
75 | /**
76 | * Added so that by default, Pull-to-Refresh refreshes the page
77 | */
78 | setOnRefreshListener(defaultOnRefreshListener);
79 | mRefreshableView.setWebChromeClient(defaultWebChromeClient);
80 | }
81 |
82 | public PullToRefreshWebView(Context context, Mode mode, AnimationStyle style) {
83 | super(context, mode, style);
84 |
85 | /**
86 | * Added so that by default, Pull-to-Refresh refreshes the page
87 | */
88 | setOnRefreshListener(defaultOnRefreshListener);
89 | mRefreshableView.setWebChromeClient(defaultWebChromeClient);
90 | }
91 |
92 | @Override
93 | public final Orientation getPullToRefreshScrollDirection() {
94 | return Orientation.VERTICAL;
95 | }
96 |
97 | @Override
98 | protected WebView createRefreshableView(Context context, AttributeSet attrs) {
99 | WebView webView;
100 | if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
101 | webView = new InternalWebViewSDK9(context, attrs);
102 | } else {
103 | webView = new WebView(context, attrs);
104 | }
105 |
106 | webView.setId(R.id.webview);
107 | return webView;
108 | }
109 |
110 | @Override
111 | protected boolean isReadyForPullStart() {
112 | return mRefreshableView.getScrollY() == 0;
113 | }
114 |
115 | @Override
116 | protected boolean isReadyForPullEnd() {
117 | float exactContentHeight = FloatMath.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale());
118 | return mRefreshableView.getScrollY() >= (exactContentHeight - mRefreshableView.getHeight());
119 | }
120 |
121 | @Override
122 | protected void onPtrRestoreInstanceState(Bundle savedInstanceState) {
123 | super.onPtrRestoreInstanceState(savedInstanceState);
124 | mRefreshableView.restoreState(savedInstanceState);
125 | }
126 |
127 | @Override
128 | protected void onPtrSaveInstanceState(Bundle saveState) {
129 | super.onPtrSaveInstanceState(saveState);
130 | mRefreshableView.saveState(saveState);
131 | }
132 |
133 | @TargetApi(9)
134 | final class InternalWebViewSDK9 extends WebView {
135 |
136 | // WebView doesn't always scroll back to it's edge so we add some
137 | // fuzziness
138 | static final int OVERSCROLL_FUZZY_THRESHOLD = 2;
139 |
140 | // WebView seems quite reluctant to overscroll so we use the scale
141 | // factor to scale it's value
142 | static final float OVERSCROLL_SCALE_FACTOR = 1.5f;
143 |
144 | public InternalWebViewSDK9(Context context, AttributeSet attrs) {
145 | super(context, attrs);
146 | }
147 |
148 | @Override
149 | protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
150 | int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
151 |
152 | final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
153 | scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
154 |
155 | // Does all of the hard work...
156 | OverscrollHelper.overScrollBy(PullToRefreshWebView.this, deltaX, scrollX, deltaY, scrollY,
157 | getScrollRange(), OVERSCROLL_FUZZY_THRESHOLD, OVERSCROLL_SCALE_FACTOR, isTouchEvent);
158 |
159 | return returnValue;
160 | }
161 |
162 | private int getScrollRange() {
163 | return (int) Math.max(0, FloatMath.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale())
164 | - (getHeight() - getPaddingBottom() - getPaddingTop()));
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/OverscrollHelper.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.annotation.TargetApi;
19 | import android.util.Log;
20 | import android.view.View;
21 |
22 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
23 | import com.handmark.pulltorefresh.library.PullToRefreshBase.State;
24 |
25 | @TargetApi(9)
26 | public final class OverscrollHelper {
27 |
28 | static final String LOG_TAG = "OverscrollHelper";
29 | static final float DEFAULT_OVERSCROLL_SCALE = 1f;
30 |
31 | /**
32 | * Helper method for Overscrolling that encapsulates all of the necessary
33 | * function.
34 | *
35 | * This should only be used on AdapterView's such as ListView as it just
36 | * calls through to overScrollBy() with the scrollRange = 0. AdapterView's
37 | * do not have a scroll range (i.e. getScrollY() doesn't work).
38 | *
39 | * @param view - PullToRefreshView that is calling this.
40 | * @param deltaX - Change in X in pixels, passed through from from
41 | * overScrollBy call
42 | * @param scrollX - Current X scroll value in pixels before applying deltaY,
43 | * passed through from from overScrollBy call
44 | * @param deltaY - Change in Y in pixels, passed through from from
45 | * overScrollBy call
46 | * @param scrollY - Current Y scroll value in pixels before applying deltaY,
47 | * passed through from from overScrollBy call
48 | * @param isTouchEvent - true if this scroll operation is the result of a
49 | * touch event, passed through from from overScrollBy call
50 | */
51 | public static void overScrollBy(final PullToRefreshBase> view, final int deltaX, final int scrollX,
52 | final int deltaY, final int scrollY, final boolean isTouchEvent) {
53 | overScrollBy(view, deltaX, scrollX, deltaY, scrollY, 0, isTouchEvent);
54 | }
55 |
56 | /**
57 | * Helper method for Overscrolling that encapsulates all of the necessary
58 | * function. This version of the call is used for Views that need to specify
59 | * a Scroll Range but scroll back to it's edge correctly.
60 | *
61 | * @param view - PullToRefreshView that is calling this.
62 | * @param deltaX - Change in X in pixels, passed through from from
63 | * overScrollBy call
64 | * @param scrollX - Current X scroll value in pixels before applying deltaY,
65 | * passed through from from overScrollBy call
66 | * @param deltaY - Change in Y in pixels, passed through from from
67 | * overScrollBy call
68 | * @param scrollY - Current Y scroll value in pixels before applying deltaY,
69 | * passed through from from overScrollBy call
70 | * @param scrollRange - Scroll Range of the View, specifically needed for
71 | * ScrollView
72 | * @param isTouchEvent - true if this scroll operation is the result of a
73 | * touch event, passed through from from overScrollBy call
74 | */
75 | public static void overScrollBy(final PullToRefreshBase> view, final int deltaX, final int scrollX,
76 | final int deltaY, final int scrollY, final int scrollRange, final boolean isTouchEvent) {
77 | overScrollBy(view, deltaX, scrollX, deltaY, scrollY, scrollRange, 0, DEFAULT_OVERSCROLL_SCALE, isTouchEvent);
78 | }
79 |
80 | /**
81 | * Helper method for Overscrolling that encapsulates all of the necessary
82 | * function. This is the advanced version of the call.
83 | *
84 | * @param view - PullToRefreshView that is calling this.
85 | * @param deltaX - Change in X in pixels, passed through from from
86 | * overScrollBy call
87 | * @param scrollX - Current X scroll value in pixels before applying deltaY,
88 | * passed through from from overScrollBy call
89 | * @param deltaY - Change in Y in pixels, passed through from from
90 | * overScrollBy call
91 | * @param scrollY - Current Y scroll value in pixels before applying deltaY,
92 | * passed through from from overScrollBy call
93 | * @param scrollRange - Scroll Range of the View, specifically needed for
94 | * ScrollView
95 | * @param fuzzyThreshold - Threshold for which the values how fuzzy we
96 | * should treat the other values. Needed for WebView as it
97 | * doesn't always scroll back to it's edge. 0 = no fuzziness.
98 | * @param scaleFactor - Scale Factor for overscroll amount
99 | * @param isTouchEvent - true if this scroll operation is the result of a
100 | * touch event, passed through from from overScrollBy call
101 | */
102 | public static void overScrollBy(final PullToRefreshBase> view, final int deltaX, final int scrollX,
103 | final int deltaY, final int scrollY, final int scrollRange, final int fuzzyThreshold,
104 | final float scaleFactor, final boolean isTouchEvent) {
105 |
106 | final int deltaValue, currentScrollValue, scrollValue;
107 | switch (view.getPullToRefreshScrollDirection()) {
108 | case HORIZONTAL:
109 | deltaValue = deltaX;
110 | scrollValue = scrollX;
111 | currentScrollValue = view.getScrollX();
112 | break;
113 | case VERTICAL:
114 | default:
115 | deltaValue = deltaY;
116 | scrollValue = scrollY;
117 | currentScrollValue = view.getScrollY();
118 | break;
119 | }
120 |
121 | // Check that OverScroll is enabled and that we're not currently
122 | // refreshing.
123 | if (view.isPullToRefreshOverScrollEnabled() && !view.isRefreshing()) {
124 | final Mode mode = view.getMode();
125 |
126 | // Check that Pull-to-Refresh is enabled, and the event isn't from
127 | // touch
128 |
129 | if (mode.permitsPullToRefresh() && !isTouchEvent && deltaValue != 0) {
130 | final int newScrollValue = (deltaValue + scrollValue);
131 |
132 | if (PullToRefreshBase.DEBUG) {
133 | Log.d(LOG_TAG, "OverScroll. DeltaX: " + deltaX + ", ScrollX: " + scrollX + ", DeltaY: " + deltaY
134 | + ", ScrollY: " + scrollY + ", NewY: " + newScrollValue + ", ScrollRange: " + scrollRange
135 | + ", CurrentScroll: " + currentScrollValue);
136 | }
137 |
138 | if (newScrollValue < (0 - fuzzyThreshold)) {
139 | // Check the mode supports the overscroll direction, and
140 | // then move scroll
141 | if (mode.showHeaderLoadingLayout()) {
142 | // If we're currently at zero, we're about to start
143 | // overscrolling, so change the state
144 | if (currentScrollValue == 0) {
145 | view.setState(State.OVERSCROLLING);
146 | }
147 |
148 | view.setHeaderScroll((int) (scaleFactor * (currentScrollValue + newScrollValue)));
149 | }
150 | } else if (newScrollValue > (scrollRange + fuzzyThreshold)) {
151 | // Check the mode supports the overscroll direction, and
152 | // then move scroll
153 | if (mode.showFooterLoadingLayout()) {
154 | // If we're currently at zero, we're about to start
155 | // overscrolling, so change the state
156 | if (currentScrollValue == 0) {
157 | view.setState(State.OVERSCROLLING);
158 | }
159 |
160 | view.setHeaderScroll((int) (scaleFactor * (currentScrollValue + newScrollValue - scrollRange)));
161 | }
162 | } else if (Math.abs(newScrollValue) <= fuzzyThreshold
163 | || Math.abs(newScrollValue - scrollRange) <= fuzzyThreshold) {
164 | // Means we've stopped overscrolling, so scroll back to 0
165 | view.setState(State.RESET);
166 | }
167 | } else if (isTouchEvent && State.OVERSCROLLING == view.getState()) {
168 | // This condition means that we were overscrolling from a fling,
169 | // but the user has touched the View and is now overscrolling
170 | // from touch instead. We need to just reset.
171 | view.setState(State.RESET);
172 | }
173 | }
174 | }
175 |
176 | static boolean isAndroidOverScrollEnabled(View view) {
177 | return view.getOverScrollMode() != View.OVER_SCROLL_NEVER;
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/IPullToRefresh.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.view.View;
19 | import android.view.animation.Interpolator;
20 |
21 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
22 | import com.handmark.pulltorefresh.library.PullToRefreshBase.OnPullEventListener;
23 | import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener;
24 | import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener2;
25 | import com.handmark.pulltorefresh.library.PullToRefreshBase.State;
26 |
27 | public interface IPullToRefresh {
28 |
29 | /**
30 | * Demos the Pull-to-Refresh functionality to the user so that they are
31 | * aware it is there. This could be useful when the user first opens your
32 | * app, etc. The animation will only happen if the Refresh View (ListView,
33 | * ScrollView, etc) is in a state where a Pull-to-Refresh could occur by a
34 | * user's touch gesture (i.e. scrolled to the top/bottom).
35 | *
36 | * @return true - if the Demo has been started, false if not.
37 | */
38 | public boolean demo();
39 |
40 | /**
41 | * Get the mode that this view is currently in. This is only really useful
42 | * when using Mode.BOTH.
43 | *
44 | * @return Mode that the view is currently in
45 | */
46 | public Mode getCurrentMode();
47 |
48 | /**
49 | * Returns whether the Touch Events are filtered or not. If true is
50 | * returned, then the View will only use touch events where the difference
51 | * in the Y-axis is greater than the difference in the X-axis. This means
52 | * that the View will not interfere when it is used in a horizontal
53 | * scrolling View (such as a ViewPager).
54 | *
55 | * @return boolean - true if the View is filtering Touch Events
56 | */
57 | public boolean getFilterTouchEvents();
58 |
59 | /**
60 | * Returns a proxy object which allows you to call methods on all of the
61 | * LoadingLayouts (the Views which show when Pulling/Refreshing).
62 | *
63 | * You should not keep the result of this method any longer than you need
64 | * it.
65 | *
66 | * @return Object which will proxy any calls you make on it, to all of the
67 | * LoadingLayouts.
68 | */
69 | public ILoadingLayout getLoadingLayoutProxy();
70 |
71 | /**
72 | * Returns a proxy object which allows you to call methods on the
73 | * LoadingLayouts (the Views which show when Pulling/Refreshing). The actual
74 | * LoadingLayout(s) which will be affected, are chosen by the parameters you
75 | * give.
76 | *
77 | * You should not keep the result of this method any longer than you need
78 | * it.
79 | *
80 | * @param includeStart - Whether to include the Start/Header Views
81 | * @param includeEnd - Whether to include the End/Footer Views
82 | * @return Object which will proxy any calls you make on it, to the
83 | * LoadingLayouts included.
84 | */
85 | public ILoadingLayout getLoadingLayoutProxy(boolean includeStart, boolean includeEnd);
86 |
87 | /**
88 | * Get the mode that this view has been set to. If this returns
89 | * Mode.BOTH, you can use getCurrentMode() to
90 | * check which mode the view is currently in
91 | *
92 | * @return Mode that the view has been set to
93 | */
94 | public Mode getMode();
95 |
96 | /**
97 | * Get the Wrapped Refreshable View. Anything returned here has already been
98 | * added to the content view.
99 | *
100 | * @return The View which is currently wrapped
101 | */
102 | public T getRefreshableView();
103 |
104 | /**
105 | * Get whether the 'Refreshing' View should be automatically shown when
106 | * refreshing. Returns true by default.
107 | *
108 | * @return - true if the Refreshing View will be show
109 | */
110 | public boolean getShowViewWhileRefreshing();
111 |
112 | /**
113 | * @return - The state that the View is currently in.
114 | */
115 | public State getState();
116 |
117 | /**
118 | * Whether Pull-to-Refresh is enabled
119 | *
120 | * @return enabled
121 | */
122 | public boolean isPullToRefreshEnabled();
123 |
124 | /**
125 | * Gets whether Overscroll support is enabled. This is different to
126 | * Android's standard Overscroll support (the edge-glow) which is available
127 | * from GINGERBREAD onwards
128 | *
129 | * @return true - if both PullToRefresh-OverScroll and Android's inbuilt
130 | * OverScroll are enabled
131 | */
132 | public boolean isPullToRefreshOverScrollEnabled();
133 |
134 | /**
135 | * Returns whether the Widget is currently in the Refreshing mState
136 | *
137 | * @return true if the Widget is currently refreshing
138 | */
139 | public boolean isRefreshing();
140 |
141 | /**
142 | * Returns whether the widget has enabled scrolling on the Refreshable View
143 | * while refreshing.
144 | *
145 | * @return true if the widget has enabled scrolling while refreshing
146 | */
147 | public boolean isScrollingWhileRefreshingEnabled();
148 |
149 | /**
150 | * Mark the current Refresh as complete. Will Reset the UI and hide the
151 | * Refreshing View
152 | */
153 | public void onRefreshComplete();
154 |
155 | /**
156 | * Set the Touch Events to be filtered or not. If set to true, then the View
157 | * will only use touch events where the difference in the Y-axis is greater
158 | * than the difference in the X-axis. This means that the View will not
159 | * interfere when it is used in a horizontal scrolling View (such as a
160 | * ViewPager), but will restrict which types of finger scrolls will trigger
161 | * the View.
162 | *
163 | * @param filterEvents - true if you want to filter Touch Events. Default is
164 | * true.
165 | */
166 | public void setFilterTouchEvents(boolean filterEvents);
167 |
168 | /**
169 | * Set the mode of Pull-to-Refresh that this view will use.
170 | *
171 | * @param mode - Mode to set the View to
172 | */
173 | public void setMode(Mode mode);
174 |
175 | /**
176 | * Set OnPullEventListener for the Widget
177 | *
178 | * @param listener - Listener to be used when the Widget has a pull event to
179 | * propogate.
180 | */
181 | public void setOnPullEventListener(OnPullEventListener listener);
182 |
183 | /**
184 | * Set OnRefreshListener for the Widget
185 | *
186 | * @param listener - Listener to be used when the Widget is set to Refresh
187 | */
188 | public void setOnRefreshListener(OnRefreshListener listener);
189 |
190 | /**
191 | * Set OnRefreshListener for the Widget
192 | *
193 | * @param listener - Listener to be used when the Widget is set to Refresh
194 | */
195 | public void setOnRefreshListener(OnRefreshListener2 listener);
196 |
197 | /**
198 | * Sets whether Overscroll support is enabled. This is different to
199 | * Android's standard Overscroll support (the edge-glow). This setting only
200 | * takes effect when running on device with Android v2.3 or greater.
201 | *
202 | * @param enabled - true if you want Overscroll enabled
203 | */
204 | public void setPullToRefreshOverScrollEnabled(boolean enabled);
205 |
206 | /**
207 | * Sets the Widget to be in the refresh state. The UI will be updated to
208 | * show the 'Refreshing' view, and be scrolled to show such.
209 | */
210 | public void setRefreshing();
211 |
212 | /**
213 | * Sets the Widget to be in the refresh state. The UI will be updated to
214 | * show the 'Refreshing' view.
215 | *
216 | * @param doScroll - true if you want to force a scroll to the Refreshing
217 | * view.
218 | */
219 | public void setRefreshing(boolean doScroll);
220 |
221 | /**
222 | * Sets the Animation Interpolator that is used for animated scrolling.
223 | * Defaults to a DecelerateInterpolator
224 | *
225 | * @param interpolator - Interpolator to use
226 | */
227 | public void setScrollAnimationInterpolator(Interpolator interpolator);
228 |
229 | /**
230 | * By default the Widget disables scrolling on the Refreshable View while
231 | * refreshing. This method can change this behaviour.
232 | *
233 | * @param scrollingWhileRefreshingEnabled - true if you want to enable
234 | * scrolling while refreshing
235 | */
236 | public void setScrollingWhileRefreshingEnabled(boolean scrollingWhileRefreshingEnabled);
237 |
238 | /**
239 | * A mutator to enable/disable whether the 'Refreshing' View should be
240 | * automatically shown when refreshing.
241 | *
242 | * @param showView
243 | */
244 | public void setShowViewWhileRefreshing(boolean showView);
245 |
246 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/PullToRefreshListView.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.annotation.TargetApi;
19 | import android.content.Context;
20 | import android.content.res.TypedArray;
21 | import android.graphics.Canvas;
22 | import android.os.Build.VERSION;
23 | import android.os.Build.VERSION_CODES;
24 | import android.util.AttributeSet;
25 | import android.view.Gravity;
26 | import android.view.MotionEvent;
27 | import android.view.View;
28 | import android.widget.FrameLayout;
29 | import android.widget.ListAdapter;
30 | import android.widget.ListView;
31 |
32 | import com.bettycc.animatepulltorefresh.library.R;
33 | import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor;
34 | import com.handmark.pulltorefresh.library.internal.LoadingLayout;
35 |
36 | public class PullToRefreshListView extends PullToRefreshAdapterViewBase {
37 |
38 | private LoadingLayout mHeaderLoadingView;
39 | private LoadingLayout mFooterLoadingView;
40 |
41 | private FrameLayout mLvFooterLoadingFrame;
42 |
43 | private boolean mListViewExtrasEnabled;
44 |
45 | public PullToRefreshListView(Context context) {
46 | super(context);
47 | }
48 |
49 | public PullToRefreshListView(Context context, AttributeSet attrs) {
50 | super(context, attrs);
51 | }
52 |
53 | public PullToRefreshListView(Context context, Mode mode) {
54 | super(context, mode);
55 | }
56 |
57 | public PullToRefreshListView(Context context, Mode mode, AnimationStyle style) {
58 | super(context, mode, style);
59 | }
60 |
61 | @Override
62 | public final Orientation getPullToRefreshScrollDirection() {
63 | return Orientation.VERTICAL;
64 | }
65 |
66 | @Override
67 | protected void onRefreshing(final boolean doScroll) {
68 | /**
69 | * If we're not showing the Refreshing view, or the list is empty, the
70 | * the header/footer views won't show so we use the normal method.
71 | */
72 | ListAdapter adapter = mRefreshableView.getAdapter();
73 | if (!mListViewExtrasEnabled || !getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) {
74 | super.onRefreshing(doScroll);
75 | return;
76 | }
77 |
78 | super.onRefreshing(false);
79 |
80 | final LoadingLayout origLoadingView, listViewLoadingView, oppositeListViewLoadingView;
81 | final int selection, scrollToY;
82 |
83 | switch (getCurrentMode()) {
84 | case MANUAL_REFRESH_ONLY:
85 | case PULL_FROM_END:
86 | origLoadingView = getFooterLayout();
87 | listViewLoadingView = mFooterLoadingView;
88 | oppositeListViewLoadingView = mHeaderLoadingView;
89 | selection = mRefreshableView.getCount() - 1;
90 | scrollToY = getScrollY() - getFooterSize();
91 | break;
92 | case PULL_FROM_START:
93 | default:
94 | origLoadingView = getHeaderLayout();
95 | listViewLoadingView = mHeaderLoadingView;
96 | oppositeListViewLoadingView = mFooterLoadingView;
97 | selection = 0;
98 | scrollToY = getScrollY() + getHeaderSize();
99 | break;
100 | }
101 |
102 | // Hide our original Loading View
103 | origLoadingView.reset();
104 | origLoadingView.hideAllViews();
105 |
106 | // Make sure the opposite end is hidden too
107 | oppositeListViewLoadingView.setVisibility(View.GONE);
108 |
109 | // Show the ListView Loading View and set it to refresh.
110 | listViewLoadingView.setVisibility(View.VISIBLE);
111 | listViewLoadingView.refreshing();
112 |
113 | if (doScroll) {
114 | // We need to disable the automatic visibility changes for now
115 | disableLoadingLayoutVisibilityChanges();
116 |
117 | // We scroll slightly so that the ListView's header/footer is at the
118 | // same Y position as our normal header/footer
119 | setHeaderScroll(scrollToY);
120 |
121 | // Make sure the ListView is scrolled to show the loading
122 | // header/footer
123 | mRefreshableView.setSelection(selection);
124 |
125 | // Smooth scroll as normal
126 | smoothScrollTo(0);
127 | }
128 | }
129 |
130 | @Override
131 | protected void onReset() {
132 | /**
133 | * If the extras are not enabled, just call up to super and return.
134 | */
135 | if (!mListViewExtrasEnabled) {
136 | super.onReset();
137 | return;
138 | }
139 |
140 | final LoadingLayout originalLoadingLayout, listViewLoadingLayout;
141 | final int scrollToHeight, selection;
142 | final boolean scrollLvToEdge;
143 |
144 | switch (getCurrentMode()) {
145 | case MANUAL_REFRESH_ONLY:
146 | case PULL_FROM_END:
147 | originalLoadingLayout = getFooterLayout();
148 | listViewLoadingLayout = mFooterLoadingView;
149 | selection = mRefreshableView.getCount() - 1;
150 | scrollToHeight = getFooterSize();
151 | scrollLvToEdge = Math.abs(mRefreshableView.getLastVisiblePosition() - selection) <= 1;
152 | break;
153 | case PULL_FROM_START:
154 | default:
155 | originalLoadingLayout = getHeaderLayout();
156 | listViewLoadingLayout = mHeaderLoadingView;
157 | scrollToHeight = -getHeaderSize();
158 | selection = 0;
159 | scrollLvToEdge = Math.abs(mRefreshableView.getFirstVisiblePosition() - selection) <= 1;
160 | break;
161 | }
162 |
163 | // If the ListView header loading layout is showing, then we need to
164 | // flip so that the original one is showing instead
165 | if (listViewLoadingLayout.getVisibility() == View.VISIBLE) {
166 |
167 | // Set our Original View to Visible
168 | originalLoadingLayout.showInvisibleViews();
169 |
170 | // Hide the ListView Header/Footer
171 | listViewLoadingLayout.setVisibility(View.GONE);
172 |
173 | /**
174 | * Scroll so the View is at the same Y as the ListView
175 | * header/footer, but only scroll if: we've pulled to refresh, it's
176 | * positioned correctly
177 | */
178 | if (scrollLvToEdge && getState() != State.MANUAL_REFRESHING) {
179 | mRefreshableView.setSelection(selection);
180 | setHeaderScroll(scrollToHeight);
181 | }
182 | }
183 |
184 | // Finally, call up to super
185 | super.onReset();
186 | }
187 |
188 | @Override
189 | protected LoadingLayoutProxy createLoadingLayoutProxy(final boolean includeStart, final boolean includeEnd) {
190 | LoadingLayoutProxy proxy = super.createLoadingLayoutProxy(includeStart, includeEnd);
191 |
192 | if (mListViewExtrasEnabled) {
193 | final Mode mode = getMode();
194 |
195 | if (includeStart && mode.showHeaderLoadingLayout()) {
196 | proxy.addLayout(mHeaderLoadingView);
197 | }
198 | if (includeEnd && mode.showFooterLoadingLayout()) {
199 | proxy.addLayout(mFooterLoadingView);
200 | }
201 | }
202 |
203 | return proxy;
204 | }
205 |
206 | protected ListView createListView(Context context, AttributeSet attrs) {
207 | final ListView lv;
208 | if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
209 | lv = new InternalListViewSDK9(context, attrs);
210 | } else {
211 | lv = new InternalListView(context, attrs);
212 | }
213 | return lv;
214 | }
215 |
216 | @Override
217 | protected ListView createRefreshableView(Context context, AttributeSet attrs) {
218 | ListView lv = createListView(context, attrs);
219 |
220 | // Set it to this so it can be used in ListActivity/ListFragment
221 | lv.setId(android.R.id.list);
222 | return lv;
223 | }
224 |
225 | @Override
226 | protected void handleStyledAttributes(TypedArray a) {
227 | super.handleStyledAttributes(a);
228 |
229 | mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true);
230 |
231 | if (mListViewExtrasEnabled) {
232 | final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
233 | FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL);
234 |
235 | // Create Loading Views ready for use later
236 | FrameLayout frame = new FrameLayout(getContext());
237 | mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a);
238 | mHeaderLoadingView.setVisibility(View.GONE);
239 | frame.addView(mHeaderLoadingView, lp);
240 | mRefreshableView.addHeaderView(frame, null, false);
241 |
242 | mLvFooterLoadingFrame = new FrameLayout(getContext());
243 | mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a);
244 | mFooterLoadingView.setVisibility(View.GONE);
245 | mLvFooterLoadingFrame.addView(mFooterLoadingView, lp);
246 |
247 | /**
248 | * If the value for Scrolling While Refreshing hasn't been
249 | * explicitly set via XML, enable Scrolling While Refreshing.
250 | */
251 | if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) {
252 | setScrollingWhileRefreshingEnabled(true);
253 | }
254 | }
255 | }
256 |
257 | @TargetApi(9)
258 | final class InternalListViewSDK9 extends InternalListView {
259 |
260 | public InternalListViewSDK9(Context context, AttributeSet attrs) {
261 | super(context, attrs);
262 | }
263 |
264 | @Override
265 | protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
266 | int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
267 |
268 | final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
269 | scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
270 |
271 | // Does all of the hard work...
272 | OverscrollHelper.overScrollBy(PullToRefreshListView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent);
273 |
274 | return returnValue;
275 | }
276 | }
277 |
278 | protected class InternalListView extends ListView implements EmptyViewMethodAccessor {
279 |
280 | private boolean mAddedLvFooter = false;
281 |
282 | public InternalListView(Context context, AttributeSet attrs) {
283 | super(context, attrs);
284 | }
285 |
286 | @Override
287 | protected void dispatchDraw(Canvas canvas) {
288 | /**
289 | * This is a bit hacky, but Samsung's ListView has got a bug in it
290 | * when using Header/Footer Views and the list is empty. This masks
291 | * the issue so that it doesn't cause an FC. See Issue #66.
292 | */
293 | try {
294 | super.dispatchDraw(canvas);
295 | } catch (IndexOutOfBoundsException e) {
296 | e.printStackTrace();
297 | }
298 | }
299 |
300 | @Override
301 | public boolean dispatchTouchEvent(MotionEvent ev) {
302 | /**
303 | * This is a bit hacky, but Samsung's ListView has got a bug in it
304 | * when using Header/Footer Views and the list is empty. This masks
305 | * the issue so that it doesn't cause an FC. See Issue #66.
306 | */
307 | try {
308 | return super.dispatchTouchEvent(ev);
309 | } catch (IndexOutOfBoundsException e) {
310 | e.printStackTrace();
311 | return false;
312 | }
313 | }
314 |
315 | @Override
316 | public void setAdapter(ListAdapter adapter) {
317 | // Add the Footer View at the last possible moment
318 | if (null != mLvFooterLoadingFrame && !mAddedLvFooter) {
319 | addFooterView(mLvFooterLoadingFrame, null, false);
320 | mAddedLvFooter = true;
321 | }
322 |
323 | super.setAdapter(adapter);
324 | }
325 |
326 | @Override
327 | public void setEmptyView(View emptyView) {
328 | PullToRefreshListView.this.setEmptyView(emptyView);
329 | }
330 |
331 | @Override
332 | public void setEmptyViewInternal(View emptyView) {
333 | super.setEmptyView(emptyView);
334 | }
335 |
336 | }
337 |
338 | }
339 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/internal/LoadingLayout.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library.internal;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.content.Context;
20 | import android.content.res.ColorStateList;
21 | import android.content.res.TypedArray;
22 | import android.graphics.Typeface;
23 | import android.graphics.drawable.AnimationDrawable;
24 | import android.graphics.drawable.Drawable;
25 | import android.text.TextUtils;
26 | import android.util.TypedValue;
27 | import android.view.Gravity;
28 | import android.view.LayoutInflater;
29 | import android.view.View;
30 | import android.view.ViewGroup;
31 | import android.view.animation.Interpolator;
32 | import android.view.animation.LinearInterpolator;
33 | import android.widget.FrameLayout;
34 | import android.widget.ImageView;
35 | import android.widget.TextView;
36 |
37 | import com.bettycc.animatepulltorefresh.library.R;
38 | import com.handmark.pulltorefresh.library.ILoadingLayout;
39 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
40 | import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
41 |
42 | import pl.droidsonroids.gif.GifImageView;
43 |
44 | @SuppressLint("ViewConstructor")
45 | public abstract class LoadingLayout extends FrameLayout implements ILoadingLayout {
46 |
47 | static final String LOG_TAG = "PullToRefresh-LoadingLayout";
48 |
49 | static final Interpolator ANIMATION_INTERPOLATOR = new LinearInterpolator();
50 |
51 | private FrameLayout mInnerLayout;
52 |
53 | public final GifImageView mHeaderImage;
54 | public final ImageView mTickImage;
55 | protected final View mHeaderProgress;
56 |
57 | private boolean mUseIntrinsicAnimation;
58 |
59 | private final TextView mHeaderText;
60 | private final TextView mSubHeaderText;
61 |
62 | protected final Mode mMode;
63 | protected final Orientation mScrollDirection;
64 |
65 | private CharSequence mPullLabel;
66 | private CharSequence mRefreshingLabel;
67 | private CharSequence mReleaseLabel;
68 |
69 | public LoadingLayout(Context context, final Mode mode, final Orientation scrollDirection, TypedArray attrs) {
70 | super(context);
71 | mMode = mode;
72 | mScrollDirection = scrollDirection;
73 |
74 | switch (scrollDirection) {
75 | case HORIZONTAL:
76 | LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_horizontal, this);
77 | break;
78 | case VERTICAL:
79 | default:
80 | LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_vertical, this);
81 | break;
82 | }
83 |
84 | mInnerLayout = (FrameLayout) findViewById(R.id.fl_inner);
85 | mHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_text);
86 | mHeaderProgress = mInnerLayout.findViewById(R.id.pull_to_refresh_progress);
87 | mSubHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_sub_text);
88 | mHeaderImage = (GifImageView) mInnerLayout.findViewById(R.id.pull_to_refresh_image);
89 | mTickImage = (ImageView) mInnerLayout.findViewById(R.id.pull_to_refresh_tick);
90 |
91 | FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mInnerLayout.getLayoutParams();
92 |
93 | switch (mode) {
94 | case PULL_FROM_END:
95 | lp.gravity = scrollDirection == Orientation.VERTICAL ? Gravity.TOP : Gravity.LEFT;
96 |
97 | // Load in labels
98 | mPullLabel = context.getString(R.string.pull_to_refresh_from_bottom_pull_label);
99 | mRefreshingLabel = context.getString(R.string.pull_to_refresh_from_bottom_refreshing_label);
100 | mReleaseLabel = context.getString(R.string.pull_to_refresh_from_bottom_release_label);
101 | break;
102 |
103 | case PULL_FROM_START:
104 | default:
105 | lp.gravity = scrollDirection == Orientation.VERTICAL ? Gravity.BOTTOM : Gravity.RIGHT;
106 |
107 | // Load in labels
108 | mPullLabel = context.getString(R.string.pull_to_refresh_pull_label);
109 | mRefreshingLabel = context.getString(R.string.pull_to_refresh_refreshing_label);
110 | mReleaseLabel = context.getString(R.string.pull_to_refresh_release_label);
111 | break;
112 | }
113 |
114 | if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderBackground)) {
115 | Drawable background = attrs.getDrawable(R.styleable.PullToRefresh_ptrHeaderBackground);
116 | if (null != background) {
117 | ViewCompat.setBackground(this, background);
118 | }
119 | }
120 |
121 | if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderTextAppearance)) {
122 | TypedValue styleID = new TypedValue();
123 | attrs.getValue(R.styleable.PullToRefresh_ptrHeaderTextAppearance, styleID);
124 | setTextAppearance(styleID.data);
125 | }
126 | if (attrs.hasValue(R.styleable.PullToRefresh_ptrSubHeaderTextAppearance)) {
127 | TypedValue styleID = new TypedValue();
128 | attrs.getValue(R.styleable.PullToRefresh_ptrSubHeaderTextAppearance, styleID);
129 | setSubTextAppearance(styleID.data);
130 | }
131 |
132 | // Text Color attrs need to be set after TextAppearance attrs
133 | if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderTextColor)) {
134 | ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderTextColor);
135 | if (null != colors) {
136 | setTextColor(colors);
137 | }
138 | }
139 | if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderSubTextColor)) {
140 | ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderSubTextColor);
141 | if (null != colors) {
142 | setSubTextColor(colors);
143 | }
144 | }
145 |
146 | // Try and get defined drawable from Attrs
147 | Drawable imageDrawable = null;
148 | if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawable)) {
149 | imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawable);
150 | }
151 |
152 | // Check Specific Drawable from Attrs, these overrite the generic
153 | // drawable attr above
154 | switch (mode) {
155 | case PULL_FROM_START:
156 | default:
157 | if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableStart)) {
158 | imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableStart);
159 | } else if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableTop)) {
160 | Utils.warnDeprecation("ptrDrawableTop", "ptrDrawableStart");
161 | imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableTop);
162 | }
163 | break;
164 |
165 | case PULL_FROM_END:
166 | if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableEnd)) {
167 | imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableEnd);
168 | } else if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableBottom)) {
169 | Utils.warnDeprecation("ptrDrawableBottom", "ptrDrawableEnd");
170 | imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableBottom);
171 | }
172 | break;
173 | }
174 |
175 | // If we don't have a user defined drawable, load the default
176 | if (null == imageDrawable) {
177 | imageDrawable = context.getResources().getDrawable(getDefaultDrawableResId());
178 | }
179 |
180 | // Set Drawable, and save width/height
181 | setLoadingDrawable(imageDrawable);
182 |
183 | reset();
184 | }
185 |
186 | public final void setHeight(int height) {
187 | ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) getLayoutParams();
188 | lp.height = height;
189 | requestLayout();
190 | }
191 |
192 | public final void setWidth(int width) {
193 | ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) getLayoutParams();
194 | lp.width = width;
195 | requestLayout();
196 | }
197 |
198 | public final int getContentSize() {
199 | switch (mScrollDirection) {
200 | case HORIZONTAL:
201 | return mInnerLayout.getWidth();
202 | case VERTICAL:
203 | default:
204 | return mInnerLayout.getHeight();
205 | }
206 | }
207 |
208 | public final void hideAllViews() {
209 | if (View.VISIBLE == mHeaderText.getVisibility()) {
210 | mHeaderText.setVisibility(View.INVISIBLE);
211 | }
212 | if (View.VISIBLE == mHeaderProgress.getVisibility()) {
213 | mHeaderProgress.setVisibility(View.INVISIBLE);
214 | }
215 | if (View.VISIBLE == mHeaderImage.getVisibility()) {
216 | mHeaderImage.setVisibility(View.INVISIBLE);
217 | }
218 | if (View.VISIBLE == mSubHeaderText.getVisibility()) {
219 | mSubHeaderText.setVisibility(View.INVISIBLE);
220 | }
221 | }
222 |
223 | public final void onPull(float scaleOfLayout) {
224 | if (!mUseIntrinsicAnimation) {
225 | onPullImpl(scaleOfLayout);
226 | }
227 | }
228 |
229 | public final void pullToRefresh() {
230 | if (null != mHeaderText) {
231 | mHeaderText.setText(mPullLabel);
232 | }
233 |
234 | // Now call the callback
235 | pullToRefreshImpl();
236 | }
237 |
238 | public final void refreshing() {
239 | if (null != mHeaderText) {
240 | mHeaderText.setText(mRefreshingLabel);
241 | }
242 |
243 | if (mUseIntrinsicAnimation) {
244 | ((AnimationDrawable) mHeaderImage.getDrawable()).start();
245 | } else {
246 | // Now call the callback
247 | refreshingImpl();
248 | }
249 |
250 | if (null != mSubHeaderText) {
251 | mSubHeaderText.setVisibility(View.GONE);
252 | }
253 | }
254 |
255 | public final void releaseToRefresh() {
256 | if (null != mHeaderText) {
257 | mHeaderText.setText(mReleaseLabel);
258 | }
259 |
260 | // Now call the callback
261 | releaseToRefreshImpl();
262 | }
263 |
264 | public final void reset() {
265 | if (null != mHeaderText) {
266 | mHeaderText.setText(mPullLabel);
267 | }
268 | mHeaderImage.setVisibility(View.VISIBLE);
269 |
270 | if (mUseIntrinsicAnimation) {
271 | ((AnimationDrawable) mHeaderImage.getDrawable()).stop();
272 | } else {
273 | // Now call the callback
274 | resetImpl();
275 | }
276 |
277 | if (null != mSubHeaderText) {
278 | if (TextUtils.isEmpty(mSubHeaderText.getText())) {
279 | mSubHeaderText.setVisibility(View.GONE);
280 | } else {
281 | mSubHeaderText.setVisibility(View.VISIBLE);
282 | }
283 | }
284 | }
285 |
286 | @Override
287 | public void setLastUpdatedLabel(CharSequence label) {
288 | setSubHeaderText(label);
289 | }
290 |
291 | public final void setLoadingDrawable(Drawable imageDrawable) {
292 | // Set Drawable
293 | mHeaderImage.setImageDrawable(imageDrawable);
294 | mUseIntrinsicAnimation = (imageDrawable instanceof AnimationDrawable);
295 |
296 | // Now call the callback
297 | onLoadingDrawableSet(imageDrawable);
298 | }
299 |
300 | public void setPullLabel(CharSequence pullLabel) {
301 | mPullLabel = pullLabel;
302 | }
303 |
304 | public void setRefreshingLabel(CharSequence refreshingLabel) {
305 | mRefreshingLabel = refreshingLabel;
306 | }
307 |
308 | public void setReleaseLabel(CharSequence releaseLabel) {
309 | mReleaseLabel = releaseLabel;
310 | }
311 |
312 | @Override
313 | public void setTextTypeface(Typeface tf) {
314 | mHeaderText.setTypeface(tf);
315 | }
316 |
317 | public final void showInvisibleViews() {
318 | if (View.INVISIBLE == mHeaderText.getVisibility()) {
319 | mHeaderText.setVisibility(View.VISIBLE);
320 | }
321 | if (View.INVISIBLE == mHeaderProgress.getVisibility()) {
322 | mHeaderProgress.setVisibility(View.VISIBLE);
323 | }
324 | if (View.INVISIBLE == mHeaderImage.getVisibility()) {
325 | mHeaderImage.setVisibility(View.VISIBLE);
326 | }
327 | if (View.INVISIBLE == mSubHeaderText.getVisibility()) {
328 | mSubHeaderText.setVisibility(View.VISIBLE);
329 | }
330 | }
331 |
332 | /**
333 | * Callbacks for derivative Layouts
334 | */
335 |
336 | protected abstract int getDefaultDrawableResId();
337 |
338 | protected abstract void onLoadingDrawableSet(Drawable imageDrawable);
339 |
340 | protected abstract void onPullImpl(float scaleOfLayout);
341 |
342 | protected abstract void pullToRefreshImpl();
343 |
344 | protected abstract void refreshingImpl();
345 |
346 | protected abstract void releaseToRefreshImpl();
347 |
348 | protected abstract void resetImpl();
349 |
350 | private void setSubHeaderText(CharSequence label) {
351 | if (null != mSubHeaderText) {
352 | if (TextUtils.isEmpty(label)) {
353 | mSubHeaderText.setVisibility(View.GONE);
354 | } else {
355 | mSubHeaderText.setText(label);
356 |
357 | // Only set it to Visible if we're GONE, otherwise VISIBLE will
358 | // be set soon
359 | if (View.GONE == mSubHeaderText.getVisibility()) {
360 | mSubHeaderText.setVisibility(View.VISIBLE);
361 | }
362 | }
363 | }
364 | }
365 |
366 | private void setSubTextAppearance(int value) {
367 | if (null != mSubHeaderText) {
368 | mSubHeaderText.setTextAppearance(getContext(), value);
369 | }
370 | }
371 |
372 | private void setSubTextColor(ColorStateList color) {
373 | if (null != mSubHeaderText) {
374 | mSubHeaderText.setTextColor(color);
375 | }
376 | }
377 |
378 | private void setTextAppearance(int value) {
379 | if (null != mHeaderText) {
380 | mHeaderText.setTextAppearance(getContext(), value);
381 | }
382 | if (null != mSubHeaderText) {
383 | mSubHeaderText.setTextAppearance(getContext(), value);
384 | }
385 | }
386 |
387 | private void setTextColor(ColorStateList color) {
388 | if (null != mHeaderText) {
389 | mHeaderText.setTextColor(color);
390 | }
391 | if (null != mSubHeaderText) {
392 | mSubHeaderText.setTextColor(color);
393 | }
394 | }
395 |
396 | }
397 |
--------------------------------------------------------------------------------
/library/src/main/java/com/handmark/pulltorefresh/library/PullToRefreshAdapterViewBase.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2011, 2012 Chris Banes.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *******************************************************************************/
16 | package com.handmark.pulltorefresh.library;
17 |
18 | import android.content.Context;
19 | import android.content.res.TypedArray;
20 | import android.util.AttributeSet;
21 | import android.util.Log;
22 | import android.view.Gravity;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 | import android.view.ViewParent;
26 | import android.widget.AbsListView;
27 | import android.widget.AbsListView.OnScrollListener;
28 | import android.widget.Adapter;
29 | import android.widget.AdapterView;
30 | import android.widget.AdapterView.OnItemClickListener;
31 | import android.widget.FrameLayout;
32 | import android.widget.LinearLayout;
33 | import android.widget.ListAdapter;
34 |
35 | import com.bettycc.animatepulltorefresh.library.R;
36 | import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor;
37 | import com.handmark.pulltorefresh.library.internal.IndicatorLayout;
38 |
39 | public abstract class PullToRefreshAdapterViewBase extends PullToRefreshBase implements
40 | OnScrollListener {
41 |
42 | private static FrameLayout.LayoutParams convertEmptyViewLayoutParams(ViewGroup.LayoutParams lp) {
43 | FrameLayout.LayoutParams newLp = null;
44 |
45 | if (null != lp) {
46 | newLp = new FrameLayout.LayoutParams(lp);
47 |
48 | if (lp instanceof LinearLayout.LayoutParams) {
49 | newLp.gravity = ((LinearLayout.LayoutParams) lp).gravity;
50 | } else {
51 | newLp.gravity = Gravity.CENTER;
52 | }
53 | }
54 |
55 | return newLp;
56 | }
57 |
58 | private boolean mLastItemVisible;
59 | private OnScrollListener mOnScrollListener;
60 | private OnLastItemVisibleListener mOnLastItemVisibleListener;
61 | private View mEmptyView;
62 |
63 | private IndicatorLayout mIndicatorIvTop;
64 | private IndicatorLayout mIndicatorIvBottom;
65 |
66 | private boolean mShowIndicator;
67 | private boolean mScrollEmptyView = true;
68 |
69 | public PullToRefreshAdapterViewBase(Context context) {
70 | super(context);
71 | mRefreshableView.setOnScrollListener(this);
72 | }
73 |
74 | public PullToRefreshAdapterViewBase(Context context, AttributeSet attrs) {
75 | super(context, attrs);
76 | mRefreshableView.setOnScrollListener(this);
77 | }
78 |
79 | public PullToRefreshAdapterViewBase(Context context, Mode mode) {
80 | super(context, mode);
81 | mRefreshableView.setOnScrollListener(this);
82 | }
83 |
84 | public PullToRefreshAdapterViewBase(Context context, Mode mode, AnimationStyle animStyle) {
85 | super(context, mode, animStyle);
86 | mRefreshableView.setOnScrollListener(this);
87 | }
88 |
89 | /**
90 | * Gets whether an indicator graphic should be displayed when the View is in
91 | * a state where a Pull-to-Refresh can happen. An example of this state is
92 | * when the Adapter View is scrolled to the top and the mode is set to
93 | * {@link Mode#PULL_FROM_START}. The default value is true if
94 | * {@link PullToRefreshBase#isPullToRefreshOverScrollEnabled()
95 | * isPullToRefreshOverScrollEnabled()} returns false.
96 | *
97 | * @return true if the indicators will be shown
98 | */
99 | public boolean getShowIndicator() {
100 | return mShowIndicator;
101 | }
102 |
103 | public final void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
104 | final int totalItemCount) {
105 |
106 | if (DEBUG) {
107 | Log.d(LOG_TAG, "First Visible: " + firstVisibleItem + ". Visible Count: " + visibleItemCount
108 | + ". Total Items:" + totalItemCount);
109 | }
110 |
111 | /**
112 | * Set whether the Last Item is Visible. lastVisibleItemIndex is a
113 | * zero-based index, so we minus one totalItemCount to check
114 | */
115 | if (null != mOnLastItemVisibleListener) {
116 | mLastItemVisible = (totalItemCount > 0) && (firstVisibleItem + visibleItemCount >= totalItemCount - 1);
117 | }
118 |
119 | // If we're showing the indicator, check positions...
120 | if (getShowIndicatorInternal()) {
121 | updateIndicatorViewsVisibility();
122 | }
123 |
124 | // Finally call OnScrollListener if we have one
125 | if (null != mOnScrollListener) {
126 | mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
127 | }
128 | }
129 |
130 | public final void onScrollStateChanged(final AbsListView view, final int state) {
131 | /**
132 | * Check that the scrolling has stopped, and that the last item is
133 | * visible.
134 | */
135 | if (state == OnScrollListener.SCROLL_STATE_IDLE && null != mOnLastItemVisibleListener && mLastItemVisible) {
136 | mOnLastItemVisibleListener.onLastItemVisible();
137 | }
138 |
139 | if (null != mOnScrollListener) {
140 | mOnScrollListener.onScrollStateChanged(view, state);
141 | }
142 | }
143 |
144 | /**
145 | * Pass-through method for {@link PullToRefreshBase#getRefreshableView()
146 | * getRefreshableView()}.
147 | * {@link AdapterView#setAdapter(android.widget.Adapter)}
148 | * setAdapter(adapter)}. This is just for convenience!
149 | *
150 | * @param adapter - Adapter to set
151 | */
152 | public void setAdapter(ListAdapter adapter) {
153 | ((AdapterView) mRefreshableView).setAdapter(adapter);
154 | }
155 |
156 | /**
157 | * Sets the Empty View to be used by the Adapter View.
158 | *
159 | * We need it handle it ourselves so that we can Pull-to-Refresh when the
160 | * Empty View is shown.
161 | *
162 | * Please note, you do not usually need to call this method
163 | * yourself. Calling setEmptyView on the AdapterView will automatically call
164 | * this method and set everything up. This includes when the Android
165 | * Framework automatically sets the Empty View based on it's ID.
166 | *
167 | * @param newEmptyView - Empty View to be used
168 | */
169 | public final void setEmptyView(View newEmptyView) {
170 | FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();
171 |
172 | if (null != newEmptyView) {
173 | // New view needs to be clickable so that Android recognizes it as a
174 | // target for Touch Events
175 | newEmptyView.setClickable(true);
176 |
177 | ViewParent newEmptyViewParent = newEmptyView.getParent();
178 | if (null != newEmptyViewParent && newEmptyViewParent instanceof ViewGroup) {
179 | ((ViewGroup) newEmptyViewParent).removeView(newEmptyView);
180 | }
181 |
182 | // We need to convert any LayoutParams so that it works in our
183 | // FrameLayout
184 | FrameLayout.LayoutParams lp = convertEmptyViewLayoutParams(newEmptyView.getLayoutParams());
185 | if (null != lp) {
186 | refreshableViewWrapper.addView(newEmptyView, lp);
187 | } else {
188 | refreshableViewWrapper.addView(newEmptyView);
189 | }
190 | }
191 |
192 | if (mRefreshableView instanceof EmptyViewMethodAccessor) {
193 | ((EmptyViewMethodAccessor) mRefreshableView).setEmptyViewInternal(newEmptyView);
194 | } else {
195 | mRefreshableView.setEmptyView(newEmptyView);
196 | }
197 | mEmptyView = newEmptyView;
198 | }
199 |
200 | /**
201 | * Pass-through method for {@link PullToRefreshBase#getRefreshableView()
202 | * getRefreshableView()}.
203 | * {@link AdapterView#setOnItemClickListener(OnItemClickListener)
204 | * setOnItemClickListener(listener)}. This is just for convenience!
205 | *
206 | * @param listener - OnItemClickListener to use
207 | */
208 | public void setOnItemClickListener(OnItemClickListener listener) {
209 | mRefreshableView.setOnItemClickListener(listener);
210 | }
211 |
212 | public final void setOnLastItemVisibleListener(OnLastItemVisibleListener listener) {
213 | mOnLastItemVisibleListener = listener;
214 | }
215 |
216 | public final void setOnScrollListener(OnScrollListener listener) {
217 | mOnScrollListener = listener;
218 | }
219 |
220 | public final void setScrollEmptyView(boolean doScroll) {
221 | mScrollEmptyView = doScroll;
222 | }
223 |
224 | /**
225 | * Sets whether an indicator graphic should be displayed when the View is in
226 | * a state where a Pull-to-Refresh can happen. An example of this state is
227 | * when the Adapter View is scrolled to the top and the mode is set to
228 | * {@link Mode#PULL_FROM_START}
229 | *
230 | * @param showIndicator - true if the indicators should be shown.
231 | */
232 | public void setShowIndicator(boolean showIndicator) {
233 | mShowIndicator = showIndicator;
234 |
235 | if (getShowIndicatorInternal()) {
236 | // If we're set to Show Indicator, add/update them
237 | addIndicatorViews();
238 | } else {
239 | // If not, then remove then
240 | removeIndicatorViews();
241 | }
242 | }
243 |
244 | ;
245 |
246 | @Override
247 | protected void onPullToRefresh() {
248 | super.onPullToRefresh();
249 |
250 | if (getShowIndicatorInternal()) {
251 | switch (getCurrentMode()) {
252 | case PULL_FROM_END:
253 | mIndicatorIvBottom.pullToRefresh();
254 | break;
255 | case PULL_FROM_START:
256 | mIndicatorIvTop.pullToRefresh();
257 | break;
258 | default:
259 | // NO-OP
260 | break;
261 | }
262 | }
263 | }
264 |
265 | protected void onRefreshing(boolean doScroll) {
266 | super.onRefreshing(doScroll);
267 |
268 | if (getShowIndicatorInternal()) {
269 | updateIndicatorViewsVisibility();
270 | }
271 | }
272 |
273 | @Override
274 | protected void onReleaseToRefresh() {
275 | super.onReleaseToRefresh();
276 |
277 | if (getShowIndicatorInternal()) {
278 | switch (getCurrentMode()) {
279 | case PULL_FROM_END:
280 | mIndicatorIvBottom.releaseToRefresh();
281 | break;
282 | case PULL_FROM_START:
283 | mIndicatorIvTop.releaseToRefresh();
284 | break;
285 | default:
286 | // NO-OP
287 | break;
288 | }
289 | }
290 | }
291 |
292 | @Override
293 | protected void onReset() {
294 | super.onReset();
295 |
296 | if (getShowIndicatorInternal()) {
297 | updateIndicatorViewsVisibility();
298 | }
299 | }
300 |
301 | @Override
302 | protected void handleStyledAttributes(TypedArray a) {
303 | // Set Show Indicator to the XML value, or default value
304 | mShowIndicator = a.getBoolean(R.styleable.PullToRefresh_ptrShowIndicator, !isPullToRefreshOverScrollEnabled());
305 | }
306 |
307 | protected boolean isReadyForPullStart() {
308 | return isFirstItemVisible();
309 | }
310 |
311 | protected boolean isReadyForPullEnd() {
312 | return isLastItemVisible();
313 | }
314 |
315 | @Override
316 | protected void onScrollChanged(int l, int t, int oldl, int oldt) {
317 | super.onScrollChanged(l, t, oldl, oldt);
318 | if (null != mEmptyView && !mScrollEmptyView) {
319 | mEmptyView.scrollTo(-l, -t);
320 | }
321 | }
322 |
323 | @Override
324 | protected void updateUIForMode() {
325 | super.updateUIForMode();
326 |
327 | // Check Indicator Views consistent with new Mode
328 | if (getShowIndicatorInternal()) {
329 | addIndicatorViews();
330 | } else {
331 | removeIndicatorViews();
332 | }
333 | }
334 |
335 | private void addIndicatorViews() {
336 | Mode mode = getMode();
337 | FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();
338 |
339 | if (mode.showHeaderLoadingLayout() && null == mIndicatorIvTop) {
340 | // If the mode can pull down, and we don't have one set already
341 | mIndicatorIvTop = new IndicatorLayout(getContext(), Mode.PULL_FROM_START);
342 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
343 | ViewGroup.LayoutParams.WRAP_CONTENT);
344 | params.rightMargin = getResources().getDimensionPixelSize(R.dimen.indicator_right_padding);
345 | params.gravity = Gravity.TOP | Gravity.RIGHT;
346 | refreshableViewWrapper.addView(mIndicatorIvTop, params);
347 |
348 | } else if (!mode.showHeaderLoadingLayout() && null != mIndicatorIvTop) {
349 | // If we can't pull down, but have a View then remove it
350 | refreshableViewWrapper.removeView(mIndicatorIvTop);
351 | mIndicatorIvTop = null;
352 | }
353 |
354 | if (mode.showFooterLoadingLayout() && null == mIndicatorIvBottom) {
355 | // If the mode can pull down, and we don't have one set already
356 | mIndicatorIvBottom = new IndicatorLayout(getContext(), Mode.PULL_FROM_END);
357 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
358 | ViewGroup.LayoutParams.WRAP_CONTENT);
359 | params.rightMargin = getResources().getDimensionPixelSize(R.dimen.indicator_right_padding);
360 | params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
361 | refreshableViewWrapper.addView(mIndicatorIvBottom, params);
362 |
363 | } else if (!mode.showFooterLoadingLayout() && null != mIndicatorIvBottom) {
364 | // If we can't pull down, but have a View then remove it
365 | refreshableViewWrapper.removeView(mIndicatorIvBottom);
366 | mIndicatorIvBottom = null;
367 | }
368 | }
369 |
370 | private boolean getShowIndicatorInternal() {
371 | return mShowIndicator && isPullToRefreshEnabled();
372 | }
373 |
374 | private boolean isFirstItemVisible() {
375 | final Adapter adapter = mRefreshableView.getAdapter();
376 |
377 | if (null == adapter || adapter.isEmpty()) {
378 | if (DEBUG) {
379 | Log.d(LOG_TAG, "isFirstItemVisible. Empty View.");
380 | }
381 | return true;
382 |
383 | } else {
384 |
385 | /**
386 | * This check should really just be:
387 | * mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView
388 | * internally use a HeaderView which messes the positions up. For
389 | * now we'll just add one to account for it and rely on the inner
390 | * condition which checks getTop().
391 | */
392 | if (mRefreshableView.getFirstVisiblePosition() <= 1) {
393 | final View firstVisibleChild = mRefreshableView.getChildAt(0);
394 | if (firstVisibleChild != null) {
395 | return firstVisibleChild.getTop() >= mRefreshableView.getTop();
396 | }
397 | }
398 | }
399 |
400 | return false;
401 | }
402 |
403 | private boolean isLastItemVisible() {
404 | final Adapter adapter = mRefreshableView.getAdapter();
405 |
406 | if (null == adapter || adapter.isEmpty()) {
407 | if (DEBUG) {
408 | Log.d(LOG_TAG, "isLastItemVisible. Empty View.");
409 | }
410 | return true;
411 | } else {
412 | final int lastItemPosition = mRefreshableView.getCount() - 1;
413 | final int lastVisiblePosition = mRefreshableView.getLastVisiblePosition();
414 |
415 | if (DEBUG) {
416 | Log.d(LOG_TAG, "isLastItemVisible. Last Item Position: " + lastItemPosition + " Last Visible Pos: "
417 | + lastVisiblePosition);
418 | }
419 |
420 | /**
421 | * This check should really just be: lastVisiblePosition ==
422 | * lastItemPosition, but PtRListView internally uses a FooterView
423 | * which messes the positions up. For me we'll just subtract one to
424 | * account for it and rely on the inner condition which checks
425 | * getBottom().
426 | */
427 | if (lastVisiblePosition >= lastItemPosition - 1) {
428 | final int childIndex = lastVisiblePosition - mRefreshableView.getFirstVisiblePosition();
429 | final View lastVisibleChild = mRefreshableView.getChildAt(childIndex);
430 | if (lastVisibleChild != null) {
431 | return lastVisibleChild.getBottom() <= mRefreshableView.getBottom();
432 | }
433 | }
434 | }
435 |
436 | return false;
437 | }
438 |
439 | private void removeIndicatorViews() {
440 | if (null != mIndicatorIvTop) {
441 | getRefreshableViewWrapper().removeView(mIndicatorIvTop);
442 | mIndicatorIvTop = null;
443 | }
444 |
445 | if (null != mIndicatorIvBottom) {
446 | getRefreshableViewWrapper().removeView(mIndicatorIvBottom);
447 | mIndicatorIvBottom = null;
448 | }
449 | }
450 |
451 | private void updateIndicatorViewsVisibility() {
452 | if (null != mIndicatorIvTop) {
453 | if (!isRefreshing() && isReadyForPullStart()) {
454 | if (!mIndicatorIvTop.isVisible()) {
455 | mIndicatorIvTop.show();
456 | }
457 | } else {
458 | if (mIndicatorIvTop.isVisible()) {
459 | mIndicatorIvTop.hide();
460 | }
461 | }
462 | }
463 |
464 | if (null != mIndicatorIvBottom) {
465 | if (!isRefreshing() && isReadyForPullEnd()) {
466 | if (!mIndicatorIvBottom.isVisible()) {
467 | mIndicatorIvBottom.show();
468 | }
469 | } else {
470 | if (mIndicatorIvBottom.isVisible()) {
471 | mIndicatorIvBottom.hide();
472 | }
473 | }
474 | }
475 | }
476 | }
477 |
--------------------------------------------------------------------------------