├── ptr-demo ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── drawable-hdpi │ │ │ ├── sky.png │ │ │ ├── sun.png │ │ │ ├── buildings.png │ │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ │ ├── sky.png │ │ │ ├── sun.png │ │ │ ├── buildings.png │ │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ │ ├── sky.png │ │ │ ├── sun.png │ │ │ ├── buildings.png │ │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ │ ├── sky.png │ │ │ ├── sun.png │ │ │ ├── buildings.png │ │ │ └── ic_launcher.png │ │ ├── drawable-xxxhdpi │ │ │ ├── sky.png │ │ │ ├── sun.png │ │ │ └── buildings.png │ │ ├── values │ │ │ ├── ptr_demo_colors.xml │ │ │ ├── arrays.xml │ │ │ └── strings.xml │ │ ├── drawable │ │ │ ├── image_border.xml │ │ │ ├── text_view_bg.xml │ │ │ └── with_long_press_list_item_background.xml │ │ ├── layout │ │ │ ├── activity_main.xml │ │ │ ├── view_pager_fragment_list_view_header.xml │ │ │ ├── fragment_view_pager.xml │ │ │ ├── with_grid_view_item_image_list_grid.xml │ │ │ ├── list_view_item.xml │ │ │ ├── with_long_press_list_view_item.xml │ │ │ ├── fragment_classic_header_with_webview.xml │ │ │ ├── view_pager_indicator_item.xml │ │ │ ├── activity_view_pager.xml │ │ │ ├── fragment_with_long_press.xml │ │ │ ├── fragment_classic_header_with_list_view.xml │ │ │ ├── fragmengt_ptr_home.xml │ │ │ ├── fragment_storehouse_header.xml │ │ │ ├── fragment_materail_style.xml │ │ │ ├── fragment_classic_header_with_textview.xml │ │ │ ├── fragment_classic_header_with_gridview.xml │ │ │ ├── fragment_classic_header_with_viewgroup.xml │ │ │ ├── fragment_classic_header_with_list_view_and_empty_view.xml │ │ │ └── fragment_classic_header_with_scroll_view.xml │ │ └── values-zh │ │ │ └── strings.xml │ │ ├── java │ │ └── in │ │ │ └── srain │ │ │ └── cube │ │ │ └── views │ │ │ └── ptr │ │ │ └── demo │ │ │ ├── ui │ │ │ ├── classic │ │ │ │ ├── KeepHeader.java │ │ │ │ ├── PullToRefresh.java │ │ │ │ ├── ReleaseToRefresh.java │ │ │ │ ├── AutoRefresh.java │ │ │ │ ├── FooterFeatures.java │ │ │ │ ├── HideHeader.java │ │ │ │ ├── EvenOnlyATextView.java │ │ │ │ ├── WithTextViewInFrameLayoutFragment.java │ │ │ │ ├── WithScrollView.java │ │ │ │ ├── WithWebView.java │ │ │ │ ├── WithListView.java │ │ │ │ ├── WithListViewAndEmptyView.java │ │ │ │ ├── WithGridViewInFrameLayout.java │ │ │ │ └── WithGridView.java │ │ │ ├── EnableNextPTRAtOnce.java │ │ │ ├── MaterialStylePinContentFragment.java │ │ │ ├── activity │ │ │ │ └── PtrDemoHomeActivity.java │ │ │ ├── Utils.java │ │ │ ├── viewpager │ │ │ │ ├── ImageListViewHolder.java │ │ │ │ ├── ViewPagerFragment.java │ │ │ │ └── ViewPagerActivity.java │ │ │ ├── header │ │ │ │ └── RentalsSunHeaderView.java │ │ │ ├── WithLongPressFragment.java │ │ │ ├── storehouse │ │ │ │ ├── StoreHouseUsingString.java │ │ │ │ ├── StoreHouseUsingStringArray.java │ │ │ │ └── StoreHouseUsingPointList.java │ │ │ ├── RentalsStyleFragment.java │ │ │ └── MaterialStyleFragment.java │ │ │ ├── data │ │ │ └── DemoRequestData.java │ │ │ ├── image │ │ │ ├── PtrImageLoadHandler.java │ │ │ └── DemoDuiTangImageReSizer.java │ │ │ └── app │ │ │ └── PtrDemoApplication.java │ │ ├── AndroidManifest.xml │ │ └── assets │ │ └── request_init │ │ └── demo │ │ └── image-list.json ├── proguard-rules.pro └── build.gradle ├── ptr-lib ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── drawable-xhdpi │ │ │ ├── ptr_rotate_arrow.png │ │ │ └── ptr_rotate_arrow_up.png │ │ ├── layout │ │ │ ├── cube_ptr_simple_loading.xml │ │ │ ├── cube_ptr_classic_default_header.xml │ │ │ └── cube_ptr_classic_default_footer.xml │ │ ├── values-zh │ │ │ └── cube_ptr_string.xml │ │ └── values │ │ │ ├── cube_ptr_string.xml │ │ │ └── cube_ptr_attrs.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── in │ │ └── srain │ │ └── cube │ │ └── views │ │ └── ptr │ │ ├── PtrHandler2.java │ │ ├── PtrHandler.java │ │ ├── PtrUIHandler.java │ │ ├── PtrDefaultHandler.java │ │ ├── PtrUIHandlerHook.java │ │ ├── util │ │ ├── PtrLocalDisplay.java │ │ └── PtrCLog.java │ │ ├── PtrDefaultHandler2.java │ │ ├── header │ │ ├── StoreHouseBarItem.java │ │ └── MaterialHeader.java │ │ ├── PtrClassicFrameLayout.java │ │ ├── indicator │ │ ├── PtrTensionIndicator.java │ │ └── PtrIndicator.java │ │ └── PtrUIHandlerHolder.java ├── project.properties ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── index.html ├── ptr-demo.apk ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── android-artifacts.gradle └── gradle-jcenter-push.gradle ├── .gitignore ├── LICENSE ├── gradle.properties ├── gradlew.bat └── gradlew /ptr-demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /ptr-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':ptr-lib', ':ptr-demo' -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/index.html -------------------------------------------------------------------------------- /ptr-demo.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo.apk -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .local.properties 9 | /ptr-lib/local.properties 10 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-hdpi/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-hdpi/sky.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-hdpi/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-hdpi/sun.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-mdpi/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-mdpi/sky.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-mdpi/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-mdpi/sun.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xhdpi/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xhdpi/sky.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xhdpi/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xhdpi/sun.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xxhdpi/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xxhdpi/sky.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xxhdpi/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xxhdpi/sun.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xxxhdpi/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xxxhdpi/sky.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xxxhdpi/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xxxhdpi/sun.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-hdpi/buildings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-hdpi/buildings.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-mdpi/buildings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-mdpi/buildings.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xhdpi/buildings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xhdpi/buildings.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xxhdpi/buildings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xxhdpi/buildings.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable-xxxhdpi/buildings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-demo/src/main/res/drawable-xxxhdpi/buildings.png -------------------------------------------------------------------------------- /ptr-lib/src/main/res/drawable-xhdpi/ptr_rotate_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-lib/src/main/res/drawable-xhdpi/ptr_rotate_arrow.png -------------------------------------------------------------------------------- /ptr-lib/src/main/res/drawable-xhdpi/ptr_rotate_arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/HEAD/ptr-lib/src/main/res/drawable-xhdpi/ptr_rotate_arrow_up.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Aug 24 14:08:07 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/values/ptr_demo_colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFC93437 4 | #FF375BF1 5 | #FFF7D23E 6 | #FF34A350 7 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable/image_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable/text_view_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ptr-lib/src/main/res/layout/cube_ptr_simple_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /ptr-lib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/drawable/with_long_press_list_item_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ptr-lib/project.properties: -------------------------------------------------------------------------------- 1 | #project 2 | project.name=Ultra-Pull-to-Refresh-with-Load-More 3 | project.groupId=in.srain.cube 4 | project.artifactId=ultra-ptr-load-more 5 | project.packaging=aar 6 | project.siteUrl=https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More 7 | project.gitUrl=https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More.git 8 | 9 | #javadoc 10 | javadoc.name=Ultra-Pull-to-Refresh-with-Load-More 11 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /gradle/android-artifacts.gradle: -------------------------------------------------------------------------------- 1 | task androidJavadocs(type: Javadoc) { 2 | source = android.sourceSets.main.java.srcDirs 3 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 4 | } 5 | 6 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 7 | classifier = 'javadoc' 8 | from androidJavadocs.destinationDir 9 | } 10 | 11 | task androidSourcesJar(type: Jar) { 12 | classifier = 'sources' 13 | from android.sourceSets.main.java.sourceFiles 14 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/KeepHeader.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 4 | import in.srain.cube.views.ptr.demo.R; 5 | 6 | public class KeepHeader extends WithTextViewInFrameLayoutFragment { 7 | 8 | @Override 9 | protected void setupViews(PtrClassicFrameLayout ptrFrame) { 10 | setHeaderTitle(R.string.ptr_demo_block_keep_header); 11 | ptrFrame.setKeepHeaderWhenRefresh(true); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/PullToRefresh.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 4 | import in.srain.cube.views.ptr.demo.R; 5 | 6 | public class PullToRefresh extends WithTextViewInFrameLayoutFragment { 7 | 8 | @Override 9 | protected void setupViews(PtrClassicFrameLayout ptrFrame) { 10 | setHeaderTitle(R.string.ptr_demo_block_pull_to_refresh); 11 | ptrFrame.setPullToRefresh(true); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/ReleaseToRefresh.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 4 | import in.srain.cube.views.ptr.demo.R; 5 | 6 | public class ReleaseToRefresh extends WithTextViewInFrameLayoutFragment { 7 | 8 | @Override 9 | protected void setupViews(PtrClassicFrameLayout ptrFrame) { 10 | setHeaderTitle(R.string.ptr_demo_block_release_to_refresh); 11 | ptrFrame.setPullToRefresh(false); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/EnableNextPTRAtOnce.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui; 2 | 3 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 4 | import in.srain.cube.views.ptr.demo.R; 5 | import in.srain.cube.views.ptr.demo.ui.classic.WithTextViewInFrameLayoutFragment; 6 | 7 | public class EnableNextPTRAtOnce extends WithTextViewInFrameLayoutFragment { 8 | 9 | @Override 10 | protected void setupViews(PtrClassicFrameLayout ptrFrame) { 11 | setHeaderTitle(R.string.ptr_demo_enable_next_ptr_at_once); 12 | ptrFrame.setEnabledNextPtrAtOnce(true); 13 | ptrFrame.setPullToRefresh(false); 14 | } 15 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/PtrHandler2.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr; 2 | 3 | import android.view.View; 4 | 5 | public interface PtrHandler2 extends PtrHandler{ 6 | 7 | /** 8 | * Check can do load more or not. For example the content is empty or the first child is in view. 9 | * 10 | * {@link PtrDefaultHandler#checkContentCanBePulledDown} 11 | */ 12 | abstract boolean checkCanDoLoadMore(final PtrFrameLayout frame, final View content, final View footer); 13 | 14 | /** 15 | * When load more begin 16 | * 17 | * @param frame 18 | */ 19 | public abstract void onLoadMoreBegin(final PtrFrameLayout frame); 20 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/AutoRefresh.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 4 | import in.srain.cube.views.ptr.demo.R; 5 | 6 | public class AutoRefresh extends WithGridView { 7 | 8 | @Override 9 | protected void setupViews(final PtrClassicFrameLayout ptrFrame) { 10 | ptrFrame.setLoadingMinTime(3000); 11 | setHeaderTitle(R.string.ptr_demo_block_auto_fresh); 12 | ptrFrame.postDelayed(new Runnable() { 13 | @Override 14 | public void run() { 15 | ptrFrame.autoRefresh(true); 16 | } 17 | }, 150); 18 | } 19 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/MaterialStylePinContentFragment.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | public class MaterialStylePinContentFragment extends MaterialStyleFragment { 9 | 10 | @Override 11 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 12 | View view = super.createView(inflater, container, savedInstanceState); 13 | // close at once 14 | mPtrFrameLayout.setDurationToClose(100); 15 | mPtrFrameLayout.setPinContent(true); 16 | return view; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/view_pager_fragment_list_view_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/PtrHandler.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr; 2 | 3 | import android.view.View; 4 | 5 | import in.srain.cube.views.ptr.indicator.PtrIndicator; 6 | 7 | public interface PtrHandler { 8 | 9 | /** 10 | * Check can do refresh or not. For example the content is empty or the first child is in view. 11 | * 12 | * {@link in.srain.cube.views.ptr.PtrDefaultHandler#checkContentCanBePulledDown} 13 | */ 14 | abstract boolean checkCanDoRefresh(final PtrFrameLayout frame, final View content, final View header); 15 | 16 | /** 17 | * When refresh begin 18 | * 19 | * @param frame 20 | */ 21 | public abstract void onRefreshBegin(final PtrFrameLayout frame); 22 | } -------------------------------------------------------------------------------- /ptr-lib/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/weizhou1/Library/Android/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 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/activity/PtrDemoHomeActivity.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import in.srain.cube.mints.base.MintsBaseActivity; 5 | import in.srain.cube.views.ptr.demo.R; 6 | import in.srain.cube.views.ptr.demo.ui.PtrDemoHomeFragment; 7 | 8 | public class PtrDemoHomeActivity extends MintsBaseActivity { 9 | 10 | @Override 11 | protected void onCreate(Bundle bundle) { 12 | super.onCreate(bundle); 13 | setContentView(R.layout.activity_main); 14 | pushFragmentToBackStack(PtrDemoHomeFragment.class, null); 15 | } 16 | 17 | @Override 18 | protected int getFragmentContainerId() { 19 | return R.id.id_fragment; 20 | } 21 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_view_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/with_grid_view_item_image_list_grid.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/FooterFeatures.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 4 | import in.srain.cube.views.ptr.demo.R; 5 | 6 | public class FooterFeatures extends WithGridView { 7 | 8 | @Override 9 | protected void setupViews(final PtrClassicFrameLayout ptrFrame) { 10 | ptrFrame.setLoadingMinTime(3000); 11 | setHeaderTitle(R.string.ptr_demo_block_grid_view_footer); 12 | ptrFrame.setResistanceFooter(1.0f); 13 | ptrFrame.setDurationToCloseFooter(0); // footer will hide immediately when completed 14 | ptrFrame.setForceBackWhenComplete(true); 15 | ptrFrame.postDelayed(new Runnable() { 16 | @Override 17 | public void run() { 18 | ptrFrame.autoLoadMore(true); 19 | } 20 | }, 150); 21 | } 22 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/list_view_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/Utils.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.widget.RelativeLayout; 7 | import in.srain.cube.util.LocalDisplay; 8 | import in.srain.cube.views.ptr.demo.R; 9 | 10 | public class Utils { 11 | 12 | public static View createSimpleLoadingTip(Context context) { 13 | final View view = LayoutInflater.from(context).inflate(R.layout.cube_ptr_simple_loading, null); 14 | RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(-2, -2); 15 | lp.setMargins(0, 0, 0, LocalDisplay.dp2px(4)); 16 | lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 17 | lp.addRule(RelativeLayout.CENTER_VERTICAL); 18 | view.setLayoutParams(lp); 19 | view.setVisibility(View.INVISIBLE); 20 | return view; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ptr-demo/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/weizhou1/Library/Android/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 | -keep class in.srain.* 19 | -dontwarn class in.srain.cube.image.ImageProvider 20 | -dontwarn class android.graphics.Bitmap 21 | -ignorewarnings class in.srain.cube.image.ImageProvider 22 | -ignorewarnings class android.graphics.Bitmap -------------------------------------------------------------------------------- /ptr-lib/src/main/res/values-zh/cube_ptr_string.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 上拉 5 | 上拉加载 6 | 释放加载 7 | 下拉 8 | 下拉刷新 9 | 释放刷新 10 | 更新中... 11 | 更新完成. 12 | 加载中... 13 | 加载完成. 14 | 15 | 上次更新:  16 |  秒之前 17 |  分钟之前 18 |  小时之前 19 | 20 | -------------------------------------------------------------------------------- /ptr-lib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | 5 | compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) 6 | buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION 7 | 8 | defaultConfig { 9 | minSdkVersion 8 10 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) 11 | versionCode Integer.parseInt(project.VERSION_CODE) 12 | versionName project.VERSION_NAME 13 | } 14 | 15 | lintOptions { 16 | abortOnError false 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | } 26 | 27 | dependencies { 28 | } 29 | 30 | apply from: rootProject.file('gradle/android-artifacts.gradle') 31 | apply from: rootProject.file('gradle/gradle-jcenter-push.gradle') 32 | //apply from: "bintrayUpload.gradle" 33 | 34 | -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/PtrUIHandler.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr; 2 | 3 | import in.srain.cube.views.ptr.indicator.PtrIndicator; 4 | 5 | /** 6 | * 7 | */ 8 | public interface PtrUIHandler { 9 | 10 | /** 11 | * When the content view has reached top and refresh has been completed, view will be reset. 12 | * 13 | * @param frame 14 | */ 15 | public void onUIReset(PtrFrameLayout frame); 16 | 17 | /** 18 | * prepare for loading 19 | * 20 | * @param frame 21 | */ 22 | public void onUIRefreshPrepare(PtrFrameLayout frame); 23 | 24 | /** 25 | * perform refreshing UI 26 | */ 27 | public void onUIRefreshBegin(PtrFrameLayout frame); 28 | 29 | /** 30 | * perform UI after refresh 31 | */ 32 | public void onUIRefreshComplete(PtrFrameLayout frame, boolean isHeader); 33 | 34 | public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator); 35 | } 36 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/with_long_press_list_view_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 15 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ptr-lib/src/main/res/values/cube_ptr_string.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pull Up 5 | Pull Up to Load 6 | Release To Load 7 | Pull Down 8 | Pull Down to Refresh 9 | Release To Refresh 10 | Updating... 11 | Loading... 12 | Updated. 13 | Loaded. 14 | 15 | last update:  16 |  seconds ago 17 |  minutes ago 18 |  hours ago 19 | 20 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/data/DemoRequestData.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.data; 2 | 3 | import in.srain.cube.request.*; 4 | 5 | public class DemoRequestData { 6 | 7 | public static void getImageList(final RequestFinishHandler requestFinishHandler) { 8 | 9 | CacheAbleRequestHandler requestHandler = new CacheAbleRequestJsonHandler() { 10 | @Override 11 | public void onCacheAbleRequestFinish(JsonData data, CacheAbleRequest.ResultType type, boolean outOfDate) { 12 | requestFinishHandler.onRequestFinish(data); 13 | } 14 | }; 15 | 16 | CacheAbleRequest request = new CacheAbleRequest(requestHandler); 17 | String url = "http://cube-server.liaohuqiu.net/api_demo/image-list.php"; 18 | request.setCacheTime(3600); 19 | request.setTimeout(1000); 20 | request.getRequestData().setRequestUrl(url); 21 | request.setAssertInitDataPath("request_init/demo/image-list.json"); 22 | request.setCacheKey("image-list-1"); 23 | request.send(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Weizhou He 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_classic_header_with_webview.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 17 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/view_pager_indicator_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 22 | 23 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/viewpager/ImageListViewHolder.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.viewpager; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.widget.ImageView; 6 | import in.srain.cube.image.CubeImageView; 7 | import in.srain.cube.image.ImageLoader; 8 | import in.srain.cube.request.JsonData; 9 | import in.srain.cube.views.list.ViewHolderBase; 10 | import in.srain.cube.views.ptr.demo.R; 11 | 12 | public class ImageListViewHolder extends ViewHolderBase { 13 | 14 | private ImageLoader mImageLoader; 15 | private CubeImageView mImageView; 16 | 17 | private ImageListViewHolder(ImageLoader imageLoader) { 18 | mImageLoader = imageLoader; 19 | } 20 | 21 | @Override 22 | public View createView(LayoutInflater inflater) { 23 | View v = inflater.inflate(R.layout.list_view_item, null); 24 | mImageView = (CubeImageView) v.findViewById(R.id.list_view_item_image_view); 25 | mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); 26 | return v; 27 | } 28 | 29 | @Override 30 | public void showData(int position, JsonData itemData) { 31 | mImageView.loadImage(mImageLoader, itemData.optString("pic")); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ANDROID_BUILD_MIN_SDK_VERSION=8 2 | ANDROID_BUILD_TARGET_SDK_VERSION=23 3 | ANDROID_BUILD_SDK_VERSION=23 4 | ANDROID_BUILD_TOOLS_VERSION=24.0.0 5 | 6 | VERSION_CODE=6 7 | VERSION_NAME=1.0.6 8 | GROUP=in.srain.cube 9 | POM_NAME=Ultra Pull to Refresh 10 | POM_ARTIFACT_ID=ptr-load-more 11 | POM_PACKAGING=aar 12 | 13 | POM_DESCRIPTION=下拉刷新,上拉加载 14 | #项目地址等,我这使用的是github的项目地址 15 | POM_URL=https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More 16 | POM_SCM_URL=https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More 17 | POM_SCM_CONNECTION=https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More.git 18 | POM_SCM_DEV_CONNECTION=https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More.git 19 | 20 | #开源协议 21 | POM_LICENCE_NAME=MIT License 22 | POM_LICENCE_URL=http://www.opensource.org/licenses/mit-license.php 23 | POM_LICENCE_DIST=repo 24 | 25 | POM_DEVELOPER_ID=captain 26 | POM_DEVELOPER_NAME=Weizhou He 27 | 28 | POM_DEVELOPER_EMAIL=weizhou.captain.he@gmail.com 29 | POM_DEVELOPER_URL=http://blog.csdn.net/hwz2311245 30 | 31 | GIT_URL=https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More.git 32 | ISSUE_URL=https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More/issues -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/image/PtrImageLoadHandler.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.image; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.drawable.BitmapDrawable; 5 | import android.graphics.drawable.ColorDrawable; 6 | import in.srain.cube.image.CubeImageView; 7 | import in.srain.cube.image.ImageTask; 8 | import in.srain.cube.image.iface.ImageLoadHandler; 9 | 10 | public class PtrImageLoadHandler implements ImageLoadHandler { 11 | 12 | @Override 13 | public void onLoading(ImageTask imageTask, CubeImageView cubeImageView) { 14 | if (cubeImageView != null) { 15 | cubeImageView.setImageDrawable(new ColorDrawable(Color.GRAY)); 16 | } 17 | } 18 | 19 | @Override 20 | public void onLoadFinish(ImageTask imageTask, CubeImageView cubeImageView, BitmapDrawable bitmapDrawable) { 21 | if (bitmapDrawable != null && cubeImageView != null) { 22 | cubeImageView.setImageDrawable(bitmapDrawable); 23 | } 24 | } 25 | 26 | @Override 27 | public void onLoadError(ImageTask imageTask, CubeImageView cubeImageView, int i) { 28 | if (cubeImageView != null) { 29 | cubeImageView.setImageDrawable(new ColorDrawable(Color.RED)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/activity_view_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 22 | 23 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_with_long_press.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ultra PTR 4 | 自动刷新 5 | 包含FrameLayout 6 | 包含GridView 7 | FrameLayout包含GridView 8 | 脚部立即隐藏 9 | 刷新时不显示头部 10 | 刷新时显示头部 11 | 仅包含一个TextView 12 | 下拉刷新 13 | 释放刷新 14 | 15 | StoreHouse Style \n使用xml中的字符串数组 16 | 使用xml:   17 | StoreHouse Style \n\n使用字符串 18 | 使用字符串:  19 | 20 | Material Style\n内容不动,原生风格 21 | 立即下拉刷新,不等UIReset 22 | 23 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_classic_header_with_list_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 17 | 18 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ptr-demo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragmengt_ptr_home.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 17 | 18 | 23 | 24 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_storehouse_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 25 | 26 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_materail_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 24 | 25 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/PtrDefaultHandler.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr; 2 | 3 | import android.view.View; 4 | import android.widget.AbsListView; 5 | import android.widget.ScrollView; 6 | 7 | public abstract class PtrDefaultHandler implements PtrHandler { 8 | 9 | public static boolean canChildScrollUp(View view) { 10 | if (android.os.Build.VERSION.SDK_INT < 14) { 11 | if (view instanceof AbsListView) { 12 | final AbsListView absListView = (AbsListView) view; 13 | return absListView.getChildCount() > 0 14 | && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0) 15 | .getTop() < absListView.getPaddingTop()); 16 | } else { 17 | return view.getScrollY() > 0; 18 | } 19 | } else { 20 | return view.canScrollVertically(-1); 21 | } 22 | } 23 | 24 | /** 25 | * Default implement for check can perform pull to refresh 26 | * 27 | * @param frame 28 | * @param content 29 | * @param header 30 | * @return 31 | */ 32 | public static boolean checkContentCanBePulledDown(PtrFrameLayout frame, View content, View header) { 33 | return !canChildScrollUp(content); 34 | } 35 | 36 | @Override 37 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 38 | return checkContentCanBePulledDown(frame, content, header); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_classic_header_with_textview.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 18 | 19 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 22,0,0,30, 6 | 22,0,30,0, 7 | 30,0,52,30, 8 | 0,30,26,30, 9 | 60,0,60,15, 10 | 60,15,60,30, 11 | 60,15,85,15, 12 | 85,15,108,0, 13 | 85,15,108,30, 14 | 117,0,147,0, 15 | 147,0,177,0, 16 | 147,0,147,32, 17 | 198,0,176,30, 18 | 198,0,206,0, 19 | 206,0,228,30, 20 | 176,30,202,30, 21 | 22 | 23 | 24 | 0,35,12,42, 25 | 12,42,24,35, 26 | 24,35,12,28, 27 | 0,35,12,28, 28 | 0,21,12,28, 29 | 12,28,24,21, 30 | 24,35,24,21, 31 | 24,21,12,14, 32 | 0,21,12,14, 33 | 0,21,0,7, 34 | 12,14,0,7, 35 | 12,14,24,7, 36 | 24,7,12,0, 37 | 0,7,12,0, 38 | 39 | 40 | 41 | @color/red 42 | @color/blue 43 | @color/yellow 44 | @color/green 45 | 46 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/HideHeader.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.view.View; 4 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 5 | import in.srain.cube.views.ptr.PtrDefaultHandler; 6 | import in.srain.cube.views.ptr.PtrFrameLayout; 7 | import in.srain.cube.views.ptr.demo.R; 8 | import in.srain.cube.views.ptr.demo.ui.Utils; 9 | 10 | public class HideHeader extends WithTextViewInFrameLayoutFragment { 11 | 12 | @Override 13 | protected void setupViews(final PtrClassicFrameLayout ptrFrame) { 14 | setHeaderTitle(R.string.ptr_demo_block_hide_header); 15 | ptrFrame.setKeepHeaderWhenRefresh(false); 16 | 17 | final View loading = Utils.createSimpleLoadingTip(getContext()); 18 | mTitleHeaderBar.getRightViewContainer().addView(loading); 19 | 20 | ptrFrame.setPtrHandler(new PtrDefaultHandler() { 21 | @Override 22 | public void onRefreshBegin(PtrFrameLayout frame) { 23 | loading.setVisibility(View.VISIBLE); 24 | frame.postDelayed(new Runnable() { 25 | @Override 26 | public void run() { 27 | loading.setVisibility(View.INVISIBLE); 28 | ptrFrame.refreshComplete(); 29 | } 30 | }, 1500); 31 | } 32 | 33 | @Override 34 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 35 | return true; 36 | } 37 | }); 38 | } 39 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/app/PtrDemoApplication.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.app; 2 | 3 | import android.app.Application; 4 | import in.srain.cube.Cube; 5 | import in.srain.cube.image.ImageLoaderFactory; 6 | import in.srain.cube.request.RequestCacheManager; 7 | import in.srain.cube.util.CLog; 8 | import in.srain.cube.util.CubeDebug; 9 | import in.srain.cube.views.ptr.PtrFrameLayout; 10 | import in.srain.cube.views.ptr.demo.image.DemoDuiTangImageReSizer; 11 | import in.srain.cube.views.ptr.demo.image.PtrImageLoadHandler; 12 | 13 | public class PtrDemoApplication extends Application { 14 | 15 | public static PtrDemoApplication instance; 16 | 17 | @Override 18 | public void onCreate() { 19 | super.onCreate(); 20 | instance = this; 21 | 22 | String environment = ""; 23 | 24 | if (environment.equals("production")) { 25 | CLog.setLogLevel(CLog.LEVEL_ERROR); 26 | } else if (environment.equals("beta")) { 27 | CLog.setLogLevel(CLog.LEVEL_WARNING); 28 | } else { 29 | // development 30 | CLog.setLogLevel(CLog.LEVEL_VERBOSE); 31 | } 32 | 33 | CubeDebug.DEBUG_IMAGE = false; 34 | PtrFrameLayout.DEBUG = false; 35 | //PtrFrameLayout.DEBUG = false; 36 | 37 | ImageLoaderFactory.setDefaultImageReSizer(DemoDuiTangImageReSizer.getInstance()); 38 | ImageLoaderFactory.setDefaultImageLoadHandler(new PtrImageLoadHandler()); 39 | String dir = "request-cache"; 40 | // ImageLoaderFactory.init(this); 41 | RequestCacheManager.init(this, dir, 1024 * 10, 1024 * 10); 42 | Cube.onCreate(this); 43 | } 44 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/PtrUIHandlerHook.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr; 2 | 3 | /** 4 | * Run a hook runnable, the runnable will run only once. 5 | * After the runnable is done, call resume to resume. 6 | * Once run, call takeover will directory call the resume action 7 | */ 8 | public abstract class PtrUIHandlerHook implements Runnable { 9 | 10 | private Runnable mResumeAction; 11 | private static final byte STATUS_PREPARE = 0; 12 | private static final byte STATUS_IN_HOOK = 1; 13 | private static final byte STATUS_RESUMED = 2; 14 | private byte mStatus = STATUS_PREPARE; 15 | 16 | public void takeOver() { 17 | takeOver(null); 18 | } 19 | 20 | public void takeOver(Runnable resumeAction) { 21 | if (resumeAction != null) { 22 | mResumeAction = resumeAction; 23 | } 24 | switch (mStatus) { 25 | case STATUS_PREPARE: 26 | mStatus = STATUS_IN_HOOK; 27 | run(); 28 | break; 29 | case STATUS_IN_HOOK: 30 | break; 31 | case STATUS_RESUMED: 32 | resume(); 33 | break; 34 | } 35 | } 36 | 37 | public void reset() { 38 | mStatus = STATUS_PREPARE; 39 | } 40 | 41 | public void resume() { 42 | if (mResumeAction != null) { 43 | mResumeAction.run(); 44 | } 45 | mStatus = STATUS_RESUMED; 46 | } 47 | 48 | /** 49 | * Hook should always have a resume action, which is hooked by this hook. 50 | * 51 | * @param runnable 52 | */ 53 | public void setResumeAction(Runnable runnable) { 54 | mResumeAction = runnable; 55 | } 56 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/util/PtrLocalDisplay.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.util; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.View; 6 | import android.view.WindowManager; 7 | 8 | public class PtrLocalDisplay { 9 | 10 | public static int SCREEN_WIDTH_PIXELS; 11 | public static int SCREEN_HEIGHT_PIXELS; 12 | public static float SCREEN_DENSITY; 13 | public static int SCREEN_WIDTH_DP; 14 | public static int SCREEN_HEIGHT_DP; 15 | 16 | public static void init(Context context) { 17 | if (context == null) { 18 | return; 19 | } 20 | DisplayMetrics dm = new DisplayMetrics(); 21 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 22 | wm.getDefaultDisplay().getMetrics(dm); 23 | SCREEN_WIDTH_PIXELS = dm.widthPixels; 24 | SCREEN_HEIGHT_PIXELS = dm.heightPixels; 25 | SCREEN_DENSITY = dm.density; 26 | SCREEN_WIDTH_DP = (int) (SCREEN_WIDTH_PIXELS / dm.density); 27 | SCREEN_HEIGHT_DP = (int) (SCREEN_HEIGHT_PIXELS / dm.density); 28 | } 29 | 30 | public static int dp2px(float dp) { 31 | final float scale = SCREEN_DENSITY; 32 | return (int) (dp * scale + 0.5f); 33 | } 34 | 35 | public static int designedDP2px(float designedDp) { 36 | if (SCREEN_WIDTH_DP != 320) { 37 | designedDp = designedDp * SCREEN_WIDTH_DP / 320f; 38 | } 39 | return dp2px(designedDp); 40 | } 41 | 42 | public static void setPadding(final View view, float left, float top, float right, float bottom) { 43 | view.setPadding(designedDP2px(left), dp2px(top), designedDP2px(right), dp2px(bottom)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_classic_header_with_gridview.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 17 | 20 | 21 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_classic_header_with_viewgroup.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 26 | 27 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/PtrDefaultHandler2.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr; 2 | 3 | import android.view.View; 4 | import android.widget.AbsListView; 5 | import android.widget.ScrollView; 6 | 7 | public abstract class PtrDefaultHandler2 extends PtrDefaultHandler implements PtrHandler2 { 8 | 9 | public static boolean canChildScrollDown(View view) { 10 | if (android.os.Build.VERSION.SDK_INT < 14) { 11 | if (view instanceof AbsListView) { 12 | final AbsListView absListView = (AbsListView) view; 13 | return absListView.getChildCount() > 0 14 | && (absListView.getLastVisiblePosition() < absListView.getChildCount() - 1 15 | || absListView.getChildAt(absListView.getChildCount() - 1).getBottom() > absListView.getPaddingBottom()); 16 | } else if (view instanceof ScrollView) { 17 | ScrollView scrollView = (ScrollView) view; 18 | if (scrollView.getChildCount() == 0) { 19 | return false; 20 | } else { 21 | return scrollView.getScrollY() < scrollView.getChildAt(0).getHeight() - scrollView.getHeight(); 22 | } 23 | } else { 24 | return false; 25 | } 26 | } else { 27 | return view.canScrollVertically(1); 28 | } 29 | } 30 | 31 | /** 32 | * Default implement for check can perform pull to refresh 33 | * 34 | * @param frame 35 | * @param content 36 | * @param header 37 | * @return 38 | */ 39 | public static boolean checkContentCanBePulledUp(PtrFrameLayout frame, View content, View header) { 40 | return !canChildScrollDown(content); 41 | } 42 | 43 | @Override 44 | public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) { 45 | return checkContentCanBePulledUp(frame, content, footer); 46 | } 47 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/res/values/cube_ptr_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 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/EvenOnlyATextView.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import in.srain.cube.mints.base.TitleBaseFragment; 8 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 9 | import in.srain.cube.views.ptr.PtrDefaultHandler; 10 | import in.srain.cube.views.ptr.PtrDefaultHandler2; 11 | import in.srain.cube.views.ptr.PtrFrameLayout; 12 | import in.srain.cube.views.ptr.demo.R; 13 | 14 | public class EvenOnlyATextView extends TitleBaseFragment { 15 | 16 | public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 17 | 18 | setHeaderTitle(R.string.ptr_demo_block_only_text_view); 19 | 20 | final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_textview, container, false); 21 | 22 | final PtrClassicFrameLayout ptrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.fragment_rotate_header_with_text_view_frame); 23 | ptrFrame.setLastUpdateTimeRelateObject(this); 24 | ptrFrame.setPtrHandler(new PtrDefaultHandler2() { 25 | @Override 26 | public void onLoadMoreBegin(PtrFrameLayout frame) { 27 | frame.postDelayed(new Runnable() { 28 | @Override 29 | public void run() { 30 | ptrFrame.refreshComplete(); 31 | } 32 | }, 1500); 33 | } 34 | 35 | @Override 36 | public void onRefreshBegin(PtrFrameLayout frame) { 37 | frame.postDelayed(new Runnable() { 38 | @Override 39 | public void run() { 40 | ptrFrame.refreshComplete(); 41 | } 42 | }, 1500); 43 | } 44 | 45 | @Override 46 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 47 | return true; 48 | } 49 | }); 50 | return contentView; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_classic_header_with_list_view_and_empty_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | 28 | 29 | 32 | 33 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /gradle/gradle-jcenter-push.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | apply plugin: 'com.jfrog.bintray' 3 | 4 | publishing { 5 | publications { 6 | mavenJava(MavenPublication) { 7 | groupId GROUP 8 | version VERSION_NAME 9 | artifactId POM_ARTIFACT_ID 10 | artifact "${project.buildDir}/outputs/aar/${project.name}-release.aar" 11 | artifact androidJavadocsJar 12 | artifact androidSourcesJar 13 | 14 | pom.withXml { 15 | Node root = asNode() 16 | root.appendNode('name', POM_ARTIFACT_ID) 17 | root.appendNode('description', POM_DESCRIPTION) 18 | root.appendNode('url', POM_URL) 19 | 20 | def issues = root.appendNode('issueManagement') 21 | issues.appendNode('system', 'github') 22 | issues.appendNode('url', ISSUE_URL) 23 | 24 | def scm = root.appendNode('scm') 25 | scm.appendNode('url', POM_SCM_URL) 26 | scm.appendNode('connection', POM_SCM_CONNECTION) 27 | scm.appendNode('developerConnection', POM_SCM_DEV_CONNECTION) 28 | 29 | def license = root.appendNode('licenses').appendNode('license') 30 | license.appendNode('name', POM_LICENCE_NAME) 31 | license.appendNode('url', POM_LICENCE_URL) 32 | license.appendNode('distribution', POM_LICENCE_DIST) 33 | } 34 | } 35 | } 36 | } 37 | 38 | def getBintrayUserProperty() { 39 | return hasProperty('BINTRAY_USER') ? BINTRAY_USER : "captainbupt" 40 | } 41 | 42 | def getBintrayApiKeyProperty() { 43 | return hasProperty('BINTRAY_APIKEY') ? BINTRAY_APIKEY : "6fda16b50a227ac640521858fb098511d4e2fef3" 44 | } 45 | 46 | // gradle bintrayUpload 47 | bintray { 48 | user = getBintrayUserProperty() 49 | key = getBintrayApiKeyProperty() 50 | publications = ['mavenJava'] 51 | 52 | dryRun = false 53 | publish = true 54 | pkg { 55 | repo = 'maven' 56 | name = POM_ARTIFACT_ID 57 | desc = POM_NAME 58 | websiteUrl = POM_URL 59 | issueTrackerUrl = ISSUE_URL 60 | vcsUrl = GIT_URL 61 | licenses = ['Apache-2.0'] 62 | labels = ['android', 'aar'] 63 | publicDownloadNumbers = true 64 | 65 | version { 66 | name = VERSION_NAME 67 | vcsTag = VERSION_NAME 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/header/StoreHouseBarItem.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.header; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.PointF; 6 | import android.view.animation.Animation; 7 | import android.view.animation.Transformation; 8 | 9 | import java.util.Random; 10 | 11 | /** 12 | * Created by srain on 11/6/14. 13 | */ 14 | public class StoreHouseBarItem extends Animation { 15 | 16 | public PointF midPoint; 17 | public float translationX; 18 | public int index; 19 | 20 | private final Paint mPaint = new Paint(); 21 | private float mFromAlpha = 1.0f; 22 | private float mToAlpha = 0.4f; 23 | private PointF mCStartPoint; 24 | private PointF mCEndPoint; 25 | 26 | public StoreHouseBarItem(int index, PointF start, PointF end, int color, int lineWidth) { 27 | this.index = index; 28 | 29 | midPoint = new PointF((start.x + end.x) / 2, (start.y + end.y) / 2); 30 | 31 | mCStartPoint = new PointF(start.x - midPoint.x, start.y - midPoint.y); 32 | mCEndPoint = new PointF(end.x - midPoint.x, end.y - midPoint.y); 33 | 34 | setColor(color); 35 | setLineWidth(lineWidth); 36 | mPaint.setAntiAlias(true); 37 | mPaint.setStyle(Paint.Style.STROKE); 38 | } 39 | 40 | public void setLineWidth(int width) { 41 | mPaint.setStrokeWidth(width); 42 | } 43 | 44 | public void setColor(int color) { 45 | mPaint.setColor(color); 46 | } 47 | 48 | public void resetPosition(int horizontalRandomness) { 49 | Random random = new Random(); 50 | int randomNumber = -random.nextInt(horizontalRandomness) + horizontalRandomness; 51 | translationX = randomNumber; 52 | } 53 | 54 | @Override 55 | protected void applyTransformation(float interpolatedTime, Transformation t) { 56 | float alpha = mFromAlpha; 57 | alpha = alpha + ((mToAlpha - alpha) * interpolatedTime); 58 | setAlpha(alpha); 59 | } 60 | 61 | public void start(float fromAlpha, float toAlpha) { 62 | mFromAlpha = fromAlpha; 63 | mToAlpha = toAlpha; 64 | super.start(); 65 | } 66 | 67 | public void setAlpha(float alpha) { 68 | mPaint.setAlpha((int) (alpha * 255)); 69 | } 70 | 71 | public void draw(Canvas canvas) { 72 | canvas.drawLine(mCStartPoint.x, mCStartPoint.y, mCEndPoint.x, mCEndPoint.y, mPaint); 73 | } 74 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/res/layout/cube_ptr_classic_default_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 17 | 18 | 24 | 25 | 32 | 33 | 34 | 40 | 41 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/image/DemoDuiTangImageReSizer.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.image; 2 | 3 | import in.srain.cube.image.ImageTask; 4 | import in.srain.cube.image.impl.DefaultImageReSizer; 5 | import in.srain.cube.util.CLog; 6 | 7 | /** 8 | * Created by srain on 8/19/14. 9 | */ 10 | public class DemoDuiTangImageReSizer extends DefaultImageReSizer { 11 | 12 | 13 | private static DemoDuiTangImageReSizer sInstance; 14 | 15 | public static DemoDuiTangImageReSizer getInstance() { 16 | if (sInstance == null) { 17 | sInstance = new DemoDuiTangImageReSizer(); 18 | } 19 | return sInstance; 20 | } 21 | 22 | private static String TAG = "thumb"; 23 | private static String SP = "_"; 24 | private static String DOT = "."; 25 | 26 | private static final int[] CDN_FIX_WIDTH_SIZE = {110, 150, 170, 220, 240, 290, 450, 580, 620, 790}; 27 | 28 | @Override 29 | public String getRemoteUrl(ImageTask imageTask) { 30 | String url = imageTask.getOriginUrl(); 31 | int size = findBestCDNSize(CDN_FIX_WIDTH_SIZE, imageTask.getRequestSize().x, true); 32 | url = url.replace(TAG, TAG + DOT + size + SP + size); 33 | CLog.d("test", "getRemoteUrl: %s %s", imageTask.getRequestSize(), url); 34 | return url; 35 | } 36 | 37 | private static int binarySearch(int[] srcArray, int des, boolean higher) { 38 | int low = 0; 39 | int high = srcArray.length - 1; 40 | while (low <= high) { 41 | int middle = (low + high) / 2; 42 | if (des == srcArray[middle]) { 43 | return middle; 44 | } else if (des < srcArray[middle]) { 45 | high = middle - 1; 46 | } else { 47 | low = middle + 1; 48 | } 49 | } 50 | if (high < 0) 51 | return 0; 52 | if (higher) { 53 | if (des > srcArray[high] && high + 1 <= srcArray.length - 1) { 54 | high = high + 1; 55 | } 56 | } else { 57 | if (des < srcArray[high] && high - 1 >= 0) 58 | high = high - 1; 59 | } 60 | return high; 61 | } 62 | 63 | private static int findBestCDNSize(int[] array, int size, boolean higher) { 64 | 65 | if (size >= array[array.length - 1]) { 66 | return array[array.length - 1]; 67 | } 68 | 69 | int pos = binarySearch(array, size, higher); 70 | return array[pos]; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ptr-lib/src/main/res/layout/cube_ptr_classic_default_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 17 | 18 | 24 | 25 | 32 | 33 | 34 | 40 | 41 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /ptr-demo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) 5 | buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION 6 | 7 | defaultConfig { 8 | applicationId "in.srain.cube.views.ptr.demo" 9 | minSdkVersion 8 10 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) 11 | } 12 | 13 | lintOptions { 14 | abortOnError false 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled true 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | 24 | dexOptions { 25 | preDexLibraries = false 26 | } 27 | } 28 | 29 | 30 | def EXCLUDE_JAR_LIST = ['cube-sdk', 'support-v4-r7-source', 'ultra-ptr', 'support-annotation', 'ptr-lib'] 31 | 32 | task copyLibs << { 33 | 34 | // copy jars 35 | copy { 36 | from configurations.compile 37 | into "libs" 38 | 39 | eachFile { file -> 40 | println file.name 41 | for (name in EXCLUDE_JAR_LIST) { 42 | if (file.name.contains(name)) { 43 | file.exclude() 44 | return 45 | } 46 | } 47 | } 48 | } 49 | 50 | // copy source 51 | copy { 52 | 53 | def sourceList = configurations.compile.incoming.dependencies.collect { dependency -> 54 | dependency.artifact { artifact -> 55 | artifact.name = dependency.name 56 | artifact.type = 'source' 57 | artifact.extension = 'jar' 58 | artifact.classifier = 'sources' 59 | } 60 | dependency 61 | } 62 | from(configurations.detachedConfiguration(sourceList as Dependency[]).resolvedConfiguration. 63 | resolvedConfiguration.lenientConfiguration.getFiles(Specs.SATISFIES_ALL)) { 64 | } 65 | 66 | into("libs") 67 | 68 | eachFile { file -> 69 | println file.name 70 | for (name in EXCLUDE_JAR_LIST) { 71 | if (file.name.contains(name)) { 72 | file.exclude() 73 | return 74 | } 75 | } 76 | } 77 | } 78 | } 79 | 80 | dependencies { 81 | //compile(project(':ptr-lib')); 82 | compile 'in.srain.cube:ptr-load-more:1.0.5' 83 | compile 'in.srain.cube:clog:1.0.2' 84 | compile 'in.srain.cube:cube-sdk:1.0.44@aar' 85 | compile 'com.google.android:support-v4:r7' 86 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ultra PTR 5 | Ultra Pull to Refresh 6 | 7 | Contains A GridView With Footer 8 | A GridView reside in FrameLayout 9 | Footer hide immediately 10 | Contains A ListView 11 | Contains A WebView 12 | Contains ScrollView 13 | Contains A FrameLayout 14 | Contains Even A TextView 15 | EmptyView and ListView 16 | It\' empty. \n\nClick to load data. 17 | 18 | Pull to Refresh 19 | Release to Refresh 20 | Auto Refresh 21 | 22 | Keep Header while Refreshing 23 | Hide Header while Refreshing 24 | Long Press 25 | View Pager 26 | StoreHouse Style \nusing string array from xml 27 | using xml:  28 | StoreHouse Style \n\nusing string 29 | using string:  30 | Using Point List 31 | Material Style 32 | Rentals Style 33 | To be continued 34 | 35 | Material Style\nPin Content\n v4 style 36 | Enable Next PTR at once 37 | 38 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/WithTextViewInFrameLayoutFragment.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import in.srain.cube.mints.base.TitleBaseFragment; 8 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 9 | import in.srain.cube.views.ptr.PtrFrameLayout; 10 | import in.srain.cube.views.ptr.PtrHandler; 11 | import in.srain.cube.views.ptr.demo.R; 12 | 13 | public class WithTextViewInFrameLayoutFragment extends TitleBaseFragment { 14 | 15 | @Override 16 | public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 17 | 18 | setHeaderTitle(R.string.ptr_demo_block_frame_layout); 19 | 20 | final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_viewgroup, container, false); 21 | 22 | final PtrClassicFrameLayout ptrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.fragment_rotate_header_with_view_group_frame); 23 | ptrFrame.setPtrHandler(new PtrHandler() { 24 | @Override 25 | public void onRefreshBegin(PtrFrameLayout frame) { 26 | frame.postDelayed(new Runnable() { 27 | @Override 28 | public void run() { 29 | ptrFrame.refreshComplete(); 30 | } 31 | }, 1800); 32 | } 33 | 34 | @Override 35 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 36 | return true; 37 | } 38 | }); 39 | ptrFrame.setLastUpdateTimeRelateObject(this); 40 | 41 | // the following are default settings 42 | ptrFrame.setResistance(1.7f); 43 | ptrFrame.setRatioOfHeaderHeightToRefresh(1.2f); 44 | ptrFrame.setDurationToClose(200); 45 | ptrFrame.setDurationToCloseHeader(1000); 46 | // default is false 47 | ptrFrame.setPullToRefresh(false); 48 | // default is true 49 | ptrFrame.setKeepHeaderWhenRefresh(true); 50 | 51 | // scroll then refresh 52 | // comment in base fragment 53 | ptrFrame.postDelayed(new Runnable() { 54 | @Override 55 | public void run() { 56 | // ptrFrame.autoRefresh(); 57 | } 58 | }, 150); 59 | 60 | setupViews(ptrFrame); 61 | 62 | return contentView; 63 | } 64 | 65 | protected void setupViews(final PtrClassicFrameLayout ptrFrame) { 66 | 67 | } 68 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/WithScrollView.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ScrollView; 8 | import in.srain.cube.mints.base.TitleBaseFragment; 9 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 10 | import in.srain.cube.views.ptr.PtrDefaultHandler; 11 | import in.srain.cube.views.ptr.PtrFrameLayout; 12 | import in.srain.cube.views.ptr.PtrHandler; 13 | import in.srain.cube.views.ptr.demo.R; 14 | 15 | public class WithScrollView extends TitleBaseFragment { 16 | 17 | private PtrClassicFrameLayout mPtrFrame; 18 | private ScrollView mScrollView; 19 | 20 | @Override 21 | public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 22 | 23 | setHeaderTitle(R.string.ptr_demo_block_scroll_view); 24 | 25 | final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_scroll_view, null); 26 | mScrollView = (ScrollView) contentView.findViewById(R.id.rotate_header_scroll_view); 27 | mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_web_view_frame); 28 | mPtrFrame.setLastUpdateTimeRelateObject(this); 29 | mPtrFrame.setPtrHandler(new PtrHandler() { 30 | @Override 31 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 32 | return PtrDefaultHandler.checkContentCanBePulledDown(frame, mScrollView, header); 33 | } 34 | 35 | @Override 36 | public void onRefreshBegin(PtrFrameLayout frame) { 37 | mPtrFrame.postDelayed(new Runnable() { 38 | @Override 39 | public void run() { 40 | mPtrFrame.refreshComplete(); 41 | } 42 | }, 100); 43 | } 44 | }); 45 | 46 | // the following are default settings 47 | mPtrFrame.setResistance(1.7f); 48 | mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f); 49 | mPtrFrame.setDurationToClose(200); 50 | mPtrFrame.setDurationToCloseHeader(1000); 51 | // default is false 52 | mPtrFrame.setPullToRefresh(false); 53 | // default is true 54 | mPtrFrame.setKeepHeaderWhenRefresh(true); 55 | mPtrFrame.postDelayed(new Runnable() { 56 | @Override 57 | public void run() { 58 | mPtrFrame.autoRefresh(); 59 | } 60 | }, 100); 61 | return contentView; 62 | } 63 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/PtrClassicFrameLayout.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | public class PtrClassicFrameLayout extends PtrFrameLayout { 7 | 8 | private PtrClassicDefaultHeader mPtrClassicHeader; 9 | private PtrClassicDefaultFooter mPtrClassicFooter; 10 | 11 | public PtrClassicFrameLayout(Context context) { 12 | super(context); 13 | initViews(); 14 | } 15 | 16 | public PtrClassicFrameLayout(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | initViews(); 19 | } 20 | 21 | public PtrClassicFrameLayout(Context context, AttributeSet attrs, int defStyle) { 22 | super(context, attrs, defStyle); 23 | initViews(); 24 | } 25 | 26 | private void initViews() { 27 | mPtrClassicHeader = new PtrClassicDefaultHeader(getContext()); 28 | setHeaderView(mPtrClassicHeader); 29 | addPtrUIHandler(mPtrClassicHeader); 30 | mPtrClassicFooter = new PtrClassicDefaultFooter(getContext()); 31 | setFooterView(mPtrClassicFooter); 32 | addPtrUIHandler(mPtrClassicFooter); 33 | } 34 | 35 | public PtrClassicDefaultHeader getHeader() { 36 | return mPtrClassicHeader; 37 | } 38 | 39 | /** 40 | * Specify the last update time by this key string 41 | * 42 | * @param key 43 | */ 44 | public void setLastUpdateTimeKey(String key) { 45 | setLastUpdateTimeHeaderKey(key); 46 | setLastUpdateTimeFooterKey(key); 47 | } 48 | 49 | public void setLastUpdateTimeHeaderKey(String key) { 50 | if (mPtrClassicHeader != null) { 51 | mPtrClassicHeader.setLastUpdateTimeKey(key); 52 | } 53 | } 54 | 55 | public void setLastUpdateTimeFooterKey(String key) { 56 | if (mPtrClassicFooter != null) { 57 | mPtrClassicFooter.setLastUpdateTimeKey(key); 58 | } 59 | } 60 | 61 | /** 62 | * Using an object to specify the last update time. 63 | * 64 | * @param object 65 | */ 66 | public void setLastUpdateTimeRelateObject(Object object) { 67 | setLastUpdateTimeHeaderRelateObject(object); 68 | setLastUpdateTimeFooterRelateObject(object); 69 | } 70 | 71 | public void setLastUpdateTimeHeaderRelateObject(Object object) { 72 | if (mPtrClassicHeader != null) { 73 | mPtrClassicHeader.setLastUpdateTimeRelateObject(object); 74 | } 75 | } 76 | 77 | public void setLastUpdateTimeFooterRelateObject(Object object) { 78 | if (mPtrClassicFooter != null) { 79 | mPtrClassicFooter.setLastUpdateTimeRelateObject(object); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/WithWebView.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.webkit.WebView; 8 | import android.webkit.WebViewClient; 9 | 10 | import in.srain.cube.mints.base.TitleBaseFragment; 11 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 12 | import in.srain.cube.views.ptr.PtrDefaultHandler; 13 | import in.srain.cube.views.ptr.PtrFrameLayout; 14 | import in.srain.cube.views.ptr.PtrHandler; 15 | import in.srain.cube.views.ptr.demo.R; 16 | 17 | public class WithWebView extends TitleBaseFragment { 18 | 19 | private PtrClassicFrameLayout mPtrFrame; 20 | private WebView mWebView; 21 | 22 | @Override 23 | public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 24 | 25 | setHeaderTitle(R.string.ptr_demo_block_web_view); 26 | 27 | final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_webview, null); 28 | mWebView = (WebView) contentView.findViewById(R.id.rotate_header_web_view); 29 | mWebView.setWebViewClient(new WebViewClient() { 30 | @Override 31 | public void onPageFinished(WebView view, String url) { 32 | mPtrFrame.refreshComplete(); 33 | } 34 | }); 35 | mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_web_view_frame); 36 | mPtrFrame.setLastUpdateTimeRelateObject(this); 37 | mPtrFrame.setPtrHandler(new PtrHandler() { 38 | @Override 39 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 40 | return PtrDefaultHandler.checkContentCanBePulledDown(frame, mWebView, header); 41 | } 42 | 43 | @Override 44 | public void onRefreshBegin(PtrFrameLayout frame) { 45 | updateData(); 46 | } 47 | }); 48 | // the following are default settings 49 | mPtrFrame.setResistance(1.7f); 50 | mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f); 51 | mPtrFrame.setDurationToClose(200); 52 | mPtrFrame.setDurationToCloseHeader(1000); 53 | // default is false 54 | mPtrFrame.setPullToRefresh(false); 55 | // default is true 56 | mPtrFrame.setKeepHeaderWhenRefresh(true); 57 | mPtrFrame.postDelayed(new Runnable() { 58 | @Override 59 | public void run() { 60 | mPtrFrame.autoRefresh(); 61 | } 62 | }, 100); 63 | return contentView; 64 | } 65 | 66 | private void updateData() { 67 | mWebView.loadUrl("http://www.liaohuqiu.net/"); 68 | } 69 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/res/layout/fragment_classic_header_with_scroll_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 22 | 23 | 27 | 28 | 38 | 39 | 49 | 50 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/header/RentalsSunHeaderView.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.header; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.drawable.Drawable; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | import in.srain.cube.views.ptr.PtrFrameLayout; 9 | import in.srain.cube.views.ptr.PtrUIHandler; 10 | import in.srain.cube.views.ptr.indicator.PtrIndicator; 11 | import in.srain.cube.views.ptr.indicator.PtrTensionIndicator; 12 | 13 | public class RentalsSunHeaderView extends View implements PtrUIHandler { 14 | 15 | private RentalsSunDrawable mDrawable; 16 | private PtrFrameLayout mPtrFrameLayout; 17 | private PtrTensionIndicator mPtrTensionIndicator; 18 | 19 | public RentalsSunHeaderView(Context context, AttributeSet attrs, int defStyleAttr) { 20 | super(context, attrs, defStyleAttr); 21 | init(); 22 | } 23 | 24 | public RentalsSunHeaderView(Context context) { 25 | super(context); 26 | init(); 27 | } 28 | 29 | public RentalsSunHeaderView(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | init(); 32 | } 33 | 34 | public void setUp(PtrFrameLayout ptrFrameLayout) { 35 | mPtrFrameLayout = ptrFrameLayout; 36 | mPtrTensionIndicator = new PtrTensionIndicator(); 37 | mPtrFrameLayout.setPtrIndicator(mPtrTensionIndicator); 38 | } 39 | 40 | private void init() { 41 | mDrawable = new RentalsSunDrawable(getContext(), this); 42 | } 43 | 44 | @Override 45 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 46 | int height = mDrawable.getTotalDragDistance() * 5 / 4; 47 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + getPaddingTop() + getPaddingBottom(), MeasureSpec.EXACTLY); 48 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 49 | } 50 | 51 | @Override 52 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 53 | int pl = getPaddingLeft(); 54 | int pt = getPaddingTop(); 55 | mDrawable.setBounds(pl, pt, pl + right - left, pt + bottom - top); 56 | } 57 | 58 | @Override 59 | public void onUIReset(PtrFrameLayout frame) { 60 | mDrawable.resetOriginals(); 61 | } 62 | 63 | @Override 64 | protected void onDraw(Canvas canvas) { 65 | mDrawable.draw(canvas); 66 | float percent = mPtrTensionIndicator.getOverDragPercent(); 67 | } 68 | 69 | @Override 70 | public void onUIRefreshPrepare(PtrFrameLayout frame) { 71 | 72 | } 73 | 74 | @Override 75 | public void onUIRefreshBegin(PtrFrameLayout frame) { 76 | mDrawable.start(); 77 | float percent = mPtrTensionIndicator.getOverDragPercent(); 78 | mDrawable.offsetTopAndBottom(mPtrTensionIndicator.getCurrentPosY()); 79 | mDrawable.setPercent(percent); 80 | invalidate(); 81 | } 82 | 83 | @Override 84 | public void onUIRefreshComplete(PtrFrameLayout frame, boolean isHeader) { 85 | float percent = mPtrTensionIndicator.getOverDragPercent(); 86 | mDrawable.stop(); 87 | mDrawable.offsetTopAndBottom(mPtrTensionIndicator.getCurrentPosY()); 88 | mDrawable.setPercent(percent); 89 | invalidate(); 90 | } 91 | 92 | @Override 93 | public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) { 94 | float percent = mPtrTensionIndicator.getOverDragPercent(); 95 | mDrawable.offsetTopAndBottom(mPtrTensionIndicator.getCurrentPosY()); 96 | mDrawable.setPercent(percent); 97 | invalidate(); 98 | } 99 | 100 | @Override 101 | public void invalidateDrawable(Drawable dr) { 102 | if (dr == mDrawable) { 103 | invalidate(); 104 | } else { 105 | super.invalidateDrawable(dr); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/WithLongPressFragment.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.AdapterView; 8 | import android.widget.ListView; 9 | import android.widget.Toast; 10 | 11 | import in.srain.cube.image.CubeImageView; 12 | import in.srain.cube.image.ImageLoader; 13 | import in.srain.cube.image.ImageLoaderFactory; 14 | import in.srain.cube.mints.base.TitleBaseFragment; 15 | import in.srain.cube.views.list.ListViewDataAdapter; 16 | import in.srain.cube.views.list.ViewHolderBase; 17 | import in.srain.cube.views.ptr.PtrDefaultHandler; 18 | import in.srain.cube.views.ptr.PtrFrameLayout; 19 | import in.srain.cube.views.ptr.demo.R; 20 | import in.srain.cube.views.ptr.demo.image.Images; 21 | 22 | import java.util.Arrays; 23 | 24 | public class WithLongPressFragment extends TitleBaseFragment { 25 | 26 | private ImageLoader mImageLoader; 27 | 28 | @Override 29 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 30 | 31 | mImageLoader = ImageLoaderFactory.create(getActivity()); 32 | 33 | View view = inflater.inflate(R.layout.fragment_with_long_press, null); 34 | 35 | setHeaderTitle(R.string.ptr_demo_block_with_long_press); 36 | 37 | final PtrFrameLayout ptrFrameLayout = (PtrFrameLayout) view.findViewById(R.id.with_long_press_list_view_frame); 38 | 39 | ListView listView = (ListView) view.findViewById(R.id.with_long_press_list_view); 40 | listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { 41 | @Override 42 | public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { 43 | Toast.makeText(getContext(), "Long Pressed: " + id, Toast.LENGTH_SHORT).show(); 44 | return true; 45 | } 46 | }); 47 | 48 | final ListViewDataAdapter listViewDataAdapter = new ListViewDataAdapter(); 49 | listViewDataAdapter.setViewHolderClass(this, ViewHolder.class); 50 | 51 | ptrFrameLayout.setPtrHandler(new PtrDefaultHandler() { 52 | 53 | @Override 54 | public void onRefreshBegin(PtrFrameLayout frame) { 55 | ptrFrameLayout.postDelayed(new Runnable() { 56 | @Override 57 | public void run() { 58 | listViewDataAdapter.getDataList().clear(); 59 | listViewDataAdapter.getDataList().addAll(Arrays.asList(Images.imageUrls)); 60 | listViewDataAdapter.notifyDataSetChanged(); 61 | ptrFrameLayout.refreshComplete(); 62 | } 63 | }, 2000); 64 | } 65 | }); 66 | ptrFrameLayout.postDelayed(new Runnable() { 67 | @Override 68 | public void run() { 69 | ptrFrameLayout.autoRefresh(); 70 | } 71 | }, 100); 72 | listView.setAdapter(listViewDataAdapter); 73 | return view; 74 | } 75 | 76 | private class ViewHolder extends ViewHolderBase { 77 | 78 | private CubeImageView mImageView; 79 | 80 | /** 81 | * create a view from resource Xml file, and hold the view that may be used in displaying data. 82 | * 83 | * @param layoutInflater 84 | */ 85 | @Override 86 | public View createView(LayoutInflater layoutInflater) { 87 | View view = layoutInflater.inflate(R.layout.with_long_press_list_view_item, null); 88 | mImageView = (CubeImageView) view.findViewById(R.id.with_long_press_list_image); 89 | return view; 90 | } 91 | 92 | /** 93 | * using the held views to display data 94 | * 95 | * @param position 96 | * @param itemData 97 | */ 98 | @Override 99 | public void showData(int position, String itemData) { 100 | mImageView.loadImage(mImageLoader, itemData); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/indicator/PtrTensionIndicator.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.indicator; 2 | 3 | public class PtrTensionIndicator extends PtrIndicator { 4 | 5 | private float DRAG_RATE = 0.5f; 6 | private float mDownY; 7 | private float mDownPos; 8 | private float mOneHeight = 0; 9 | 10 | private float mCurrentDragPercent; 11 | 12 | private int mReleasePos; 13 | private float mReleasePercent = -1; 14 | 15 | @Override 16 | public void onPressDown(float x, float y) { 17 | super.onPressDown(x, y); 18 | mDownY = y; 19 | mDownPos = getCurrentPosY(); 20 | } 21 | 22 | @Override 23 | public void onRelease() { 24 | super.onRelease(); 25 | mReleasePos = getCurrentPosY(); 26 | mReleasePercent = mCurrentDragPercent; 27 | } 28 | 29 | @Override 30 | public void onUIRefreshComplete() { 31 | mReleasePos = getCurrentPosY(); 32 | mReleasePercent = getOverDragPercent(); 33 | } 34 | 35 | @Override 36 | public void setHeaderHeight(int height) { 37 | super.setHeaderHeight(height); 38 | mOneHeight = height * 4f / 5; 39 | } 40 | 41 | @Override 42 | protected void processOnMove(float currentX, float currentY, float offsetX, float offsetY) { 43 | 44 | if (currentY < mDownY) { 45 | super.processOnMove(currentX, currentY, offsetX, offsetY); 46 | return; 47 | } 48 | 49 | // distance from top 50 | final float scrollTop = (currentY - mDownY) * DRAG_RATE + mDownPos; 51 | final float currentDragPercent = scrollTop / mOneHeight; 52 | 53 | if (currentDragPercent < 0) { 54 | setOffset(offsetX, 0); 55 | return; 56 | } 57 | 58 | mCurrentDragPercent = currentDragPercent; 59 | 60 | // 0 ~ 1 61 | float boundedDragPercent = Math.min(1f, Math.abs(currentDragPercent)); 62 | float extraOS = scrollTop - mOneHeight; 63 | 64 | // 0 ~ 2 65 | // if extraOS lower than 0, which means scrollTop lower than onHeight, tensionSlingshotPercent will be 0. 66 | float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, mOneHeight * 2) / mOneHeight); 67 | 68 | float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f; 69 | float extraMove = (mOneHeight) * tensionPercent / 2; 70 | int targetY = (int) ((mOneHeight * boundedDragPercent) + extraMove); 71 | int change = targetY - getCurrentPosY(); 72 | 73 | setOffset(currentX, change); 74 | } 75 | 76 | private float offsetToTarget(float scrollTop) { 77 | 78 | // distance from top 79 | final float currentDragPercent = scrollTop / mOneHeight; 80 | 81 | mCurrentDragPercent = currentDragPercent; 82 | 83 | // 0 ~ 1 84 | float boundedDragPercent = Math.min(1f, Math.abs(currentDragPercent)); 85 | float extraOS = scrollTop - mOneHeight; 86 | 87 | // 0 ~ 2 88 | // if extraOS lower than 0, which means scrollTop lower than mOneHeight, tensionSlingshotPercent will be 0. 89 | float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, mOneHeight * 2) / mOneHeight); 90 | 91 | float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f; 92 | float extraMove = (mOneHeight) * tensionPercent / 2; 93 | int targetY = (int) ((mOneHeight * boundedDragPercent) + extraMove); 94 | 95 | return 0; 96 | } 97 | 98 | @Override 99 | public int getOffsetToKeepHeaderWhileLoading() { 100 | return getOffsetToRefresh(); 101 | } 102 | 103 | @Override 104 | public int getOffsetToRefresh() { 105 | return (int) mOneHeight; 106 | } 107 | 108 | public float getOverDragPercent() { 109 | if (isUnderTouch()) { 110 | return mCurrentDragPercent; 111 | } else { 112 | if (mReleasePercent <= 0) { 113 | return 1.0f * getCurrentPosY() / getOffsetToKeepHeaderWhileLoading(); 114 | } 115 | // after release 116 | return mReleasePercent * getCurrentPosY() / mReleasePos; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/viewpager/ViewPagerFragment.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.viewpager; 2 | 3 | import android.os.Bundle; 4 | import android.text.TextUtils; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.AdapterView; 9 | import android.widget.ListView; 10 | import android.widget.TextView; 11 | 12 | import in.srain.cube.app.CubeFragment; 13 | import in.srain.cube.image.ImageLoader; 14 | import in.srain.cube.image.ImageLoaderFactory; 15 | import in.srain.cube.request.JsonData; 16 | import in.srain.cube.util.CLog; 17 | import in.srain.cube.views.list.ListViewDataAdapter; 18 | import in.srain.cube.views.ptr.demo.R; 19 | import in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment; 20 | 21 | public class ViewPagerFragment extends CubeFragment { 22 | 23 | private int mPage; 24 | private ListView mListView; 25 | private ImageLoader mImageLoader; 26 | private ListViewDataAdapter mAdapter; 27 | 28 | public static ViewPagerFragment create(int page) { 29 | ViewPagerFragment fragment = new ViewPagerFragment(); 30 | fragment.mPage = page; 31 | return fragment; 32 | } 33 | 34 | @Override 35 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 36 | return null; 37 | } 38 | 39 | @Override 40 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 41 | mImageLoader = ImageLoaderFactory.create(getContext()).tryToAttachToContainer(getContext()); 42 | View view = inflater.inflate(R.layout.fragment_view_pager, null); 43 | mListView = (ListView) view.findViewById(R.id.view_pager_list_view); 44 | 45 | View headerView = inflater.inflate(R.layout.view_pager_fragment_list_view_header, null); 46 | TextView mHeaderTextView = (TextView) headerView.findViewById(R.id.view_pager_fragment_list_view_header_title); 47 | mHeaderTextView.setBackgroundColor(0xff4d90fe * mPage / 30); 48 | mHeaderTextView.setText("Page: " + mPage); 49 | 50 | mListView.addHeaderView(headerView); 51 | mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 52 | @Override 53 | public void onItemClick(AdapterView parent, View view, int position, long id) { 54 | if (position >= 0) { 55 | JsonData js = mAdapter.getItem(position); 56 | final String url = js != null ? js.optString("pic") : null; 57 | if (!TextUtils.isEmpty(url)) { 58 | getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url); 59 | } 60 | } 61 | } 62 | }); 63 | 64 | mAdapter = new ListViewDataAdapter(); 65 | mAdapter.setViewHolderClass(this, ImageListViewHolder.class, mImageLoader); 66 | mListView.setAdapter(mAdapter); 67 | return view; 68 | } 69 | 70 | public void update(JsonData data) { 71 | mAdapter.getDataList().clear(); 72 | mAdapter.getDataList().addAll(data.optJson("data").optJson("list").toArrayList()); 73 | mAdapter.notifyDataSetChanged(); 74 | } 75 | 76 | public void show() { 77 | 78 | } 79 | 80 | public void hide() { 81 | 82 | } 83 | 84 | public boolean checkCanDoRefresh() { 85 | if (mAdapter.getCount() == 0 || mListView == null) { 86 | return true; 87 | } 88 | CLog.d("test", "checkCanDoRefresh: %s %s", mListView.getFirstVisiblePosition(), mListView.getChildAt(0).getTop()); 89 | return mListView.getFirstVisiblePosition() == 0 && mListView.getChildAt(0).getTop() == 0; 90 | } 91 | 92 | public boolean checkCanDoLoadMore() { 93 | if (mAdapter.getCount() == 0 || mListView == null) { 94 | return true; 95 | } 96 | CLog.d("test", "checkCanDoRefresh: %s %s", mListView.getFirstVisiblePosition(), mListView.getChildAt(0).getTop()); 97 | return mListView.getLastVisiblePosition() < mAdapter.getCount() - 1 || mListView.getChildAt(mAdapter.getCount() - 1) 98 | .getBottom() > mListView.getPaddingBottom(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/storehouse/StoreHouseUsingString.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.storehouse; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import in.srain.cube.image.CubeImageView; 9 | import in.srain.cube.image.ImageLoader; 10 | import in.srain.cube.image.ImageLoaderFactory; 11 | import in.srain.cube.mints.base.TitleBaseFragment; 12 | import in.srain.cube.util.LocalDisplay; 13 | import in.srain.cube.views.ptr.PtrFrameLayout; 14 | import in.srain.cube.views.ptr.PtrHandler; 15 | import in.srain.cube.views.ptr.PtrUIHandler; 16 | import in.srain.cube.views.ptr.demo.R; 17 | import in.srain.cube.views.ptr.header.StoreHouseHeader; 18 | import in.srain.cube.views.ptr.indicator.PtrIndicator; 19 | 20 | public class StoreHouseUsingString extends TitleBaseFragment { 21 | 22 | final String[] mStringList = {"Alibaba", "TMALL 11-11"}; 23 | private String mTitlePre; 24 | 25 | @Override 26 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 27 | 28 | View view = inflater.inflate(R.layout.fragment_storehouse_header, null); 29 | mTitlePre = getString(R.string.ptr_demo_storehouse_header_using_string_in_title); 30 | 31 | CubeImageView imageView = (CubeImageView) view.findViewById(R.id.store_house_ptr_image); 32 | ImageLoader imageLoader = ImageLoaderFactory.create(getContext()); 33 | String pic = "http://img5.duitang.com/uploads/item/201406/28/20140628122218_fLQyP.thumb.jpeg"; 34 | imageView.loadImage(imageLoader, pic); 35 | 36 | final PtrFrameLayout frame = (PtrFrameLayout) view.findViewById(R.id.store_house_ptr_frame); 37 | 38 | // header 39 | final StoreHouseHeader header = new StoreHouseHeader(getContext()); 40 | header.setPadding(0, LocalDisplay.dp2px(15), 0, 0); 41 | 42 | /** 43 | * using a string, support: A-Z 0-9 - . 44 | * you can add more letters by {@link in.srain.cube.views.ptr.header.StoreHousePath#addChar} 45 | */ 46 | header.initWithString(mStringList[0]); 47 | setHeaderTitle(mTitlePre + mStringList[0]); 48 | 49 | // for changing string 50 | frame.addPtrUIHandler(new PtrUIHandler() { 51 | 52 | private int mLoadTime = 0; 53 | 54 | @Override 55 | public void onUIReset(PtrFrameLayout frame) { 56 | mLoadTime++; 57 | String string = mStringList[mLoadTime % mStringList.length]; 58 | header.initWithString(string); 59 | } 60 | 61 | @Override 62 | public void onUIRefreshPrepare(PtrFrameLayout frame) { 63 | String string = mStringList[mLoadTime % mStringList.length]; 64 | setHeaderTitle(mTitlePre + string); 65 | } 66 | 67 | @Override 68 | public void onUIRefreshBegin(PtrFrameLayout frame) { 69 | 70 | } 71 | 72 | @Override 73 | public void onUIRefreshComplete(PtrFrameLayout frame, boolean isHeader) { 74 | 75 | } 76 | 77 | @Override 78 | public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) { 79 | 80 | } 81 | }); 82 | 83 | frame.setDurationToCloseHeader(3000); 84 | frame.setHeaderView(header); 85 | frame.addPtrUIHandler(header); 86 | frame.postDelayed(new Runnable() { 87 | @Override 88 | public void run() { 89 | frame.autoRefresh(false); 90 | } 91 | }, 100); 92 | 93 | frame.setPtrHandler(new PtrHandler() { 94 | @Override 95 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 96 | return true; 97 | } 98 | 99 | @Override 100 | public void onRefreshBegin(final PtrFrameLayout frame) { 101 | frame.postDelayed(new Runnable() { 102 | @Override 103 | public void run() { 104 | frame.refreshComplete(); 105 | } 106 | }, 2000); 107 | } 108 | }); 109 | return view; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/storehouse/StoreHouseUsingStringArray.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.storehouse; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import in.srain.cube.image.CubeImageView; 9 | import in.srain.cube.image.ImageLoader; 10 | import in.srain.cube.image.ImageLoaderFactory; 11 | import in.srain.cube.mints.base.TitleBaseFragment; 12 | import in.srain.cube.util.LocalDisplay; 13 | import in.srain.cube.views.ptr.PtrFrameLayout; 14 | import in.srain.cube.views.ptr.PtrHandler; 15 | import in.srain.cube.views.ptr.PtrUIHandler; 16 | import in.srain.cube.views.ptr.demo.R; 17 | import in.srain.cube.views.ptr.header.StoreHouseHeader; 18 | import in.srain.cube.views.ptr.indicator.PtrIndicator; 19 | 20 | public class StoreHouseUsingStringArray extends TitleBaseFragment { 21 | 22 | private String mTitlePre; 23 | 24 | @Override 25 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 26 | 27 | final View view = inflater.inflate(R.layout.fragment_storehouse_header, null); 28 | 29 | mTitlePre = getString(R.string.ptr_demo_storehouse_header_using_string_array_in_title); 30 | 31 | setHeaderTitle(mTitlePre + "R.array.storehouse"); 32 | 33 | // loading image 34 | CubeImageView imageView = (CubeImageView) view.findViewById(R.id.store_house_ptr_image); 35 | ImageLoader imageLoader = ImageLoaderFactory.create(getContext()); 36 | String pic = "http://img5.duitang.com/uploads/item/201406/28/20140628122218_fLQyP.thumb.jpeg"; 37 | imageView.loadImage(imageLoader, pic); 38 | 39 | final PtrFrameLayout frame = (PtrFrameLayout) view.findViewById(R.id.store_house_ptr_frame); 40 | final StoreHouseHeader header = new StoreHouseHeader(getContext()); 41 | header.setPadding(0, LocalDisplay.dp2px(15), 0, 0); 42 | 43 | // using string array from resource xml file 44 | header.initWithStringArray(R.array.storehouse); 45 | 46 | frame.setDurationToCloseHeader(1500); 47 | frame.setHeaderView(header); 48 | frame.addPtrUIHandler(header); 49 | frame.postDelayed(new Runnable() { 50 | @Override 51 | public void run() { 52 | frame.autoRefresh(false); 53 | } 54 | }, 100); 55 | 56 | // change header after loaded 57 | frame.addPtrUIHandler(new PtrUIHandler() { 58 | 59 | private int mLoadTime = 0; 60 | 61 | @Override 62 | public void onUIReset(PtrFrameLayout frame) { 63 | mLoadTime++; 64 | if (mLoadTime % 2 == 0) { 65 | header.setScale(1); 66 | header.initWithStringArray(R.array.storehouse); 67 | } else { 68 | header.setScale(0.5f); 69 | header.initWithStringArray(R.array.akta); 70 | } 71 | } 72 | 73 | @Override 74 | public void onUIRefreshPrepare(PtrFrameLayout frame) { 75 | if (mLoadTime % 2 == 0) { 76 | setHeaderTitle(mTitlePre + "R.array.storehouse"); 77 | } else { 78 | setHeaderTitle(mTitlePre + "R.array.akta"); 79 | } 80 | } 81 | 82 | @Override 83 | public void onUIRefreshBegin(PtrFrameLayout frame) { 84 | 85 | } 86 | 87 | @Override 88 | public void onUIRefreshComplete(PtrFrameLayout frame, boolean isHeader) { 89 | 90 | } 91 | 92 | @Override 93 | public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) { 94 | 95 | } 96 | }); 97 | 98 | frame.setPtrHandler(new PtrHandler() { 99 | @Override 100 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 101 | return true; 102 | } 103 | 104 | @Override 105 | public void onRefreshBegin(final PtrFrameLayout frame) { 106 | frame.postDelayed(new Runnable() { 107 | @Override 108 | public void run() { 109 | frame.refreshComplete(); 110 | } 111 | }, 2000); 112 | } 113 | }); 114 | return view; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/RentalsStyleFragment.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.drawable.BitmapDrawable; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | import android.graphics.drawable.TransitionDrawable; 8 | import android.os.Bundle; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import in.srain.cube.image.CubeImageView; 13 | import in.srain.cube.image.ImageLoader; 14 | import in.srain.cube.image.ImageLoaderFactory; 15 | import in.srain.cube.image.ImageTask; 16 | import in.srain.cube.image.iface.ImageLoadHandler; 17 | import in.srain.cube.mints.base.TitleBaseFragment; 18 | import in.srain.cube.util.LocalDisplay; 19 | import in.srain.cube.views.ptr.PtrFrameLayout; 20 | import in.srain.cube.views.ptr.PtrHandler; 21 | import in.srain.cube.views.ptr.demo.R; 22 | import in.srain.cube.views.ptr.demo.ui.header.RentalsSunHeaderView; 23 | 24 | public class RentalsStyleFragment extends TitleBaseFragment { 25 | 26 | private String mUrl = "http://img4.duitang.com/uploads/blog/201407/07/20140707113856_hBf3R.thumb.jpeg"; 27 | private long mStartLoadingTime = -1; 28 | private boolean mImageHasLoaded = false; 29 | 30 | @Override 31 | public void onEnter(Object data) { 32 | if (data != null && data instanceof String) { 33 | mUrl = (String) data; 34 | } 35 | } 36 | 37 | @Override 38 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 39 | 40 | View view = inflater.inflate(R.layout.fragment_materail_style, null); 41 | setHeaderTitle(R.string.ptr_demo_rentals_style); 42 | 43 | final CubeImageView imageView = (CubeImageView) view.findViewById(R.id.material_style_image_view); 44 | final ImageLoader imageLoader = ImageLoaderFactory.create(getContext()); 45 | 46 | final PtrFrameLayout frame = (PtrFrameLayout) view.findViewById(R.id.material_style_ptr_frame); 47 | 48 | // header 49 | final RentalsSunHeaderView header = new RentalsSunHeaderView(getContext()); 50 | header.setLayoutParams(new PtrFrameLayout.LayoutParams(-1, -2)); 51 | header.setPadding(0, LocalDisplay.dp2px(15), 0, LocalDisplay.dp2px(10)); 52 | header.setUp(frame); 53 | 54 | frame.setLoadingMinTime(1000); 55 | frame.setDurationToCloseHeader(1500); 56 | frame.setHeaderView(header); 57 | frame.addPtrUIHandler(header); 58 | // frame.setPullToRefresh(true); 59 | frame.postDelayed(new Runnable() { 60 | @Override 61 | public void run() { 62 | frame.autoRefresh(true); 63 | } 64 | }, 100); 65 | 66 | frame.setPtrHandler(new PtrHandler() { 67 | @Override 68 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 69 | return true; 70 | } 71 | 72 | @Override 73 | public void onRefreshBegin(final PtrFrameLayout frame) { 74 | if (mImageHasLoaded) { 75 | long delay = 1500; 76 | frame.postDelayed(new Runnable() { 77 | @Override 78 | public void run() { 79 | frame.refreshComplete(); 80 | } 81 | }, delay); 82 | } else { 83 | mStartLoadingTime = System.currentTimeMillis(); 84 | imageView.loadImage(imageLoader, mUrl); 85 | } 86 | } 87 | }); 88 | 89 | ImageLoadHandler imageLoadHandler = new ImageLoadHandler() { 90 | @Override 91 | public void onLoading(ImageTask imageTask, CubeImageView cubeImageView) { 92 | } 93 | 94 | @Override 95 | public void onLoadFinish(ImageTask imageTask, final CubeImageView cubeImageView, final BitmapDrawable bitmapDrawable) { 96 | mImageHasLoaded = true; 97 | long delay = 1500; 98 | frame.postDelayed(new Runnable() { 99 | @Override 100 | public void run() { 101 | if (cubeImageView != null && bitmapDrawable != null) { 102 | TransitionDrawable w1 = new TransitionDrawable(new Drawable[]{new ColorDrawable(Color.WHITE), (Drawable) bitmapDrawable}); 103 | imageView.setImageDrawable(w1); 104 | w1.startTransition(200); 105 | } 106 | frame.refreshComplete(); 107 | } 108 | }, delay); 109 | } 110 | 111 | @Override 112 | public void onLoadError(ImageTask imageTask, CubeImageView cubeImageView, int i) { 113 | 114 | } 115 | }; 116 | imageLoader.setImageLoadHandler(imageLoadHandler); 117 | return view; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/PtrUIHandlerHolder.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr; 2 | 3 | import in.srain.cube.views.ptr.indicator.PtrIndicator; 4 | 5 | /** 6 | * A single linked list to wrap PtrUIHandler 7 | */ 8 | class PtrUIHandlerHolder implements PtrUIHandler { 9 | 10 | private PtrUIHandler mHandler; 11 | private PtrUIHandlerHolder mNext; 12 | 13 | private boolean contains(PtrUIHandler handler) { 14 | return mHandler != null && mHandler == handler; 15 | } 16 | 17 | private PtrUIHandlerHolder() { 18 | 19 | } 20 | 21 | public boolean hasHandler() { 22 | return mHandler != null; 23 | } 24 | 25 | private PtrUIHandler getHandler() { 26 | return mHandler; 27 | } 28 | 29 | public static void addHandler(PtrUIHandlerHolder head, PtrUIHandler handler) { 30 | 31 | if (null == handler) { 32 | return; 33 | } 34 | if (head == null) { 35 | return; 36 | } 37 | if (null == head.mHandler) { 38 | head.mHandler = handler; 39 | return; 40 | } 41 | 42 | PtrUIHandlerHolder current = head; 43 | for (; ; current = current.mNext) { 44 | 45 | // duplicated 46 | if (current.contains(handler)) { 47 | return; 48 | } 49 | if (current.mNext == null) { 50 | break; 51 | } 52 | } 53 | 54 | PtrUIHandlerHolder newHolder = new PtrUIHandlerHolder(); 55 | newHolder.mHandler = handler; 56 | current.mNext = newHolder; 57 | } 58 | 59 | public static PtrUIHandlerHolder create() { 60 | return new PtrUIHandlerHolder(); 61 | } 62 | 63 | public static PtrUIHandlerHolder removeHandler(PtrUIHandlerHolder head, PtrUIHandler handler) { 64 | if (head == null || handler == null || null == head.mHandler) { 65 | return head; 66 | } 67 | 68 | PtrUIHandlerHolder current = head; 69 | PtrUIHandlerHolder pre = null; 70 | do { 71 | 72 | // delete current: link pre to next, unlink next from current; 73 | // pre will no change, current move to next element; 74 | if (current.contains(handler)) { 75 | 76 | // current is head 77 | if (pre == null) { 78 | 79 | head = current.mNext; 80 | current.mNext = null; 81 | 82 | current = head; 83 | } else { 84 | 85 | pre.mNext = current.mNext; 86 | current.mNext = null; 87 | current = pre.mNext; 88 | } 89 | } else { 90 | pre = current; 91 | current = current.mNext; 92 | } 93 | 94 | } while (current != null); 95 | 96 | if (head == null) { 97 | head = new PtrUIHandlerHolder(); 98 | } 99 | return head; 100 | } 101 | 102 | @Override 103 | public void onUIReset(PtrFrameLayout frame) { 104 | PtrUIHandlerHolder current = this; 105 | do { 106 | final PtrUIHandler handler = current.getHandler(); 107 | if (null != handler) { 108 | handler.onUIReset(frame); 109 | } 110 | } while ((current = current.mNext) != null); 111 | } 112 | 113 | @Override 114 | public void onUIRefreshPrepare(PtrFrameLayout frame) { 115 | if (!hasHandler()) { 116 | return; 117 | } 118 | PtrUIHandlerHolder current = this; 119 | do { 120 | final PtrUIHandler handler = current.getHandler(); 121 | if (null != handler) { 122 | handler.onUIRefreshPrepare(frame); 123 | } 124 | } while ((current = current.mNext) != null); 125 | } 126 | 127 | @Override 128 | public void onUIRefreshBegin(PtrFrameLayout frame) { 129 | PtrUIHandlerHolder current = this; 130 | do { 131 | final PtrUIHandler handler = current.getHandler(); 132 | if (null != handler) { 133 | handler.onUIRefreshBegin(frame); 134 | } 135 | } while ((current = current.mNext) != null); 136 | } 137 | 138 | @Override 139 | public void onUIRefreshComplete(PtrFrameLayout frame, boolean isHeader) { 140 | PtrUIHandlerHolder current = this; 141 | do { 142 | final PtrUIHandler handler = current.getHandler(); 143 | if (null != handler) { 144 | handler.onUIRefreshComplete(frame, isHeader); 145 | } 146 | } while ((current = current.mNext) != null); 147 | } 148 | 149 | @Override 150 | public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) { 151 | PtrUIHandlerHolder current = this; 152 | do { 153 | final PtrUIHandler handler = current.getHandler(); 154 | if (null != handler) { 155 | handler.onUIPositionChange(frame, isUnderTouch, status, ptrIndicator); 156 | } 157 | } while ((current = current.mNext) != null); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/WithListView.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.os.Bundle; 4 | import android.text.TextUtils; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.AdapterView; 9 | import android.widget.ImageView; 10 | import android.widget.ListView; 11 | import in.srain.cube.image.CubeImageView; 12 | import in.srain.cube.image.ImageLoader; 13 | import in.srain.cube.image.ImageLoaderFactory; 14 | import in.srain.cube.mints.base.TitleBaseFragment; 15 | import in.srain.cube.request.JsonData; 16 | import in.srain.cube.request.RequestFinishHandler; 17 | import in.srain.cube.views.list.ListViewDataAdapter; 18 | import in.srain.cube.views.list.ViewHolderBase; 19 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 20 | import in.srain.cube.views.ptr.PtrDefaultHandler; 21 | import in.srain.cube.views.ptr.PtrFrameLayout; 22 | import in.srain.cube.views.ptr.PtrHandler; 23 | import in.srain.cube.views.ptr.demo.R; 24 | import in.srain.cube.views.ptr.demo.data.DemoRequestData; 25 | import in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment; 26 | 27 | public class WithListView extends TitleBaseFragment { 28 | 29 | private ImageLoader mImageLoader; 30 | private ListViewDataAdapter mAdapter; 31 | private PtrClassicFrameLayout mPtrFrame; 32 | 33 | @Override 34 | public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 35 | 36 | setHeaderTitle(R.string.ptr_demo_block_list_view); 37 | 38 | mImageLoader = ImageLoaderFactory.create(getContext()); 39 | 40 | final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_list_view, null); 41 | final ListView listView = (ListView) contentView.findViewById(R.id.rotate_header_list_view); 42 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 43 | @Override 44 | public void onItemClick(AdapterView parent, View view, int position, long id) { 45 | if (position >= 0) { 46 | final String url = mAdapter.getItem(position).optString("pic"); 47 | if (!TextUtils.isEmpty(url)) { 48 | getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url); 49 | } 50 | } 51 | } 52 | }); 53 | 54 | mAdapter = new ListViewDataAdapter(); 55 | mAdapter.setViewHolderClass(this, ViewHolder.class); 56 | listView.setAdapter(mAdapter); 57 | 58 | mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_list_view_frame); 59 | mPtrFrame.setLastUpdateTimeRelateObject(this); 60 | mPtrFrame.setPtrHandler(new PtrHandler() { 61 | @Override 62 | public void onRefreshBegin(PtrFrameLayout frame) { 63 | updateData(); 64 | } 65 | 66 | @Override 67 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 68 | return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header); 69 | } 70 | }); 71 | // the following are default settings 72 | mPtrFrame.setResistance(1.7f); 73 | mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f); 74 | mPtrFrame.setDurationToClose(200); 75 | mPtrFrame.setDurationToCloseHeader(1000); 76 | // default is false 77 | mPtrFrame.setPullToRefresh(false); 78 | // default is true 79 | mPtrFrame.setKeepHeaderWhenRefresh(true); 80 | mPtrFrame.postDelayed(new Runnable() { 81 | @Override 82 | public void run() { 83 | mPtrFrame.autoRefresh(); 84 | } 85 | }, 100); 86 | return contentView; 87 | } 88 | 89 | protected void updateData() { 90 | 91 | DemoRequestData.getImageList(new RequestFinishHandler() { 92 | @Override 93 | public void onRequestFinish(final JsonData data) { 94 | mPtrFrame.postDelayed(new Runnable() { 95 | @Override 96 | public void run() { 97 | mAdapter.getDataList().clear(); 98 | mAdapter.getDataList().addAll(data.optJson("data").optJson("list").toArrayList()); 99 | mPtrFrame.refreshComplete(); 100 | mAdapter.notifyDataSetChanged(); 101 | } 102 | }, 0); 103 | } 104 | }); 105 | } 106 | 107 | private class ViewHolder extends ViewHolderBase { 108 | 109 | private CubeImageView mImageView; 110 | 111 | @Override 112 | public View createView(LayoutInflater inflater) { 113 | View v = inflater.inflate(R.layout.list_view_item, null); 114 | mImageView = (CubeImageView) v.findViewById(R.id.list_view_item_image_view); 115 | mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); 116 | return v; 117 | } 118 | 119 | @Override 120 | public void showData(int position, JsonData itemData) { 121 | mImageView.loadImage(mImageLoader, itemData.optString("pic")); 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/MaterialStyleFragment.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.drawable.BitmapDrawable; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | import android.graphics.drawable.TransitionDrawable; 8 | import android.os.Bundle; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import in.srain.cube.image.CubeImageView; 13 | import in.srain.cube.image.ImageLoader; 14 | import in.srain.cube.image.ImageLoaderFactory; 15 | import in.srain.cube.image.ImageTask; 16 | import in.srain.cube.image.iface.ImageLoadHandler; 17 | import in.srain.cube.mints.base.TitleBaseFragment; 18 | import in.srain.cube.util.LocalDisplay; 19 | import in.srain.cube.views.ptr.PtrFrameLayout; 20 | import in.srain.cube.views.ptr.PtrHandler; 21 | import in.srain.cube.views.ptr.demo.R; 22 | import in.srain.cube.views.ptr.header.MaterialHeader; 23 | 24 | public class MaterialStyleFragment extends TitleBaseFragment { 25 | 26 | private String mUrl = "http://img5.duitang.com/uploads/blog/201407/17/20140717113117_mUssJ.thumb.jpeg"; 27 | private long mStartLoadingTime = -1; 28 | private boolean mImageHasLoaded = false; 29 | protected PtrFrameLayout mPtrFrameLayout; 30 | 31 | @Override 32 | public void onEnter(Object data) { 33 | if (data != null && data instanceof String) { 34 | mUrl = (String) data; 35 | } 36 | } 37 | 38 | @Override 39 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 40 | 41 | View view = inflater.inflate(R.layout.fragment_materail_style, null); 42 | setHeaderTitle(R.string.ptr_demo_material_style); 43 | 44 | final CubeImageView imageView = (CubeImageView) view.findViewById(R.id.material_style_image_view); 45 | final ImageLoader imageLoader = ImageLoaderFactory.create(getContext()); 46 | 47 | mPtrFrameLayout = (PtrFrameLayout) view.findViewById(R.id.material_style_ptr_frame); 48 | 49 | // header 50 | final MaterialHeader header = new MaterialHeader(getContext()); 51 | int[] colors = getResources().getIntArray(R.array.google_colors); 52 | header.setColorSchemeColors(colors); 53 | header.setLayoutParams(new PtrFrameLayout.LayoutParams(-1, -2)); 54 | header.setPadding(0, LocalDisplay.dp2px(15), 0, LocalDisplay.dp2px(10)); 55 | header.setPtrFrameLayout(mPtrFrameLayout); 56 | 57 | mPtrFrameLayout.setLoadingMinTime(1000); 58 | mPtrFrameLayout.setDurationToCloseHeader(1500); 59 | mPtrFrameLayout.setHeaderView(header); 60 | mPtrFrameLayout.addPtrUIHandler(header); 61 | mPtrFrameLayout.postDelayed(new Runnable() { 62 | @Override 63 | public void run() { 64 | mPtrFrameLayout.autoRefresh(false); 65 | } 66 | }, 100); 67 | 68 | mPtrFrameLayout.setPtrHandler(new PtrHandler() { 69 | @Override 70 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 71 | return true; 72 | } 73 | 74 | @Override 75 | public void onRefreshBegin(final PtrFrameLayout frame) { 76 | if (mImageHasLoaded) { 77 | long delay = (long) (1000 + Math.random() * 2000); 78 | delay = Math.max(0, delay); 79 | delay = 0; 80 | frame.postDelayed(new Runnable() { 81 | @Override 82 | public void run() { 83 | frame.refreshComplete(); 84 | } 85 | }, delay); 86 | } else { 87 | mStartLoadingTime = System.currentTimeMillis(); 88 | imageView.loadImage(imageLoader, mUrl); 89 | } 90 | } 91 | }); 92 | 93 | ImageLoadHandler imageLoadHandler = new ImageLoadHandler() { 94 | @Override 95 | public void onLoading(ImageTask imageTask, CubeImageView cubeImageView) { 96 | } 97 | 98 | @Override 99 | public void onLoadFinish(ImageTask imageTask, final CubeImageView cubeImageView, final BitmapDrawable bitmapDrawable) { 100 | mImageHasLoaded = true; 101 | long delay = Math.max(0, 1000 - (System.currentTimeMillis() - mStartLoadingTime)); 102 | delay = 0; 103 | mPtrFrameLayout.postDelayed(new Runnable() { 104 | @Override 105 | public void run() { 106 | if (cubeImageView != null && bitmapDrawable != null) { 107 | TransitionDrawable w1 = new TransitionDrawable(new Drawable[]{new ColorDrawable(Color.WHITE), (Drawable) bitmapDrawable}); 108 | imageView.setImageDrawable(w1); 109 | w1.startTransition(200); 110 | } 111 | mPtrFrameLayout.refreshComplete(); 112 | } 113 | }, delay); 114 | } 115 | 116 | @Override 117 | public void onLoadError(ImageTask imageTask, CubeImageView cubeImageView, int i) { 118 | 119 | } 120 | }; 121 | imageLoader.setImageLoadHandler(imageLoadHandler); 122 | return view; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/WithListViewAndEmptyView.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.os.Bundle; 4 | import android.text.TextUtils; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.AdapterView; 9 | import android.widget.ImageView; 10 | import android.widget.ListView; 11 | import android.widget.TextView; 12 | import in.srain.cube.image.CubeImageView; 13 | import in.srain.cube.image.ImageLoader; 14 | import in.srain.cube.image.ImageLoaderFactory; 15 | import in.srain.cube.mints.base.TitleBaseFragment; 16 | import in.srain.cube.request.JsonData; 17 | import in.srain.cube.request.RequestFinishHandler; 18 | import in.srain.cube.views.list.ListViewDataAdapter; 19 | import in.srain.cube.views.list.ViewHolderBase; 20 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 21 | import in.srain.cube.views.ptr.PtrDefaultHandler; 22 | import in.srain.cube.views.ptr.PtrFrameLayout; 23 | import in.srain.cube.views.ptr.PtrHandler; 24 | import in.srain.cube.views.ptr.demo.R; 25 | import in.srain.cube.views.ptr.demo.data.DemoRequestData; 26 | import in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment; 27 | 28 | public class WithListViewAndEmptyView extends TitleBaseFragment { 29 | 30 | private ImageLoader mImageLoader; 31 | private ListViewDataAdapter mAdapter; 32 | private PtrClassicFrameLayout mPtrFrame; 33 | private TextView mTextView; 34 | private ListView mListView; 35 | 36 | @Override 37 | public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 38 | 39 | setHeaderTitle(R.string.ptr_demo_block_with_list_view_and_empty_view); 40 | 41 | mImageLoader = ImageLoaderFactory.create(getContext()); 42 | 43 | 44 | final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_list_view_and_empty_view, null); 45 | mTextView = (TextView) contentView.findViewById(R.id.list_view_with_empty_view_fragment_empty_view); 46 | mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.list_view_with_empty_view_fragment_ptr_frame); 47 | 48 | mTextView.setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View v) { 51 | mPtrFrame.setVisibility(View.VISIBLE); 52 | mPtrFrame.autoRefresh(); 53 | } 54 | }); 55 | 56 | mListView = (ListView) contentView.findViewById(R.id.list_view_with_empty_view_fragment_list_view); 57 | mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 58 | @Override 59 | public void onItemClick(AdapterView parent, View view, int position, long id) { 60 | if (position >= 0) { 61 | final String url = mAdapter.getItem(position).optString("pic"); 62 | if (!TextUtils.isEmpty(url)) { 63 | getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url); 64 | } 65 | } 66 | } 67 | }); 68 | 69 | // show empty view 70 | mPtrFrame.setVisibility(View.INVISIBLE); 71 | mTextView.setVisibility(View.VISIBLE); 72 | 73 | mAdapter = new ListViewDataAdapter(); 74 | mAdapter.setViewHolderClass(this, ViewHolder.class); 75 | mListView.setAdapter(mAdapter); 76 | 77 | mPtrFrame.setLastUpdateTimeRelateObject(this); 78 | mPtrFrame.setPtrHandler(new PtrHandler() { 79 | @Override 80 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 81 | 82 | // here check $mListView instead of $content 83 | return PtrDefaultHandler.checkContentCanBePulledDown(frame, mListView, header); 84 | } 85 | 86 | @Override 87 | public void onRefreshBegin(PtrFrameLayout frame) { 88 | updateData(); 89 | } 90 | }); 91 | // the following are default settings 92 | mPtrFrame.setResistance(1.7f); 93 | mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f); 94 | mPtrFrame.setDurationToClose(200); 95 | mPtrFrame.setDurationToCloseHeader(1000); 96 | // default is false 97 | mPtrFrame.setPullToRefresh(false); 98 | // default is true 99 | mPtrFrame.setKeepHeaderWhenRefresh(true); 100 | return contentView; 101 | } 102 | 103 | protected void updateData() { 104 | 105 | DemoRequestData.getImageList(new RequestFinishHandler() { 106 | @Override 107 | public void onRequestFinish(final JsonData data) { 108 | displayData(data); 109 | } 110 | }); 111 | } 112 | 113 | private void displayData(JsonData data) { 114 | 115 | mTextView.setVisibility(View.GONE); 116 | 117 | mAdapter.getDataList().clear(); 118 | mAdapter.getDataList().addAll(data.optJson("data").optJson("list").toArrayList()); 119 | mPtrFrame.refreshComplete(); 120 | mAdapter.notifyDataSetChanged(); 121 | } 122 | 123 | private class ViewHolder extends ViewHolderBase { 124 | 125 | private CubeImageView mImageView; 126 | 127 | @Override 128 | public View createView(LayoutInflater inflater) { 129 | View v = inflater.inflate(R.layout.list_view_item, null); 130 | mImageView = (CubeImageView) v.findViewById(R.id.list_view_item_image_view); 131 | mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); 132 | return v; 133 | } 134 | 135 | @Override 136 | public void showData(int position, JsonData itemData) { 137 | mImageView.loadImage(mImageLoader, itemData.optString("pic")); 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/header/MaterialHeader.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.header; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.Drawable; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.view.animation.Animation; 11 | import android.view.animation.Transformation; 12 | import in.srain.cube.views.ptr.PtrFrameLayout; 13 | import in.srain.cube.views.ptr.PtrUIHandler; 14 | import in.srain.cube.views.ptr.PtrUIHandlerHook; 15 | import in.srain.cube.views.ptr.indicator.PtrIndicator; 16 | 17 | public class MaterialHeader extends View implements PtrUIHandler { 18 | 19 | private MaterialProgressDrawable mDrawable; 20 | private float mScale = 1f; 21 | private PtrFrameLayout mPtrFrameLayout; 22 | 23 | private Animation mScaleAnimation = new Animation() { 24 | @Override 25 | public void applyTransformation(float interpolatedTime, Transformation t) { 26 | mScale = 1f - interpolatedTime; 27 | mDrawable.setAlpha((int) (255 * mScale)); 28 | invalidate(); 29 | } 30 | }; 31 | 32 | public MaterialHeader(Context context) { 33 | super(context); 34 | initView(); 35 | } 36 | 37 | public MaterialHeader(Context context, AttributeSet attrs) { 38 | super(context, attrs); 39 | initView(); 40 | } 41 | 42 | public MaterialHeader(Context context, AttributeSet attrs, int defStyleAttr) { 43 | super(context, attrs, defStyleAttr); 44 | initView(); 45 | } 46 | 47 | public void setPtrFrameLayout(PtrFrameLayout layout) { 48 | 49 | final PtrUIHandlerHook mPtrUIHandlerHook = new PtrUIHandlerHook() { 50 | @Override 51 | public void run() { 52 | startAnimation(mScaleAnimation); 53 | } 54 | }; 55 | 56 | mScaleAnimation.setDuration(200); 57 | mScaleAnimation.setAnimationListener(new Animation.AnimationListener() { 58 | @Override 59 | public void onAnimationStart(Animation animation) { 60 | 61 | } 62 | 63 | @Override 64 | public void onAnimationEnd(Animation animation) { 65 | mPtrUIHandlerHook.resume(); 66 | } 67 | 68 | @Override 69 | public void onAnimationRepeat(Animation animation) { 70 | 71 | } 72 | }); 73 | 74 | mPtrFrameLayout = layout; 75 | mPtrFrameLayout.setRefreshCompleteHook(mPtrUIHandlerHook); 76 | } 77 | 78 | private void initView() { 79 | mDrawable = new MaterialProgressDrawable(getContext(), this); 80 | mDrawable.setBackgroundColor(Color.WHITE); 81 | mDrawable.setCallback(this); 82 | } 83 | 84 | @Override 85 | public void invalidateDrawable(Drawable dr) { 86 | if (dr == mDrawable) { 87 | invalidate(); 88 | } else { 89 | super.invalidateDrawable(dr); 90 | } 91 | } 92 | 93 | public void setColorSchemeColors(int[] colors) { 94 | mDrawable.setColorSchemeColors(colors); 95 | invalidate(); 96 | } 97 | 98 | @Override 99 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 100 | int height = mDrawable.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom(); 101 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); 102 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 103 | } 104 | 105 | @Override 106 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 107 | final int size = mDrawable.getIntrinsicHeight(); 108 | mDrawable.setBounds(0, 0, size, size); 109 | } 110 | 111 | @Override 112 | protected void onDraw(Canvas canvas) { 113 | final int saveCount = canvas.save(); 114 | Rect rect = mDrawable.getBounds(); 115 | int l = getPaddingLeft() + (getMeasuredWidth() - mDrawable.getIntrinsicWidth()) / 2; 116 | canvas.translate(l, getPaddingTop()); 117 | canvas.scale(mScale, mScale, rect.exactCenterX(), rect.exactCenterY()); 118 | mDrawable.draw(canvas); 119 | canvas.restoreToCount(saveCount); 120 | } 121 | 122 | /** 123 | * When the content view has reached top and refresh has been completed, view will be reset. 124 | * 125 | * @param frame 126 | */ 127 | @Override 128 | public void onUIReset(PtrFrameLayout frame) { 129 | mScale = 1f; 130 | mDrawable.stop(); 131 | } 132 | 133 | /** 134 | * prepare for loading 135 | * 136 | * @param frame 137 | */ 138 | @Override 139 | public void onUIRefreshPrepare(PtrFrameLayout frame) { 140 | } 141 | 142 | /** 143 | * perform refreshing UI 144 | * 145 | * @param frame 146 | */ 147 | @Override 148 | public void onUIRefreshBegin(PtrFrameLayout frame) { 149 | mDrawable.setAlpha(255); 150 | mDrawable.start(); 151 | } 152 | 153 | /** 154 | * perform UI after refresh 155 | * 156 | * @param frame 157 | */ 158 | @Override 159 | public void onUIRefreshComplete(PtrFrameLayout frame, boolean isHeader) { 160 | mDrawable.stop(); 161 | } 162 | 163 | @Override 164 | public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) { 165 | 166 | float percent = Math.min(1f, ptrIndicator.getCurrentPercent()); 167 | 168 | if (status == PtrFrameLayout.PTR_STATUS_PREPARE) { 169 | mDrawable.setAlpha((int) (255 * percent)); 170 | mDrawable.showArrow(true); 171 | 172 | float strokeStart = ((percent) * .8f); 173 | mDrawable.setStartEndTrim(0f, Math.min(0.8f, strokeStart)); 174 | mDrawable.setArrowScale(Math.min(1f, percent)); 175 | 176 | // magic 177 | float rotation = (-0.25f + .4f * percent + percent * 2) * .5f; 178 | mDrawable.setProgressRotation(rotation); 179 | invalidate(); 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/storehouse/StoreHouseUsingPointList.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.storehouse; 2 | 3 | import android.graphics.Point; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import in.srain.cube.image.CubeImageView; 9 | import in.srain.cube.image.ImageLoader; 10 | import in.srain.cube.image.ImageLoaderFactory; 11 | import in.srain.cube.mints.base.TitleBaseFragment; 12 | import in.srain.cube.util.LocalDisplay; 13 | import in.srain.cube.views.ptr.PtrFrameLayout; 14 | import in.srain.cube.views.ptr.PtrHandler; 15 | import in.srain.cube.views.ptr.demo.R; 16 | import in.srain.cube.views.ptr.header.StoreHouseHeader; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | /** 22 | * the point list used here is taken from: 23 | * https://github.com/cloay/CRefreshLayout 24 | */ 25 | 26 | public class StoreHouseUsingPointList extends TitleBaseFragment { 27 | 28 | @Override 29 | protected View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 30 | setHeaderTitle(R.string.ptr_demo_storehouse_header_using_point_list); 31 | 32 | View view = inflater.inflate(R.layout.fragment_storehouse_header, null); 33 | 34 | CubeImageView imageView = (CubeImageView) view.findViewById(R.id.store_house_ptr_image); 35 | ImageLoader imageLoader = ImageLoaderFactory.create(getContext()); 36 | String pic = "http://img5.duitang.com/uploads/item/201406/28/20140628122218_fLQyP.thumb.jpeg"; 37 | imageView.loadImage(imageLoader, pic); 38 | 39 | final PtrFrameLayout frame = (PtrFrameLayout) view.findViewById(R.id.store_house_ptr_frame); 40 | 41 | // header 42 | final StoreHouseHeader header = new StoreHouseHeader(getContext()); 43 | header.setPadding(0, LocalDisplay.dp2px(15), 0, 0); 44 | 45 | header.initWithPointList(getPointList()); 46 | 47 | frame.setDurationToCloseHeader(3000); 48 | frame.setHeaderView(header); 49 | frame.addPtrUIHandler(header); 50 | frame.postDelayed(new Runnable() { 51 | @Override 52 | public void run() { 53 | frame.autoRefresh(false); 54 | } 55 | }, 100); 56 | 57 | frame.setPtrHandler(new PtrHandler() { 58 | @Override 59 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 60 | return true; 61 | } 62 | 63 | @Override 64 | public void onRefreshBegin(final PtrFrameLayout frame) { 65 | frame.postDelayed(new Runnable() { 66 | @Override 67 | public void run() { 68 | frame.refreshComplete(); 69 | } 70 | }, 2000); 71 | } 72 | }); 73 | return view; 74 | } 75 | 76 | private ArrayList getPointList() { 77 | // this point is taken from https://github.com/cloay/CRefreshLayout 78 | List startPoints = new ArrayList(); 79 | startPoints.add(new Point(240, 80)); 80 | startPoints.add(new Point(270, 80)); 81 | startPoints.add(new Point(265, 103)); 82 | startPoints.add(new Point(255, 65)); 83 | startPoints.add(new Point(275, 80)); 84 | startPoints.add(new Point(275, 80)); 85 | startPoints.add(new Point(302, 80)); 86 | startPoints.add(new Point(275, 107)); 87 | 88 | startPoints.add(new Point(320, 70)); 89 | startPoints.add(new Point(313, 80)); 90 | startPoints.add(new Point(330, 63)); 91 | startPoints.add(new Point(315, 87)); 92 | startPoints.add(new Point(330, 80)); 93 | startPoints.add(new Point(315, 100)); 94 | startPoints.add(new Point(330, 90)); 95 | startPoints.add(new Point(315, 110)); 96 | startPoints.add(new Point(345, 65)); 97 | startPoints.add(new Point(357, 67)); 98 | startPoints.add(new Point(363, 103)); 99 | 100 | startPoints.add(new Point(375, 80)); 101 | startPoints.add(new Point(375, 80)); 102 | startPoints.add(new Point(425, 80)); 103 | startPoints.add(new Point(380, 95)); 104 | startPoints.add(new Point(400, 63)); 105 | 106 | List endPoints = new ArrayList(); 107 | endPoints.add(new Point(270, 80)); 108 | endPoints.add(new Point(270, 110)); 109 | endPoints.add(new Point(270, 110)); 110 | endPoints.add(new Point(250, 110)); 111 | endPoints.add(new Point(275, 107)); 112 | endPoints.add(new Point(302, 80)); 113 | endPoints.add(new Point(302, 107)); 114 | endPoints.add(new Point(302, 107)); 115 | 116 | endPoints.add(new Point(340, 70)); 117 | endPoints.add(new Point(360, 80)); 118 | endPoints.add(new Point(330, 80)); 119 | endPoints.add(new Point(340, 87)); 120 | endPoints.add(new Point(315, 100)); 121 | endPoints.add(new Point(345, 98)); 122 | endPoints.add(new Point(330, 120)); 123 | endPoints.add(new Point(345, 108)); 124 | endPoints.add(new Point(360, 120)); 125 | endPoints.add(new Point(363, 75)); 126 | endPoints.add(new Point(345, 117)); 127 | 128 | endPoints.add(new Point(380, 95)); 129 | endPoints.add(new Point(425, 80)); 130 | endPoints.add(new Point(420, 95)); 131 | endPoints.add(new Point(420, 95)); 132 | endPoints.add(new Point(400, 120)); 133 | ArrayList list = new ArrayList(); 134 | 135 | int offsetX = Integer.MAX_VALUE; 136 | int offsetY = Integer.MAX_VALUE; 137 | 138 | for (int i = 0; i < startPoints.size(); i++) { 139 | offsetX = Math.min(startPoints.get(i).x, offsetX); 140 | offsetY = Math.min(startPoints.get(i).y, offsetY); 141 | } 142 | for (int i = 0; i < endPoints.size(); i++) { 143 | float[] point = new float[4]; 144 | point[0] = startPoints.get(i).x - offsetX; 145 | point[1] = startPoints.get(i).y - offsetY; 146 | point[2] = endPoints.get(i).x - offsetX; 147 | point[3] = endPoints.get(i).y - offsetY; 148 | list.add(point); 149 | } 150 | return list; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /ptr-demo/src/main/assets/request_init/demo/image-list.json: -------------------------------------------------------------------------------- 1 | {"data":{"time":"2014-08-27 02:13:01 UTC","list":[{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201311\/04\/20131104193715_NCexN.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201408\/09\/20140809210610_iTSJx.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/blog\/201401\/07\/20140107223310_LH3Uy.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201405\/09\/20140509222156_kVexJ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201306\/14\/20130614185903_raNR3.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201112\/11\/20111211191621_HU4Bj.thumb.jpg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/item\/201408\/07\/20140807224553_VXaUc.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/29\/20140729105929_GQLwC.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201408\/04\/20140804160432_LnFeB.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201408\/04\/20140804161101_JVJea.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/blog\/201408\/04\/20140804093210_FxFNd.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201408\/04\/20140804160314_hRKtv.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/item\/201408\/01\/20140801080524_SnGfE.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/23\/20140723140958_NSWfE.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201407\/22\/20140722153305_WHejQ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/21\/20140721010148_ZBQwe.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/item\/201407\/23\/20140723085122_cmteu.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/23\/20140723130620_Z2yJB.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/blog\/201407\/20\/20140720204738_NXxLE.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/item\/201407\/20\/20140720134916_VGfyh.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717113117_mUssJ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717121501_wfFEm.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717121431_w4AV8.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717121918_TtJjY.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/11\/20140711234806_FNLBQ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/18\/20140718121437_UyiAS.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717114829_RiCXR.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201407\/17\/20140717120301_wGFYL.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/11\/20140511121106_JXS4B.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/10\/20140510094144_kfLji.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/09\/20140509201906_kERjy.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/08\/20140508193226_UaSGB.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201405\/05\/20140505201747_aPNtf.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/06\/20140506104824_jPWQj.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/05\/20140505201105_MkXdn.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/03\/20140503205822_GCzta.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/03\/20140503205535_cCHPB.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/03\/20140503204354_xxSQX.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201404\/06\/20140406191307_GTxFd.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201404\/06\/20140406191247_BG2cU.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201404\/06\/20140406191114_MzYtw.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201404\/06\/20140406191127_fazJA.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/10\/20140710081204_vYnCi.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/15\/20140715133758_M2Y3J.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/item\/201407\/13\/20140713190806_TGJHm.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201407\/05\/20140705223413_5r3ze.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/13\/20140713012526_tcy5u.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/13\/20140713121424_Gy43T.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/item\/201407\/15\/20140715033844_tcvrY.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/10\/20140710181106_4HHay.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/06\/20140706122850_8PER3.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/07\/20140707192042_8xKXF.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/07\/20140707063954_mVa3y.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/08\/20140708093733_AFFhc.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/07\/20140707161220_unvzn.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201407\/07\/20140707113856_hBf3R.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201308\/26\/20130826090203_NtuYA.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/item\/201407\/07\/20140707145925_dHeKV.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625101534_xiZxN.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201406\/30\/20140630150534_EWUVY.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625121626_ZmT5n.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201307\/31\/20130731231806_4yGxV.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/28\/20140628122218_fLQyP.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201406\/26\/20140626131831_MrdKP.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201406\/16\/20140616165201_nuKWj.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625140308_KP4rn.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625121604_2auuA.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/item\/201406\/25\/20140625131625_LmmLZ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625132851_mPmKY.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625133312_ZtmW4.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625164858_AuafS.thumb.jpeg"}]},"server_time":"2014-08-27 02:13:01"} -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/WithGridViewInFrameLayout.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.os.Bundle; 4 | import android.text.TextUtils; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.AdapterView; 9 | import android.widget.GridView; 10 | import android.widget.ImageView.ScaleType; 11 | import android.widget.LinearLayout; 12 | 13 | import in.srain.cube.image.CubeImageView; 14 | import in.srain.cube.image.ImageLoader; 15 | import in.srain.cube.image.ImageLoaderFactory; 16 | import in.srain.cube.mints.base.TitleBaseFragment; 17 | import in.srain.cube.request.JsonData; 18 | import in.srain.cube.request.RequestFinishHandler; 19 | import in.srain.cube.util.LocalDisplay; 20 | import in.srain.cube.views.list.ListViewDataAdapter; 21 | import in.srain.cube.views.list.ViewHolderBase; 22 | import in.srain.cube.views.list.ViewHolderCreator; 23 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 24 | import in.srain.cube.views.ptr.PtrDefaultHandler2; 25 | import in.srain.cube.views.ptr.PtrFrameLayout; 26 | import in.srain.cube.views.ptr.demo.R; 27 | import in.srain.cube.views.ptr.demo.data.DemoRequestData; 28 | import in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment; 29 | 30 | public class WithGridViewInFrameLayout extends TitleBaseFragment { 31 | 32 | private static final int sGirdImageSize = (LocalDisplay.SCREEN_WIDTH_PIXELS - LocalDisplay.dp2px(12 + 12 + 10)) / 2; 33 | private ImageLoader mImageLoader; 34 | private ListViewDataAdapter mAdapter; 35 | private PtrClassicFrameLayout mPtrFrame; 36 | 37 | @Override 38 | public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 39 | 40 | setHeaderTitle(R.string.ptr_demo_block_grid_view); 41 | 42 | mImageLoader = ImageLoaderFactory.create(getContext()); 43 | 44 | final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_gridview, null); 45 | final GridView gridListView = (GridView) contentView.findViewById(R.id.rotate_header_grid_view); 46 | gridListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 47 | @Override 48 | public void onItemClick(AdapterView parent, View view, int position, long id) { 49 | if (position >= 0) { 50 | final String url = mAdapter.getItem(position).optString("pic"); 51 | if (!TextUtils.isEmpty(url)) { 52 | getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url); 53 | } 54 | } 55 | } 56 | }); 57 | 58 | mAdapter = new ListViewDataAdapter(new ViewHolderCreator() { 59 | @Override 60 | public ViewHolderBase createViewHolder() { 61 | return new ViewHolder(); 62 | } 63 | }); 64 | gridListView.setAdapter(mAdapter); 65 | 66 | mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_grid_view_frame); 67 | mPtrFrame.setLastUpdateTimeRelateObject(this); 68 | mPtrFrame.setPtrHandler(new PtrDefaultHandler2() { 69 | 70 | @Override 71 | public void onLoadMoreBegin(PtrFrameLayout frame) { 72 | updateData(); 73 | } 74 | 75 | @Override 76 | public void onRefreshBegin(PtrFrameLayout frame) { 77 | updateData(); 78 | } 79 | 80 | @Override 81 | public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) { 82 | return super.checkCanDoLoadMore(frame, gridListView, footer); 83 | } 84 | 85 | @Override 86 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 87 | return super.checkCanDoRefresh(frame, gridListView, header); 88 | } 89 | }); 90 | // the following are default settings 91 | mPtrFrame.setResistance(1.7f); // you can also set foot and header separately 92 | mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f); 93 | mPtrFrame.setDurationToClose(1000); // you can also set foot and header separately 94 | // default is false 95 | mPtrFrame.setPullToRefresh(false); 96 | 97 | // default is true 98 | mPtrFrame.setKeepHeaderWhenRefresh(true); 99 | mPtrFrame.postDelayed(new Runnable() { 100 | @Override 101 | public void run() { 102 | // mPtrFrame.autoRefresh(); 103 | } 104 | }, 100); 105 | // updateData(); 106 | 107 | setupViews(mPtrFrame); 108 | return contentView; 109 | } 110 | 111 | protected void setupViews(final PtrClassicFrameLayout ptrFrame) { 112 | 113 | } 114 | 115 | protected void updateData() { 116 | 117 | DemoRequestData.getImageList(new RequestFinishHandler() { 118 | @Override 119 | public void onRequestFinish(final JsonData data) { 120 | mPtrFrame.postDelayed(new Runnable() { 121 | @Override 122 | public void run() { 123 | mAdapter.getDataList().clear(); 124 | mAdapter.getDataList().addAll(data.optJson("data").optJson("list").toArrayList().subList(0,10)); 125 | mPtrFrame.refreshComplete(); 126 | mAdapter.notifyDataSetChanged(); 127 | } 128 | }, 1000); 129 | } 130 | }); 131 | } 132 | 133 | private class ViewHolder extends ViewHolderBase { 134 | 135 | private CubeImageView mImageView; 136 | 137 | @Override 138 | public View createView(LayoutInflater inflater) { 139 | View view = LayoutInflater.from(getActivity()).inflate(R.layout.with_grid_view_item_image_list_grid, null); 140 | mImageView = (CubeImageView) view.findViewById(R.id.with_grid_view_item_image); 141 | mImageView.setScaleType(ScaleType.CENTER_CROP); 142 | 143 | LinearLayout.LayoutParams lyp = new LinearLayout.LayoutParams(sGirdImageSize, sGirdImageSize); 144 | mImageView.setLayoutParams(lyp); 145 | return view; 146 | } 147 | 148 | @Override 149 | public void showData(int position, JsonData itemData) { 150 | String url = itemData.optString("pic"); 151 | mImageView.loadImage(mImageLoader, url); 152 | } 153 | } 154 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/classic/WithGridView.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.classic; 2 | 3 | import android.os.Bundle; 4 | import android.text.TextUtils; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.AdapterView; 9 | import android.widget.GridView; 10 | import android.widget.ImageView.ScaleType; 11 | import android.widget.LinearLayout; 12 | 13 | import in.srain.cube.image.CubeImageView; 14 | import in.srain.cube.image.ImageLoader; 15 | import in.srain.cube.image.ImageLoaderFactory; 16 | import in.srain.cube.mints.base.TitleBaseFragment; 17 | import in.srain.cube.request.JsonData; 18 | import in.srain.cube.request.RequestFinishHandler; 19 | import in.srain.cube.util.LocalDisplay; 20 | import in.srain.cube.views.list.ListViewDataAdapter; 21 | import in.srain.cube.views.list.ViewHolderBase; 22 | import in.srain.cube.views.list.ViewHolderCreator; 23 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 24 | import in.srain.cube.views.ptr.PtrDefaultHandler; 25 | import in.srain.cube.views.ptr.PtrDefaultHandler2; 26 | import in.srain.cube.views.ptr.PtrFrameLayout; 27 | import in.srain.cube.views.ptr.PtrHandler; 28 | import in.srain.cube.views.ptr.PtrHandler2; 29 | import in.srain.cube.views.ptr.demo.R; 30 | import in.srain.cube.views.ptr.demo.data.DemoRequestData; 31 | import in.srain.cube.views.ptr.demo.ui.MaterialStyleFragment; 32 | 33 | public class WithGridView extends TitleBaseFragment { 34 | 35 | private static final int sGirdImageSize = (LocalDisplay.SCREEN_WIDTH_PIXELS - LocalDisplay.dp2px(12 + 12 + 10)) / 2; 36 | private ImageLoader mImageLoader; 37 | private ListViewDataAdapter mAdapter; 38 | private PtrClassicFrameLayout mPtrFrame; 39 | 40 | @Override 41 | public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 42 | 43 | setHeaderTitle(R.string.ptr_demo_block_grid_view); 44 | 45 | mImageLoader = ImageLoaderFactory.create(getContext()); 46 | 47 | final View contentView = inflater.inflate(R.layout.fragment_classic_header_with_gridview, null); 48 | final GridView gridListView = (GridView) contentView.findViewById(R.id.rotate_header_grid_view); 49 | gridListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 50 | @Override 51 | public void onItemClick(AdapterView parent, View view, int position, long id) { 52 | if (position >= 0) { 53 | final String url = mAdapter.getItem(position).optString("pic"); 54 | if (!TextUtils.isEmpty(url)) { 55 | getContext().pushFragmentToBackStack(MaterialStyleFragment.class, url); 56 | } 57 | } 58 | } 59 | }); 60 | 61 | mAdapter = new ListViewDataAdapter(new ViewHolderCreator() { 62 | @Override 63 | public ViewHolderBase createViewHolder() { 64 | return new ViewHolder(); 65 | } 66 | }); 67 | gridListView.setAdapter(mAdapter); 68 | 69 | mPtrFrame = (PtrClassicFrameLayout) contentView.findViewById(R.id.rotate_header_grid_view_frame); 70 | mPtrFrame.setLastUpdateTimeRelateObject(this); 71 | mPtrFrame.setPtrHandler(new PtrDefaultHandler2() { 72 | 73 | @Override 74 | public void onLoadMoreBegin(PtrFrameLayout frame) { 75 | updateData(); 76 | } 77 | 78 | @Override 79 | public void onRefreshBegin(PtrFrameLayout frame) { 80 | updateData(); 81 | } 82 | 83 | @Override 84 | public boolean checkCanDoLoadMore(PtrFrameLayout frame, View content, View footer) { 85 | return super.checkCanDoLoadMore(frame, gridListView, footer); 86 | } 87 | 88 | @Override 89 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 90 | return super.checkCanDoRefresh(frame, gridListView, header); 91 | } 92 | }); 93 | // the following are default settings 94 | mPtrFrame.setResistance(1.7f); // you can also set foot and header separately 95 | mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f); 96 | mPtrFrame.setDurationToClose(1000); // you can also set foot and header separately 97 | // default is false 98 | mPtrFrame.setPullToRefresh(false); 99 | 100 | // default is true 101 | mPtrFrame.setKeepHeaderWhenRefresh(true); 102 | mPtrFrame.postDelayed(new Runnable() { 103 | @Override 104 | public void run() { 105 | // mPtrFrame.autoRefresh(); 106 | } 107 | }, 100); 108 | // updateData(); 109 | 110 | setupViews(mPtrFrame); 111 | return contentView; 112 | } 113 | 114 | protected void setupViews(final PtrClassicFrameLayout ptrFrame) { 115 | 116 | } 117 | 118 | protected void updateData() { 119 | 120 | DemoRequestData.getImageList(new RequestFinishHandler() { 121 | @Override 122 | public void onRequestFinish(final JsonData data) { 123 | mPtrFrame.postDelayed(new Runnable() { 124 | @Override 125 | public void run() { 126 | mAdapter.getDataList().clear(); 127 | mAdapter.getDataList().addAll(data.optJson("data").optJson("list").toArrayList().subList(0,10)); 128 | mPtrFrame.refreshComplete(); 129 | mAdapter.notifyDataSetChanged(); 130 | } 131 | }, 1000); 132 | } 133 | }); 134 | } 135 | 136 | private class ViewHolder extends ViewHolderBase { 137 | 138 | private CubeImageView mImageView; 139 | 140 | @Override 141 | public View createView(LayoutInflater inflater) { 142 | View view = LayoutInflater.from(getActivity()).inflate(R.layout.with_grid_view_item_image_list_grid, null); 143 | mImageView = (CubeImageView) view.findViewById(R.id.with_grid_view_item_image); 144 | mImageView.setScaleType(ScaleType.CENTER_CROP); 145 | 146 | LinearLayout.LayoutParams lyp = new LinearLayout.LayoutParams(sGirdImageSize, sGirdImageSize); 147 | mImageView.setLayoutParams(lyp); 148 | return view; 149 | } 150 | 151 | @Override 152 | public void showData(int position, JsonData itemData) { 153 | String url = itemData.optString("pic"); 154 | mImageView.loadImage(mImageLoader, url); 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /ptr-demo/src/main/java/in/srain/cube/views/ptr/demo/ui/viewpager/ViewPagerActivity.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.demo.ui.viewpager; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.support.v4.view.ViewPager; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.AbsListView; 12 | import android.widget.TextView; 13 | 14 | import in.srain.cube.mints.base.TitleBaseActivity; 15 | import in.srain.cube.request.JsonData; 16 | import in.srain.cube.request.RequestFinishHandler; 17 | import in.srain.cube.util.LocalDisplay; 18 | import in.srain.cube.views.pager.TabPageIndicator; 19 | import in.srain.cube.views.ptr.PtrClassicFrameLayout; 20 | import in.srain.cube.views.ptr.PtrFrameLayout; 21 | import in.srain.cube.views.ptr.PtrHandler; 22 | import in.srain.cube.views.ptr.demo.R; 23 | import in.srain.cube.views.ptr.demo.data.DemoRequestData; 24 | 25 | import java.util.ArrayList; 26 | 27 | public class ViewPagerActivity extends TitleBaseActivity { 28 | 29 | private TabPageIndicator mCatTabPageIndicator; 30 | private ViewPager mFragmentViewPager; 31 | private FragmentViewPagerAdapter mPagerAdapter; 32 | private PtrFrameLayout mPtrFrame; 33 | 34 | @Override 35 | public void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setHeaderTitle(R.string.ptr_demo_block_with_view_pager); 38 | setContentView(R.layout.activity_view_pager); 39 | initCateViews(); 40 | } 41 | 42 | private void initCateViews() { 43 | 44 | int startIndex = 0; 45 | 46 | mCatTabPageIndicator = (TabPageIndicator) findViewById(R.id.view_pager_tab_indicator); 47 | mFragmentViewPager = (ViewPager) this.findViewById(R.id.view_pager_view_pager); 48 | ArrayList list = new ArrayList(); 49 | 50 | for (int i = 1; i <= 8; i++) { 51 | list.add(ViewPagerFragment.create(i)); 52 | } 53 | mPagerAdapter = new FragmentViewPagerAdapter(getSupportFragmentManager(), list); 54 | mFragmentViewPager.setAdapter(mPagerAdapter); 55 | 56 | mCatTabPageIndicator.setViewHolderCreator(new TabPageIndicator.ViewHolderCreator() { 57 | @Override 58 | public TabPageIndicator.ViewHolderBase createViewHolder() { 59 | return new HomeCatItemViewHolder(); 60 | } 61 | }); 62 | mCatTabPageIndicator.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { 63 | 64 | @Override 65 | public void onPageSelected(int i) { 66 | switchTo(i); 67 | } 68 | }); 69 | mCatTabPageIndicator.setViewPager(mFragmentViewPager); 70 | 71 | mPtrFrame = (PtrClassicFrameLayout) findViewById(R.id.view_pager_ptr_frame); 72 | mPtrFrame.disableWhenHorizontalMove(true); 73 | mPtrFrame.setPtrHandler(new PtrHandler() { 74 | @Override 75 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { 76 | return mPagerAdapter.checkCanDoRefresh(); 77 | } 78 | 79 | @Override 80 | public void onRefreshBegin(PtrFrameLayout frame) { 81 | mPagerAdapter.updateData(); 82 | } 83 | }); 84 | mFragmentViewPager.setCurrentItem(startIndex); 85 | } 86 | 87 | @Override 88 | protected void onResume() { 89 | super.onResume(); 90 | mCatTabPageIndicator.moveToItem(mFragmentViewPager.getCurrentItem()); 91 | } 92 | 93 | private void switchTo(int position) { 94 | mPagerAdapter.switchTO(position); 95 | } 96 | 97 | private class FragmentViewPagerAdapter extends FragmentStatePagerAdapter { 98 | 99 | private final ArrayList mViewPagerFragments; 100 | private ViewPagerFragment mCurrentFragment; 101 | 102 | public FragmentViewPagerAdapter(FragmentManager fm, ArrayList list) { 103 | super(fm); 104 | mViewPagerFragments = list; 105 | } 106 | 107 | @Override 108 | public Fragment getItem(int position) { 109 | return mViewPagerFragments.get(position); 110 | } 111 | 112 | @Override 113 | public void destroyItem(ViewGroup container, int position, Object object) { 114 | } 115 | 116 | protected void updateData() { 117 | final ViewPagerFragment fragment = mCurrentFragment; 118 | DemoRequestData.getImageList(new RequestFinishHandler() { 119 | @Override 120 | public void onRequestFinish(final JsonData data) { 121 | if (fragment == mCurrentFragment) { 122 | fragment.update(data); 123 | mPtrFrame.refreshComplete(); 124 | } 125 | } 126 | }); 127 | } 128 | 129 | @Override 130 | public int getCount() { 131 | return mViewPagerFragments.size(); 132 | } 133 | 134 | public void switchTO(final int position) { 135 | int len = mViewPagerFragments.size(); 136 | for (int i = 0; i < len; i++) { 137 | ViewPagerFragment fragment = mViewPagerFragments.get(i); 138 | if (i == position) { 139 | mCurrentFragment = fragment; 140 | fragment.show(); 141 | } else { 142 | fragment.hide(); 143 | } 144 | } 145 | } 146 | 147 | public boolean checkCanDoRefresh() { 148 | if (mCurrentFragment == null) { 149 | return true; 150 | } 151 | return mCurrentFragment.checkCanDoRefresh(); 152 | } 153 | 154 | public boolean checkCanDoLoadMore() { 155 | if (mCurrentFragment == null) { 156 | return true; 157 | } 158 | return mCurrentFragment.checkCanDoLoadMore(); 159 | } 160 | } 161 | 162 | private class HomeCatItemViewHolder extends TabPageIndicator.ViewHolderBase { 163 | 164 | private TextView mNameView; 165 | private View mTagView; 166 | 167 | @Override 168 | public View createView(LayoutInflater layoutInflater, int position) { 169 | View view = layoutInflater.inflate(R.layout.view_pager_indicator_item, null); 170 | view.setLayoutParams(new AbsListView.LayoutParams(LocalDisplay.dp2px(40), -1)); 171 | mNameView = (TextView) view.findViewById(R.id.view_pager_indicator_name); 172 | mTagView = view.findViewById(R.id.view_pager_indicator_tab_current); 173 | return view; 174 | } 175 | 176 | @Override 177 | public void updateView(int position, boolean isCurrent) { 178 | mNameView.setText(position + ""); 179 | if (isCurrent) { 180 | mTagView.setVisibility(View.VISIBLE); 181 | } else { 182 | mTagView.setVisibility(View.INVISIBLE); 183 | } 184 | } 185 | } 186 | } -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/indicator/PtrIndicator.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.indicator; 2 | 3 | import android.graphics.PointF; 4 | 5 | public class PtrIndicator { 6 | 7 | public final static int POS_START = 0; 8 | protected int mOffsetToRefresh = 0; 9 | protected int mOffsetToLoadMore = 0; 10 | private PointF mPtLastMove = new PointF(); 11 | private float mOffsetX; 12 | private float mOffsetY; 13 | private int mCurrentPos = 0; 14 | private int mLastPos = 0; 15 | private int mHeaderHeight; 16 | private int mFooterHeight; 17 | private int mPressedPos = 0; 18 | private boolean isHeader = true; 19 | 20 | private float mRatioOfHeaderHeightToRefresh = 1.2f; 21 | private float mResistanceHeader = 1.7f; 22 | private float mResistanceFooter = 1.7f; 23 | private boolean mIsUnderTouch = false; 24 | private int mOffsetToKeepHeaderWhileLoading = -1; 25 | // record the refresh complete position 26 | private int mRefreshCompleteY = 0; 27 | 28 | 29 | 30 | public boolean isHeader() { 31 | return isHeader; 32 | } 33 | 34 | public void setIsHeader(boolean isHeader) { 35 | this.isHeader = isHeader; 36 | } 37 | 38 | public boolean isUnderTouch() { 39 | return mIsUnderTouch; 40 | } 41 | 42 | public float getResistanceHeader() { 43 | return mResistanceHeader; 44 | } 45 | 46 | public float getResistanceFooter() { 47 | return mResistanceFooter; 48 | } 49 | 50 | public void setResistanceHeader(float resistance) { 51 | mResistanceHeader = resistance; 52 | } 53 | 54 | public void setResistanceFooter(float resistance) { 55 | mResistanceFooter = resistance; 56 | } 57 | 58 | public void onRelease() { 59 | mIsUnderTouch = false; 60 | } 61 | 62 | public void onUIRefreshComplete() { 63 | mRefreshCompleteY = mCurrentPos; 64 | } 65 | 66 | public boolean goDownCrossFinishPosition() { 67 | return mCurrentPos >= mRefreshCompleteY; 68 | } 69 | 70 | protected void processOnMove(float currentX, float currentY, float offsetX, float offsetY) { 71 | setOffset(offsetX, offsetY / mResistanceHeader); 72 | } 73 | 74 | public void setRatioOfHeaderHeightToRefresh(float ratio) { 75 | mRatioOfHeaderHeightToRefresh = ratio; 76 | mOffsetToRefresh = (int) (mHeaderHeight * ratio); 77 | mOffsetToLoadMore = (int) (mFooterHeight * ratio); 78 | } 79 | 80 | public float getRatioOfHeaderToHeightRefresh() { 81 | return mRatioOfHeaderHeightToRefresh; 82 | } 83 | 84 | public int getOffsetToRefresh() { 85 | return mOffsetToRefresh; 86 | } 87 | 88 | public int getOffsetToLoadMore() { 89 | return mOffsetToLoadMore; 90 | } 91 | 92 | public void setOffsetToRefresh(int offset) { 93 | mRatioOfHeaderHeightToRefresh = mHeaderHeight * 1f / offset; 94 | mOffsetToRefresh = offset; 95 | mOffsetToLoadMore = offset; 96 | } 97 | 98 | public void onPressDown(float x, float y) { 99 | mIsUnderTouch = true; 100 | mPressedPos = mCurrentPos; 101 | mPtLastMove.set(x, y); 102 | } 103 | 104 | public final void onMove(float x, float y) { 105 | float offsetX = x - mPtLastMove.x; 106 | float offsetY = (y - mPtLastMove.y); 107 | processOnMove(x, y, offsetX, offsetY); 108 | mPtLastMove.set(x, y); 109 | } 110 | 111 | protected void setOffset(float x, float y) { 112 | mOffsetX = x; 113 | mOffsetY = y; 114 | } 115 | 116 | public float getOffsetX() { 117 | return mOffsetX; 118 | } 119 | 120 | public float getOffsetY() { 121 | return mOffsetY; 122 | } 123 | 124 | public int getLastPosY() { 125 | return mLastPos; 126 | } 127 | 128 | public int getCurrentPosY() { 129 | return mCurrentPos; 130 | } 131 | 132 | /** 133 | * Update current position before update the UI 134 | */ 135 | public final void setCurrentPos(int current) { 136 | mLastPos = mCurrentPos; 137 | mCurrentPos = current; 138 | onUpdatePos(current, mLastPos); 139 | } 140 | 141 | protected void onUpdatePos(int current, int last) { 142 | 143 | } 144 | 145 | public int getHeaderHeight() { 146 | return mHeaderHeight; 147 | } 148 | 149 | public void setHeaderHeight(int height) { 150 | mHeaderHeight = height; 151 | updateHeight(); 152 | } 153 | 154 | public void setFooterHeight(int height) { 155 | mFooterHeight = height; 156 | updateHeight(); 157 | } 158 | 159 | protected void updateHeight() { 160 | mOffsetToRefresh = (int) (mRatioOfHeaderHeightToRefresh * mHeaderHeight); 161 | mOffsetToLoadMore = (int) (mRatioOfHeaderHeightToRefresh * mFooterHeight); 162 | } 163 | 164 | public void convertFrom(PtrIndicator ptrSlider) { 165 | mCurrentPos = ptrSlider.mCurrentPos; 166 | mLastPos = ptrSlider.mLastPos; 167 | mHeaderHeight = ptrSlider.mHeaderHeight; 168 | } 169 | 170 | public boolean hasLeftStartPosition() { 171 | return mCurrentPos > POS_START; 172 | } 173 | 174 | public boolean hasJustLeftStartPosition() { 175 | return mLastPos == POS_START && hasLeftStartPosition(); 176 | } 177 | 178 | public boolean hasJustBackToStartPosition() { 179 | return mLastPos != POS_START && isInStartPosition(); 180 | } 181 | 182 | public boolean isOverOffsetToRefresh() { 183 | return mCurrentPos >= getOffsetToRefresh(); 184 | } 185 | 186 | public boolean hasMovedAfterPressedDown() { 187 | return mCurrentPos != mPressedPos; 188 | } 189 | 190 | public boolean isInStartPosition() { 191 | return mCurrentPos == POS_START; 192 | } 193 | 194 | public boolean crossRefreshLineFromTopToBottom() { 195 | return mLastPos < getOffsetToRefresh() && mCurrentPos >= getOffsetToRefresh(); 196 | } 197 | 198 | public boolean hasJustReachedHeaderHeightFromTopToBottom() { 199 | return mLastPos < mHeaderHeight && mCurrentPos >= mHeaderHeight; 200 | } 201 | 202 | public boolean isOverOffsetToKeepHeaderWhileLoading() { 203 | return mCurrentPos > getOffsetToKeepHeaderWhileLoading(); 204 | } 205 | 206 | public void setOffsetToKeepHeaderWhileLoading(int offset) { 207 | mOffsetToKeepHeaderWhileLoading = offset; 208 | } 209 | 210 | public int getOffsetToKeepHeaderWhileLoading() { 211 | if(isHeader) { 212 | return mOffsetToKeepHeaderWhileLoading >= 0 ? mOffsetToKeepHeaderWhileLoading : mHeaderHeight; 213 | }else{ 214 | return mOffsetToKeepHeaderWhileLoading >= 0 ? mOffsetToKeepHeaderWhileLoading : mFooterHeight; 215 | } 216 | } 217 | 218 | public boolean isAlreadyHere(int to) { 219 | return mCurrentPos == to; 220 | } 221 | 222 | public float getLastPercent() { 223 | final float oldPercent = mHeaderHeight == 0 ? 0 : mLastPos * 1f / mHeaderHeight; 224 | return oldPercent; 225 | } 226 | 227 | public float getCurrentPercent() { 228 | final float currentPercent = mHeaderHeight == 0 ? 0 : mCurrentPos * 1f / mHeaderHeight; 229 | return currentPercent; 230 | } 231 | 232 | public boolean willOverTop(int to) { 233 | return to < POS_START; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /ptr-lib/src/main/java/in/srain/cube/views/ptr/util/PtrCLog.java: -------------------------------------------------------------------------------- 1 | package in.srain.cube.views.ptr.util; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * An encapsulation of {@link Log}, enable log level and print log with parameters. 7 | * 8 | * @author http://www.liaohuqiu.net/ 9 | */ 10 | public class PtrCLog { 11 | 12 | public static final int LEVEL_VERBOSE = 0; 13 | public static final int LEVEL_DEBUG = 1; 14 | public static final int LEVEL_INFO = 2; 15 | public static final int LEVEL_WARNING = 3; 16 | public static final int LEVEL_ERROR = 4; 17 | public static final int LEVEL_FATAL = 5; 18 | 19 | private static int sLevel = LEVEL_VERBOSE; 20 | 21 | /** 22 | * set log level, the level lower than this level will not be logged 23 | * 24 | * @param level 25 | */ 26 | public static void setLogLevel(int level) { 27 | sLevel = level; 28 | } 29 | 30 | /** 31 | * Send a VERBOSE log message. 32 | * 33 | * @param tag 34 | * @param msg 35 | */ 36 | public static void v(String tag, String msg) { 37 | if (sLevel > LEVEL_VERBOSE) { 38 | return; 39 | } 40 | Log.v(tag, msg); 41 | } 42 | 43 | /** 44 | * Send a VERBOSE log message. 45 | * 46 | * @param tag 47 | * @param msg 48 | * @param throwable 49 | */ 50 | public static void v(String tag, String msg, Throwable throwable) { 51 | if (sLevel > LEVEL_VERBOSE) { 52 | return; 53 | } 54 | Log.v(tag, msg, throwable); 55 | } 56 | 57 | /** 58 | * Send a VERBOSE log message. 59 | * 60 | * @param tag 61 | * @param msg 62 | * @param args 63 | */ 64 | public static void v(String tag, String msg, Object... args) { 65 | if (sLevel > LEVEL_VERBOSE) { 66 | return; 67 | } 68 | if (args.length > 0) { 69 | msg = String.format(msg, args); 70 | } 71 | Log.v(tag, msg); 72 | } 73 | 74 | /** 75 | * Send a DEBUG log message 76 | * 77 | * @param tag 78 | * @param msg 79 | */ 80 | public static void d(String tag, String msg) { 81 | if (sLevel > LEVEL_DEBUG) { 82 | return; 83 | } 84 | Log.d(tag, msg); 85 | } 86 | 87 | /** 88 | * Send a DEBUG log message 89 | * 90 | * @param tag 91 | * @param msg 92 | * @param args 93 | */ 94 | public static void d(String tag, String msg, Object... args) { 95 | if (sLevel > LEVEL_DEBUG) { 96 | return; 97 | } 98 | if (args.length > 0) { 99 | msg = String.format(msg, args); 100 | } 101 | Log.d(tag, msg); 102 | } 103 | 104 | /** 105 | * Send a DEBUG log message 106 | * 107 | * @param tag 108 | * @param msg 109 | * @param throwable 110 | */ 111 | public static void d(String tag, String msg, Throwable throwable) { 112 | if (sLevel > LEVEL_DEBUG) { 113 | return; 114 | } 115 | Log.d(tag, msg, throwable); 116 | } 117 | 118 | /** 119 | * Send an INFO log message 120 | * 121 | * @param tag 122 | * @param msg 123 | */ 124 | public static void i(String tag, String msg) { 125 | if (sLevel > LEVEL_INFO) { 126 | return; 127 | } 128 | Log.i(tag, msg); 129 | } 130 | 131 | /** 132 | * Send an INFO log message 133 | * 134 | * @param tag 135 | * @param msg 136 | * @param args 137 | */ 138 | public static void i(String tag, String msg, Object... args) { 139 | if (sLevel > LEVEL_INFO) { 140 | return; 141 | } 142 | if (args.length > 0) { 143 | msg = String.format(msg, args); 144 | } 145 | Log.i(tag, msg); 146 | } 147 | 148 | /** 149 | * Send an INFO log message 150 | * 151 | * @param tag 152 | * @param msg 153 | */ 154 | public static void i(String tag, String msg, Throwable throwable) { 155 | if (sLevel > LEVEL_INFO) { 156 | return; 157 | } 158 | Log.i(tag, msg, throwable); 159 | } 160 | 161 | /** 162 | * Send a WARNING log message 163 | * 164 | * @param tag 165 | * @param msg 166 | */ 167 | public static void w(String tag, String msg) { 168 | if (sLevel > LEVEL_WARNING) { 169 | return; 170 | } 171 | Log.w(tag, msg); 172 | } 173 | 174 | /** 175 | * Send a WARNING log message 176 | * 177 | * @param tag 178 | * @param msg 179 | * @param args 180 | */ 181 | public static void w(String tag, String msg, Object... args) { 182 | if (sLevel > LEVEL_WARNING) { 183 | return; 184 | } 185 | if (args.length > 0) { 186 | msg = String.format(msg, args); 187 | } 188 | Log.w(tag, msg); 189 | } 190 | 191 | /** 192 | * Send a WARNING log message 193 | * 194 | * @param tag 195 | * @param msg 196 | * @param throwable 197 | */ 198 | public static void w(String tag, String msg, Throwable throwable) { 199 | if (sLevel > LEVEL_WARNING) { 200 | return; 201 | } 202 | Log.w(tag, msg, throwable); 203 | } 204 | 205 | /** 206 | * Send an ERROR log message 207 | * 208 | * @param tag 209 | * @param msg 210 | */ 211 | public static void e(String tag, String msg) { 212 | if (sLevel > LEVEL_ERROR) { 213 | return; 214 | } 215 | Log.e(tag, msg); 216 | } 217 | 218 | /** 219 | * Send an ERROR log message 220 | * 221 | * @param tag 222 | * @param msg 223 | * @param args 224 | */ 225 | public static void e(String tag, String msg, Object... args) { 226 | if (sLevel > LEVEL_ERROR) { 227 | return; 228 | } 229 | if (args.length > 0) { 230 | msg = String.format(msg, args); 231 | } 232 | Log.e(tag, msg); 233 | } 234 | 235 | /** 236 | * Send an ERROR log message 237 | * 238 | * @param tag 239 | * @param msg 240 | * @param throwable 241 | */ 242 | public static void e(String tag, String msg, Throwable throwable) { 243 | if (sLevel > LEVEL_ERROR) { 244 | return; 245 | } 246 | Log.e(tag, msg, throwable); 247 | } 248 | 249 | /** 250 | * Send a FATAL ERROR log message 251 | * 252 | * @param tag 253 | * @param msg 254 | */ 255 | public static void f(String tag, String msg) { 256 | if (sLevel > LEVEL_FATAL) { 257 | return; 258 | } 259 | Log.wtf(tag, msg); 260 | } 261 | 262 | /** 263 | * Send a FATAL ERROR log message 264 | * 265 | * @param tag 266 | * @param msg 267 | * @param args 268 | */ 269 | public static void f(String tag, String msg, Object... args) { 270 | if (sLevel > LEVEL_FATAL) { 271 | return; 272 | } 273 | if (args.length > 0) { 274 | msg = String.format(msg, args); 275 | } 276 | Log.wtf(tag, msg); 277 | } 278 | 279 | /** 280 | * Send a FATAL ERROR log message 281 | * 282 | * @param tag 283 | * @param msg 284 | * @param throwable 285 | */ 286 | public static void f(String tag, String msg, Throwable throwable) { 287 | if (sLevel > LEVEL_FATAL) { 288 | return; 289 | } 290 | Log.wtf(tag, msg, throwable); 291 | } 292 | } 293 | --------------------------------------------------------------------------------