1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-27 11:42:16 -05:00

Update Android-PullToRefresh to v2.1.1

This commit is contained in:
cketti 2013-01-03 14:40:52 +01:00
parent 1767c3428e
commit 186379cbd0
97 changed files with 3421 additions and 1217 deletions

View File

@ -9,7 +9,14 @@ This project aims to provide a reusable Pull to Refresh widget for Android. It w
* Supports both Pulling Down from the top, and Pulling Up from the bottom (or even both). * Supports both Pulling Down from the top, and Pulling Up from the bottom (or even both).
* Animated Scrolling for all devices. * Animated Scrolling for all devices.
* Over Scroll supports for devices on Android v2.3+. * Over Scroll supports for devices on Android v2.3+.
* Currently works with **ListView**, **ExpandableListView** & **GridView**, **WebView** and **ScrollView**! * Currently works with:
* **ListView**
* **ExpandableListView**
* **GridView**
* **WebView**
* **ScrollView**
* **HorizontalScrollView**
* **ViewPager**
* Integrated End of List Listener for use of detecting when the user has scrolled to the bottom. * Integrated End of List Listener for use of detecting when the user has scrolled to the bottom.
* Maven Support. * Maven Support.
* Indicators to show the user when a Pull-to-Refresh is available. * Indicators to show the user when a Pull-to-Refresh is available.

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.handmark.pulltorefresh.extras.listfragment" package="com.handmark.pulltorefresh.extras.listfragment"
android:versionCode="1420" android:versionCode="2110"
android:versionName="1.4.2" > android:versionName="2.1.1" >
<application /> <application />

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -10,7 +10,7 @@
<parent> <parent>
<groupId>com.github.chrisbanes.pulltorefresh</groupId> <groupId>com.github.chrisbanes.pulltorefresh</groupId>
<artifactId>extras</artifactId> <artifactId>extras</artifactId>
<version>1.4.2</version> <version>2.1.1</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@ -0,0 +1,68 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.extras.listfragment;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ListView;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
abstract class PullToRefreshBaseListFragment<T extends PullToRefreshBase<? extends AbsListView>> extends ListFragment {
private T mPullToRefreshListView;
@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = super.onCreateView(inflater, container, savedInstanceState);
ListView lv = (ListView) layout.findViewById(android.R.id.list);
ViewGroup parent = (ViewGroup) lv.getParent();
// Remove ListView and add PullToRefreshListView in its place
int lvIndex = parent.indexOfChild(lv);
parent.removeViewAt(lvIndex);
mPullToRefreshListView = onCreatePullToRefreshListView(inflater, savedInstanceState);
parent.addView(mPullToRefreshListView, lvIndex, lv.getLayoutParams());
return layout;
}
/**
* @return The {@link PullToRefreshBase} attached to this ListFragment.
*/
public final T getPullToRefreshListView() {
return mPullToRefreshListView;
}
/**
* Returns the {@link PullToRefreshBase} which will replace the ListView
* created from ListFragment. You should override this method if you wish to
* customise the {@link PullToRefreshBase} from the default.
*
* @param inflater - LayoutInflater which can be used to inflate from XML.
* @param savedInstanceState - Bundle passed through from
* {@link ListFragment#onCreateView(LayoutInflater, ViewGroup, Bundle)
* onCreateView(...)}
* @return The {@link PullToRefreshBase} which will replace the ListView.
*/
protected abstract T onCreatePullToRefreshListView(LayoutInflater inflater, Bundle savedInstanceState);
}

View File

@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.extras.listfragment;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import com.handmark.pulltorefresh.library.PullToRefreshExpandableListView;
/**
* A sample implementation of how to use {@link PullToRefreshExpandableListView}
* with {@link ListFragment}. This implementation simply replaces the ListView
* that {@code ListFragment} creates with a new
* {@code PullToRefreshExpandableListView}. This means that ListFragment still
* works 100% (e.g. <code>setListShown(...)</code> ).
* <p/>
* The new PullToRefreshListView is created in the method
* {@link #onCreatePullToRefreshListView(LayoutInflater, Bundle)}. If you wish
* to customise the {@code PullToRefreshExpandableListView} then override this
* method and return your customised instance.
*
* @author Chris Banes
*
*/
public class PullToRefreshExpandableListFragment extends PullToRefreshBaseListFragment<PullToRefreshExpandableListView> {
protected PullToRefreshExpandableListView onCreatePullToRefreshListView(LayoutInflater inflater,
Bundle savedInstanceState) {
return new PullToRefreshExpandableListView(getActivity());
}
}

View File

@ -18,66 +18,25 @@ package com.handmark.pulltorefresh.extras.listfragment;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.ListFragment; import android.support.v4.app.ListFragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import com.handmark.pulltorefresh.library.PullToRefreshListView; import com.handmark.pulltorefresh.library.PullToRefreshListView;
/** /**
* A sample implementation of how to the PullToRefreshListView with * A sample implementation of how to use {@link PullToRefreshListView} with
* ListFragment. This implementation simply replaces the ListView that * {@link ListFragment}. This implementation simply replaces the ListView that
* ListFragment creates with a new PullToRefreshListView. This means that * {@code ListFragment} creates with a new PullToRefreshListView. This means
* ListFragment still works 100% (e.g. <code>setListShown(...)</code>). * that ListFragment still works 100% (e.g. <code>setListShown(...)</code> ).
* * <p/>
* The new PullToRefreshListView is created in the method * The new PullToRefreshListView is created in the method
* <code>onCreatePullToRefreshListView()</code>. If you wish to customise the * {@link #onCreatePullToRefreshListView(LayoutInflater, Bundle)}. If you wish
* PullToRefreshListView then override this method and return your customised * to customise the {@code PullToRefreshListView} then override this method and
* instance. * return your customised instance.
* *
* @author Chris Banes * @author Chris Banes
* *
*/ */
public class PullToRefreshListFragment extends ListFragment { public class PullToRefreshListFragment extends PullToRefreshBaseListFragment<PullToRefreshListView> {
private PullToRefreshListView mPullToRefreshListView;
@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = super.onCreateView(inflater, container, savedInstanceState);
ListView lv = (ListView) layout.findViewById(android.R.id.list);
ViewGroup parent = (ViewGroup) lv.getParent();
//Remove ListView and add PullToRefreshListView in its place
int lvIndex = parent.indexOfChild(lv);
parent.removeViewAt(lvIndex);
mPullToRefreshListView = onCreatePullToRefreshListView(inflater, savedInstanceState);
parent.addView(mPullToRefreshListView, lvIndex, lv.getLayoutParams());
return layout;
}
/**
* @return The {@link PullToRefreshListView} attached to this ListFragment.
*/
public final PullToRefreshListView getPullToRefreshListView() {
return mPullToRefreshListView;
}
/**
* Returns the {@link PullToRefreshListView} which will replace the ListView
* created from ListFragment. You should override this method if you wish to
* customise the {@link PullToRefreshListView} from the default.
*
* @param inflater
* - LayoutInflater which can be used to inflate from XML.
* @param savedInstanceState
* - Bundle passed through from
* {@link ListFragment#onCreateView(LayoutInflater, ViewGroup, Bundle)
* onCreateView(...)}
* @return The {@link PullToRefreshListView} which will replace the
* ListView.
*/
protected PullToRefreshListView onCreatePullToRefreshListView(LayoutInflater inflater, Bundle savedInstanceState) { protected PullToRefreshListView onCreatePullToRefreshListView(LayoutInflater inflater, Bundle savedInstanceState) {
return new PullToRefreshListView(getActivity()); return new PullToRefreshListView(getActivity());
} }

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.handmark.pulltorefresh.extras.viewpager"
android:versionCode="2110"
android:versionName="2.1.1" >
<uses-sdk android:minSdkVersion="4" />
<application />
</manifest>

View File

@ -0,0 +1,17 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked into Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.chrisbanes.pulltorefresh</groupId>
<artifactId>extra-viewpager</artifactId>
<packaging>apklib</packaging>
<name>Android-PullToRefresh Extras: ViewPager</name>
<parent>
<groupId>com.github.chrisbanes.pulltorefresh</groupId>
<artifactId>extras</artifactId>
<version>2.1.1</version>
</parent>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
</dependency>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>support-v4</artifactId>
<version>r7</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>library</artifactId>
<type>apklib</type>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,16 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
android.library=true
# Project target.
target=android-16
android.library.reference.1=../../library

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- Need this for Maven, otherwise it doesn't build. I hate Maven. -->
</LinearLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="viewpager" />
</resources>

View File

@ -0,0 +1,70 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.extras.viewpager;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
public class PullToRefreshViewPager extends PullToRefreshBase<ViewPager> {
public PullToRefreshViewPager(Context context) {
super(context);
}
public PullToRefreshViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public final Orientation getPullToRefreshScrollDirection() {
return Orientation.HORIZONTAL;
}
@Override
protected ViewPager createRefreshableView(Context context, AttributeSet attrs) {
ViewPager viewPager = new ViewPager(context, attrs);
viewPager.setId(R.id.viewpager);
return viewPager;
}
@Override
protected boolean isReadyForPullStart() {
ViewPager refreshableView = getRefreshableView();
PagerAdapter adapter = refreshableView.getAdapter();
if (null != adapter) {
return refreshableView.getCurrentItem() == 0;
}
return false;
}
@Override
protected boolean isReadyForPullEnd() {
ViewPager refreshableView = getRefreshableView();
PagerAdapter adapter = refreshableView.getAdapter();
if (null != adapter) {
return refreshableView.getCurrentItem() == adapter.getCount() - 1;
}
return false;
}
}

View File

@ -10,10 +10,11 @@
<parent> <parent>
<groupId>com.github.chrisbanes.pulltorefresh</groupId> <groupId>com.github.chrisbanes.pulltorefresh</groupId>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<version>1.4.2</version> <version>2.1.1</version>
</parent> </parent>
<modules> <modules>
<module>PullToRefreshListFragment</module> <module>PullToRefreshListFragment</module>
<module>PullToRefreshViewPager</module>
</modules> </modules>
</project> </project>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.handmark.pulltorefresh.library" package="com.handmark.pulltorefresh.library"
android:versionCode="1420" android:versionCode="2110"
android:versionName="1.4.2" > android:versionName="2.1.1" >
<uses-sdk android:minSdkVersion="4" /> <uses-sdk android:minSdkVersion="4" />

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -10,7 +10,7 @@
<parent> <parent>
<groupId>com.github.chrisbanes.pulltorefresh</groupId> <groupId>com.github.chrisbanes.pulltorefresh</groupId>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<version>1.4.2</version> <version>2.1.1</version>
</parent> </parent>
<dependencies> <dependencies>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/header_footer_internal_padding" >
<ImageView
android:id="@+id/pull_to_refresh_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/pull_to_refresh_progress"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
<TextView
android:id="@+id/pull_to_refresh_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold" />
<TextView
android:id="@+id/pull_to_refresh_sub_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="gone" />
</LinearLayout>
</merge>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<FrameLayout
android:id="@+id/fl_inner"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingBottom="@dimen/header_footer_top_bottom_padding"
android:paddingLeft="@dimen/header_footer_left_right_padding"
android:paddingRight="@dimen/header_footer_left_right_padding"
android:paddingTop="@dimen/header_footer_top_bottom_padding" >
<ImageView
android:id="@+id/pull_to_refresh_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<ProgressBar
android:id="@+id/pull_to_refresh_progress"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone" />
</FrameLayout>
</merge>

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<FrameLayout
android:id="@+id/fl_inner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/header_footer_top_bottom_padding"
android:paddingLeft="@dimen/header_footer_left_right_padding"
android:paddingRight="@dimen/header_footer_left_right_padding"
android:paddingTop="@dimen/header_footer_top_bottom_padding" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|center_vertical" >
<ImageView
android:id="@+id/pull_to_refresh_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<ProgressBar
android:id="@+id/pull_to_refresh_progress"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:orientation="vertical" >
<TextView
android:id="@+id/pull_to_refresh_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearance"
android:textStyle="bold" />
<TextView
android:id="@+id/pull_to_refresh_sub_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="gone" />
</LinearLayout>
</FrameLayout>
</merge>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pull_to_refresh_pull_label">اسحب للتحديث…</string>
<string name="pull_to_refresh_release_label">اترك للتحديث…</string>
<string name="pull_to_refresh_refreshing_label">تحميل…</string>
</resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Tažením aktualizujete&#8230;</string> <string name="pull_to_refresh_pull_label">Tažením aktualizujete</string>
<string name="pull_to_refresh_release_label">Uvolněním aktualizujete&#8230;</string> <string name="pull_to_refresh_release_label">Uvolněním aktualizujete</string>
<string name="pull_to_refresh_refreshing_label">Načítání&#8230;</string> <string name="pull_to_refresh_refreshing_label">Načítání</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Ziehen zum Aktualisieren&#8230;</string> <string name="pull_to_refresh_pull_label">Ziehen zum Aktualisieren</string>
<string name="pull_to_refresh_release_label">Loslassen zum Aktualisieren&#8230;</string> <string name="pull_to_refresh_release_label">Loslassen zum Aktualisieren</string>
<string name="pull_to_refresh_refreshing_label">Laden&#8230;</string> <string name="pull_to_refresh_refreshing_label">Laden</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Tire para actualizar&#8230;</string> <string name="pull_to_refresh_pull_label">Tirar para actualizar…</string>
<string name="pull_to_refresh_release_label">Deslice para actualizar&#8230;</string> <string name="pull_to_refresh_release_label">Soltar para actualizar…</string>
<string name="pull_to_refresh_refreshing_label">Cargando&#8230;</string> <string name="pull_to_refresh_refreshing_label">Cargando</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Tirez pour rafraîchir&#8230;</string> <string name="pull_to_refresh_pull_label">Tirez pour rafraîchir</string>
<string name="pull_to_refresh_release_label">Relâcher pour rafraîchir&#8230;</string> <string name="pull_to_refresh_release_label">Relâcher pour rafraîchir</string>
<string name="pull_to_refresh_refreshing_label">Chargement&#8230;</string> <string name="pull_to_refresh_refreshing_label">Chargement</string>
</resources> </resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pull_to_refresh_pull_label">משוך לרענון…</string>
<string name="pull_to_refresh_release_label">שחרר לרענון…</string>
<string name="pull_to_refresh_refreshing_label">טוען…</string>
</resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Tira per aggiornare&#8230;</string> <string name="pull_to_refresh_pull_label">Tira per aggiornare</string>
<string name="pull_to_refresh_release_label">Rilascia per aggionare&#8230;</string> <string name="pull_to_refresh_release_label">Rilascia per aggionare</string>
<string name="pull_to_refresh_refreshing_label">Caricamento&#8230;</string> <string name="pull_to_refresh_refreshing_label">Caricamento</string>
</resources> </resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pull_to_refresh_pull_label">משוך לרענון…</string>
<string name="pull_to_refresh_release_label">שחרר לרענון…</string>
<string name="pull_to_refresh_refreshing_label">טוען…</string>
</resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">画面を引っ張って&#8230;</string> <string name="pull_to_refresh_pull_label">画面を引っ張って</string>
<string name="pull_to_refresh_release_label">指を離すと更新&#8230;</string> <string name="pull_to_refresh_release_label">指を離して更新…</string>
<string name="pull_to_refresh_refreshing_label">読み込み中&#8230;</string> <string name="pull_to_refresh_refreshing_label">読み込み中</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">당겨서 새로 고침&#8230;</string> <string name="pull_to_refresh_pull_label">당겨서 새로 고침</string>
<string name="pull_to_refresh_release_label">놓아서 새로 고침&#8230;</string> <string name="pull_to_refresh_release_label">놓아서 새로 고침</string>
<string name="pull_to_refresh_refreshing_label">딩 중&#8230;</string> <string name="pull_to_refresh_refreshing_label">드 중…</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Sleep om te vernieuwen&#8230;</string> <string name="pull_to_refresh_pull_label">Sleep om te vernieuwen</string>
<string name="pull_to_refresh_release_label">Loslaten om te vernieuwen&#8230;</string> <string name="pull_to_refresh_release_label">Loslaten om te vernieuwen</string>
<string name="pull_to_refresh_refreshing_label">Laden&#8230;</string> <string name="pull_to_refresh_refreshing_label">Laden</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Pociągnij, aby odświeżyć&#8230;</string> <string name="pull_to_refresh_pull_label">Pociągnij, aby odświeżyć</string>
<string name="pull_to_refresh_release_label">Puść, aby odświeżyć&#8230;</string> <string name="pull_to_refresh_release_label">Puść, aby odświeżyć</string>
<string name="pull_to_refresh_refreshing_label">Trwa ładowanie&#8230;</string> <string name="pull_to_refresh_refreshing_label">Wczytywanie…</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Puxe para atualizar&#8230;</string> <string name="pull_to_refresh_pull_label">Puxe para atualizar</string>
<string name="pull_to_refresh_release_label">Libere para atualizar&#8230;</string> <string name="pull_to_refresh_release_label">Libere para atualizar</string>
<string name="pull_to_refresh_refreshing_label">Carregando&#8230;</string> <string name="pull_to_refresh_refreshing_label">Carregando</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Puxe para atualizar&#8230;</string> <string name="pull_to_refresh_pull_label">Puxe para atualizar</string>
<string name="pull_to_refresh_release_label">Liberação para atualizar&#8230;</string> <string name="pull_to_refresh_release_label">Liberação para atualizar</string>
<string name="pull_to_refresh_refreshing_label">A carregar&#8230;</string> <string name="pull_to_refresh_refreshing_label">A carregar</string>
</resources> </resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pull_to_refresh_pull_label">Trage pentru a reîmprospăta…</string>
<string name="pull_to_refresh_release_label">Eliberează pentru a reîmprospăta…</string>
<string name="pull_to_refresh_refreshing_label">Încărcare…</string>
</resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Потяните для обновления&#8230;</string> <string name="pull_to_refresh_pull_label">Потяните для обновления</string>
<string name="pull_to_refresh_release_label">Отпустите для обновления&#8230;</string> <string name="pull_to_refresh_release_label">Отпустите для обновления</string>
<string name="pull_to_refresh_refreshing_label">Загрузка&#8230;</string> <string name="pull_to_refresh_refreshing_label">Загрузка</string>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">下拉刷新&#8230;</string> <string name="pull_to_refresh_pull_label">下拉刷新</string>
<string name="pull_to_refresh_release_label">松手刷新&#8230;</string> <string name="pull_to_refresh_release_label">放开以刷新…</string>
<string name="pull_to_refresh_refreshing_label">载入中&#8230;</string> <string name="pull_to_refresh_refreshing_label">正在载入…</string>
</resources> </resources>

View File

@ -2,27 +2,79 @@
<resources> <resources>
<declare-styleable name="PullToRefresh"> <declare-styleable name="PullToRefresh">
<attr name="ptrAdapterViewBackground" format="reference|color" />
<!-- A drawable to use as the background of the Refreshable View -->
<attr name="ptrRefreshableViewBackground" format="reference|color" />
<!-- A drawable to use as the background of the Header and Footer Loading Views -->
<attr name="ptrHeaderBackground" format="reference|color" /> <attr name="ptrHeaderBackground" format="reference|color" />
<!-- Text Color of the Header and Footer Loading Views -->
<attr name="ptrHeaderTextColor" format="reference|color" /> <attr name="ptrHeaderTextColor" format="reference|color" />
<!-- Text Color of the Header and Footer Loading Views Sub Header -->
<attr name="ptrHeaderSubTextColor" format="reference|color" /> <attr name="ptrHeaderSubTextColor" format="reference|color" />
<!-- Mode of Pull-to-Refresh that should be used -->
<attr name="ptrMode"> <attr name="ptrMode">
<flag name="disabled" value="0x0" /> <flag name="disabled" value="0x0" />
<flag name="pullFromStart" value="0x1" />
<flag name="pullFromEnd" value="0x2" />
<flag name="both" value="0x3" />
<flag name="manualOnly" value="0x4" />
<!-- These last two are depreacted -->
<flag name="pullDownFromTop" value="0x1" /> <flag name="pullDownFromTop" value="0x1" />
<flag name="pullUpFromBottom" value="0x2" /> <flag name="pullUpFromBottom" value="0x2" />
<flag name="both" value="0x3" />
</attr> </attr>
<!-- Whether the Indicator overlay(s) should be used -->
<attr name="ptrShowIndicator" format="reference|boolean" /> <attr name="ptrShowIndicator" format="reference|boolean" />
<!-- Drawable to use as Loading Indicator. Changes both Header and Footer. -->
<attr name="ptrDrawable" format="reference" /> <attr name="ptrDrawable" format="reference" />
<attr name="ptrDrawableTop" format="reference" />
<attr name="ptrDrawableBottom" format="reference" /> <!-- Drawable to use as Loading Indicator in the Header View. Overrides value set in ptrDrawable. -->
<attr name="ptrDrawableStart" format="reference" />
<!-- Drawable to use as Loading Indicator in the Footer View. Overrides value set in ptrDrawable. -->
<attr name="ptrDrawableEnd" format="reference" />
<!-- Whether Android's built-in Over Scroll should be utilised for Pull-to-Refresh. -->
<attr name="ptrOverScroll" format="reference|boolean" /> <attr name="ptrOverScroll" format="reference|boolean" />
<!-- Base text color, typeface, size, and style for Header and Footer Loading Views -->
<attr name="ptrHeaderTextAppearance" format="reference" /> <attr name="ptrHeaderTextAppearance" format="reference" />
<!-- Base text color, typeface, size, and style for Header and Footer Loading Views Sub Header -->
<attr name="ptrSubHeaderTextAppearance" format="reference" /> <attr name="ptrSubHeaderTextAppearance" format="reference" />
<!-- Style of Animation should be used displayed when pulling. -->
<attr name="ptrAnimationStyle"> <attr name="ptrAnimationStyle">
<flag name="rotate" value="0x0" /> <flag name="rotate" value="0x0" />
<flag name="flip" value="0x1" /> <flag name="flip" value="0x1" />
</attr> </attr>
<!-- Whether the user can scroll while the View is Refreshing -->
<attr name="ptrScrollingWhileRefreshingEnabled" format="reference|boolean" />
<!--
Whether PullToRefreshListView has it's extras enabled. This allows the user to be
able to scroll while refreshing, and behaves better. It acheives this by adding
Header and/or Footer Views to the ListView.
-->
<attr name="ptrListViewExtrasEnabled" format="reference|boolean" />
<!--
Whether the Drawable should be continually rotated as you pull. This only
takes effect when using the 'Rotate' Animation Style.
-->
<attr name="ptrRotateDrawableWhilePulling" format="reference|boolean" />
<!-- BELOW HERE ARE DEPRECEATED. DO NOT USE. -->
<attr name="ptrAdapterViewBackground" format="reference|color" />
<attr name="ptrDrawableTop" format="reference" />
<attr name="ptrDrawableBottom" format="reference" />
</declare-styleable> </declare-styleable>
</resources> </resources>

View File

@ -4,8 +4,7 @@
<dimen name="indicator_right_padding">10dp</dimen> <dimen name="indicator_right_padding">10dp</dimen>
<dimen name="indicator_corner_radius">12dp</dimen> <dimen name="indicator_corner_radius">12dp</dimen>
<dimen name="indicator_internal_padding">4dp</dimen> <dimen name="indicator_internal_padding">4dp</dimen>
<dimen name="header_footer_left_right_padding">25dp</dimen> <dimen name="header_footer_left_right_padding">24dp</dimen>
<dimen name="header_footer_top_bottom_padding">10dp</dimen> <dimen name="header_footer_top_bottom_padding">12dp</dimen>
<dimen name="header_footer_internal_padding">20dp</dimen>
</resources> </resources>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pull_to_refresh_pull_label">Pull to refresh&#8230;</string> <string name="pull_to_refresh_pull_label">Pull to refresh</string>
<string name="pull_to_refresh_release_label">Release to refresh&#8230;</string> <string name="pull_to_refresh_release_label">Release to refresh</string>
<string name="pull_to_refresh_refreshing_label">Loading&#8230;</string> <string name="pull_to_refresh_refreshing_label">Loading</string>
<!-- Just use standard Pull Down String when pulling up. These can be set for languages which require it --> <!-- Just use standard Pull Down String when pulling up. These can be set for languages which require it -->
<string name="pull_to_refresh_from_bottom_pull_label">@string/pull_to_refresh_pull_label</string> <string name="pull_to_refresh_from_bottom_pull_label">@string/pull_to_refresh_pull_label</string>

View File

@ -0,0 +1,57 @@
package com.handmark.pulltorefresh.library;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
public interface ILoadingLayout {
/**
* Set the Last Updated Text. This displayed under the main label when
* Pulling
*
* @param label - Label to set
*/
public void setLastUpdatedLabel(CharSequence label);
/**
* Set the drawable used in the loading layout. This is the same as calling
* <code>setLoadingDrawable(drawable, Mode.BOTH)</code>
*
* @param drawable - Drawable to display
*/
public void setLoadingDrawable(Drawable drawable);
/**
* Set Text to show when the Widget is being Pulled
* <code>setPullLabel(releaseLabel, Mode.BOTH)</code>
*
* @param pullLabel - CharSequence to display
*/
public void setPullLabel(CharSequence pullLabel);
/**
* Set Text to show when the Widget is refreshing
* <code>setRefreshingLabel(releaseLabel, Mode.BOTH)</code>
*
* @param refreshingLabel - CharSequence to display
*/
public void setRefreshingLabel(CharSequence refreshingLabel);
/**
* Set Text to show when the Widget is being pulled, and will refresh when
* released. This is the same as calling
* <code>setReleaseLabel(releaseLabel, Mode.BOTH)</code>
*
* @param releaseLabel - CharSequence to display
*/
public void setReleaseLabel(CharSequence releaseLabel);
/**
* Set's the Sets the typeface and style in which the text should be
* displayed. Please see
* {@link android.widget.TextView#setTypeface(Typeface)
* TextView#setTypeface(Typeface)}.
*/
public void setTextTypeface(Typeface tf);
}

View File

@ -15,7 +15,6 @@
*******************************************************************************/ *******************************************************************************/
package com.handmark.pulltorefresh.library; package com.handmark.pulltorefresh.library;
import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import android.view.animation.Interpolator; import android.view.animation.Interpolator;
@ -27,6 +26,17 @@ import com.handmark.pulltorefresh.library.PullToRefreshBase.State;
public interface IPullToRefresh<T extends View> { public interface IPullToRefresh<T extends View> {
/**
* Demos the Pull-to-Refresh functionality to the user so that they are
* aware it is there. This could be useful when the user first opens your
* app, etc. The animation will only happen if the Refresh View (ListView,
* ScrollView, etc) is in a state where a Pull-to-Refresh could occur by a
* user's touch gesture (i.e. scrolled to the top/bottom).
*
* @return true - if the Demo has been started, false if not.
*/
public boolean demo();
/** /**
* Get the mode that this view is currently in. This is only really useful * Get the mode that this view is currently in. This is only really useful
* when using <code>Mode.BOTH</code>. * when using <code>Mode.BOTH</code>.
@ -46,6 +56,34 @@ public interface IPullToRefresh<T extends View> {
*/ */
public boolean getFilterTouchEvents(); public boolean getFilterTouchEvents();
/**
* Returns a proxy object which allows you to call methods on all of the
* LoadingLayouts (the Views which show when Pulling/Refreshing).
* <p />
* You should not keep the result of this method any longer than you need
* it.
*
* @return Object which will proxy any calls you make on it, to all of the
* LoadingLayouts.
*/
public ILoadingLayout getLoadingLayoutProxy();
/**
* Returns a proxy object which allows you to call methods on the
* LoadingLayouts (the Views which show when Pulling/Refreshing). The actual
* LoadingLayout(s) which will be affected, are chosen by the parameters you
* give.
* <p />
* You should not keep the result of this method any longer than you need
* it.
*
* @param includeStart - Whether to include the Start/Header Views
* @param includeEnd - Whether to include the End/Footer Views
* @return Object which will proxy any calls you make on it, to the
* LoadingLayouts included.
*/
public ILoadingLayout getLoadingLayoutProxy(boolean includeStart, boolean includeEnd);
/** /**
* Get the mode that this view has been set to. If this returns * Get the mode that this view has been set to. If this returns
* <code>Mode.BOTH</code>, you can use <code>getCurrentMode()</code> to * <code>Mode.BOTH</code>, you can use <code>getCurrentMode()</code> to
@ -77,12 +115,11 @@ public interface IPullToRefresh<T extends View> {
public State getState(); public State getState();
/** /**
* Returns whether the widget has disabled scrolling on the Refreshable View * Whether Pull-to-Refresh is enabled
* while refreshing.
* *
* @return true if the widget has disabled scrolling while refreshing * @return enabled
*/ */
public boolean isDisableScrollingWhileRefreshing(); public boolean isPullToRefreshEnabled();
/** /**
* Gets whether Overscroll support is enabled. This is different to * Gets whether Overscroll support is enabled. This is different to
@ -94,13 +131,6 @@ public interface IPullToRefresh<T extends View> {
*/ */
public boolean isPullToRefreshOverScrollEnabled(); public boolean isPullToRefreshOverScrollEnabled();
/**
* Whether Pull-to-Refresh is enabled
*
* @return enabled
*/
public boolean isPullToRefreshEnabled();
/** /**
* Returns whether the Widget is currently in the Refreshing mState * Returns whether the Widget is currently in the Refreshing mState
* *
@ -108,21 +138,20 @@ public interface IPullToRefresh<T extends View> {
*/ */
public boolean isRefreshing(); public boolean isRefreshing();
/**
* Returns whether the widget has enabled scrolling on the Refreshable View
* while refreshing.
*
* @return true if the widget has enabled scrolling while refreshing
*/
public boolean isScrollingWhileRefreshingEnabled();
/** /**
* Mark the current Refresh as complete. Will Reset the UI and hide the * Mark the current Refresh as complete. Will Reset the UI and hide the
* Refreshing View * Refreshing View
*/ */
public void onRefreshComplete(); public void onRefreshComplete();
/**
* By default the Widget disabled scrolling on the Refreshable View while
* refreshing. This method can change this behaviour.
*
* @param disableScrollingWhileRefreshing
* - true if you want to disable scrolling while refreshing
*/
public void setDisableScrollingWhileRefreshing(boolean disableScrollingWhileRefreshing);
/** /**
* Set the Touch Events to be filtered or not. If set to true, then the View * Set the Touch Events to be filtered or not. If set to true, then the View
* will only use touch events where the difference in the Y-axis is greater * will only use touch events where the difference in the Y-axis is greater
@ -131,54 +160,22 @@ public interface IPullToRefresh<T extends View> {
* ViewPager), but will restrict which types of finger scrolls will trigger * ViewPager), but will restrict which types of finger scrolls will trigger
* the View. * the View.
* *
* @param filterEvents * @param filterEvents - true if you want to filter Touch Events. Default is
* - true if you want to filter Touch Events. Default is true. * true.
*/ */
public void setFilterTouchEvents(boolean filterEvents); public void setFilterTouchEvents(boolean filterEvents);
/**
* Set the Last Updated Text. This displayed under the main label when
* Pulling
*
* @param label
* - Label to set
*/
public void setLastUpdatedLabel(CharSequence label);
/**
* Set the drawable used in the loading layout. This is the same as calling
* <code>setLoadingDrawable(drawable, Mode.BOTH)</code>
*
* @param drawable
* - Drawable to display
*/
public void setLoadingDrawable(Drawable drawable);
/**
* Set the drawable used in the loading layout.
*
* @param drawable
* - Drawable to display
* @param mode
* - Controls which Header/Footer Views will be updated.
* <code>Mode.BOTH</code> will update all available, other values
* will update the relevant View.
*/
public void setLoadingDrawable(Drawable drawable, Mode mode);
/** /**
* Set the mode of Pull-to-Refresh that this view will use. * Set the mode of Pull-to-Refresh that this view will use.
* *
* @param mode * @param mode - Mode to set the View to
* - Mode to set the View to
*/ */
public void setMode(Mode mode); public void setMode(Mode mode);
/** /**
* Set OnPullEventListener for the Widget * Set OnPullEventListener for the Widget
* *
* @param listener * @param listener - Listener to be used when the Widget has a pull event to
* - Listener to be used when the Widget has a pull event to
* propogate. * propogate.
*/ */
public void setOnPullEventListener(OnPullEventListener<T> listener); public void setOnPullEventListener(OnPullEventListener<T> listener);
@ -186,16 +183,14 @@ public interface IPullToRefresh<T extends View> {
/** /**
* Set OnRefreshListener for the Widget * Set OnRefreshListener for the Widget
* *
* @param listener * @param listener - Listener to be used when the Widget is set to Refresh
* - Listener to be used when the Widget is set to Refresh
*/ */
public void setOnRefreshListener(OnRefreshListener<T> listener); public void setOnRefreshListener(OnRefreshListener<T> listener);
/** /**
* Set OnRefreshListener for the Widget * Set OnRefreshListener for the Widget
* *
* @param listener * @param listener - Listener to be used when the Widget is set to Refresh
* - Listener to be used when the Widget is set to Refresh
*/ */
public void setOnRefreshListener(OnRefreshListener2<T> listener); public void setOnRefreshListener(OnRefreshListener2<T> listener);
@ -204,32 +199,10 @@ public interface IPullToRefresh<T extends View> {
* Android's standard Overscroll support (the edge-glow). This setting only * Android's standard Overscroll support (the edge-glow). This setting only
* takes effect when running on device with Android v2.3 or greater. * takes effect when running on device with Android v2.3 or greater.
* *
* @param enabled * @param enabled - true if you want Overscroll enabled
* - true if you want Overscroll enabled
*/ */
public void setPullToRefreshOverScrollEnabled(boolean enabled); public void setPullToRefreshOverScrollEnabled(boolean enabled);
/**
* Set Text to show when the Widget is being Pulled
* <code>setPullLabel(releaseLabel, Mode.BOTH)</code>
*
* @param releaseLabel
* - CharSequence to display
*/
public void setPullLabel(CharSequence pullLabel);
/**
* Set Text to show when the Widget is being Pulled
*
* @param pullLabel
* - CharSequence to display
* @param mode
* - Controls which Header/Footer Views will be updated.
* <code>Mode.BOTH</code> will update all available, other values
* will update the relevant View.
*/
public void setPullLabel(CharSequence pullLabel, Mode mode);
/** /**
* Sets the Widget to be in the refresh state. The UI will be updated to * Sets the Widget to be in the refresh state. The UI will be updated to
* show the 'Refreshing' view, and be scrolled to show such. * show the 'Refreshing' view, and be scrolled to show such.
@ -240,64 +213,28 @@ public interface IPullToRefresh<T extends View> {
* Sets the Widget to be in the refresh state. The UI will be updated to * Sets the Widget to be in the refresh state. The UI will be updated to
* show the 'Refreshing' view. * show the 'Refreshing' view.
* *
* @param doScroll * @param doScroll - true if you want to force a scroll to the Refreshing
* - true if you want to force a scroll to the Refreshing view. * view.
*/ */
public void setRefreshing(boolean doScroll); public void setRefreshing(boolean doScroll);
/**
* Set Text to show when the Widget is refreshing
* <code>setRefreshingLabel(releaseLabel, Mode.BOTH)</code>
*
* @param releaseLabel
* - CharSequence to display
*/
public void setRefreshingLabel(CharSequence refreshingLabel);
/**
* Set Text to show when the Widget is refreshing
*
* @param refreshingLabel
* - CharSequence to display
* @param mode
* - Controls which Header/Footer Views will be updated.
* <code>Mode.BOTH</code> will update all available, other values
* will update the relevant View.
*/
public void setRefreshingLabel(CharSequence refreshingLabel, Mode mode);
/**
* Set Text to show when the Widget is being pulled, and will refresh when
* released. This is the same as calling
* <code>setReleaseLabel(releaseLabel, Mode.BOTH)</code>
*
* @param releaseLabel
* - CharSequence to display
*/
public void setReleaseLabel(CharSequence releaseLabel);
/**
* Set Text to show when the Widget is being pulled, and will refresh when
* released
*
* @param releaseLabel
* - CharSequence to display
* @param mode
* - Controls which Header/Footer Views will be updated.
* <code>Mode.BOTH</code> will update all available, other values
* will update the relevant View.
*/
public void setReleaseLabel(CharSequence releaseLabel, Mode mode);
/** /**
* Sets the Animation Interpolator that is used for animated scrolling. * Sets the Animation Interpolator that is used for animated scrolling.
* Defaults to a DecelerateInterpolator * Defaults to a DecelerateInterpolator
* *
* @param interpolator * @param interpolator - Interpolator to use
* - Interpolator to use
*/ */
public void setScrollAnimationInterpolator(Interpolator interpolator); public void setScrollAnimationInterpolator(Interpolator interpolator);
/**
* By default the Widget disables scrolling on the Refreshable View while
* refreshing. This method can change this behaviour.
*
* @param scrollingWhileRefreshingEnabled - true if you want to enable
* scrolling while refreshing
*/
public void setScrollingWhileRefreshingEnabled(boolean scrollingWhileRefreshingEnabled);
/** /**
* A mutator to enable/disable whether the 'Refreshing' View should be * A mutator to enable/disable whether the 'Refreshing' View should be
* automatically shown when refreshing. * automatically shown when refreshing.

View File

@ -0,0 +1,73 @@
package com.handmark.pulltorefresh.library;
import java.util.HashSet;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import com.handmark.pulltorefresh.library.internal.LoadingLayout;
public class LoadingLayoutProxy implements ILoadingLayout {
private final HashSet<LoadingLayout> mLoadingLayouts;
LoadingLayoutProxy() {
mLoadingLayouts = new HashSet<LoadingLayout>();
}
/**
* This allows you to add extra LoadingLayout instances to this proxy. This
* is only necessary if you keep your own instances, and want to have them
* included in any
* {@link PullToRefreshBase#createLoadingLayoutProxy(boolean, boolean)
* createLoadingLayoutProxy(...)} calls.
*
* @param layout - LoadingLayout to have included.
*/
public void addLayout(LoadingLayout layout) {
if (null != layout) {
mLoadingLayouts.add(layout);
}
}
@Override
public void setLastUpdatedLabel(CharSequence label) {
for (LoadingLayout layout : mLoadingLayouts) {
layout.setLastUpdatedLabel(label);
}
}
@Override
public void setLoadingDrawable(Drawable drawable) {
for (LoadingLayout layout : mLoadingLayouts) {
layout.setLoadingDrawable(drawable);
}
}
@Override
public void setRefreshingLabel(CharSequence refreshingLabel) {
for (LoadingLayout layout : mLoadingLayouts) {
layout.setRefreshingLabel(refreshingLabel);
}
}
@Override
public void setPullLabel(CharSequence label) {
for (LoadingLayout layout : mLoadingLayouts) {
layout.setPullLabel(label);
}
}
@Override
public void setReleaseLabel(CharSequence label) {
for (LoadingLayout layout : mLoadingLayouts) {
layout.setReleaseLabel(label);
}
}
public void setTextTypeface(Typeface tf) {
for (LoadingLayout layout : mLoadingLayouts) {
layout.setTextTypeface(tf);
}
}
}

View File

@ -20,9 +20,10 @@ import android.util.Log;
import android.view.View; import android.view.View;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode; import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshBase.State;
@TargetApi(9) @TargetApi(9)
final class OverscrollHelper { public final class OverscrollHelper {
static final String LOG_TAG = "OverscrollHelper"; static final String LOG_TAG = "OverscrollHelper";
static final float DEFAULT_OVERSCROLL_SCALE = 1f; static final float DEFAULT_OVERSCROLL_SCALE = 1f;
@ -30,26 +31,26 @@ final class OverscrollHelper {
/** /**
* Helper method for Overscrolling that encapsulates all of the necessary * Helper method for Overscrolling that encapsulates all of the necessary
* function. * function.
* * <p/>
* This should only be used on AdapterView's such as ListView as it just * This should only be used on AdapterView's such as ListView as it just
* calls through to overScrollBy() with the scrollRange = 0. AdapterView's * calls through to overScrollBy() with the scrollRange = 0. AdapterView's
* do not have a scroll range (i.e. getScrollY() doesn't work). * do not have a scroll range (i.e. getScrollY() doesn't work).
* *
* @param view * @param view - PullToRefreshView that is calling this.
* - PullToRefreshView that is calling this. * @param deltaX - Change in X in pixels, passed through from from
* @param deltaY * overScrollBy call
* - Change in Y in pixels, passed through from from overScrollBy * @param scrollX - Current X scroll value in pixels before applying deltaY,
* call
* @param scrollY
* - Current Y scroll value in pixels before applying deltaY,
* passed through from from overScrollBy call * passed through from from overScrollBy call
* @param isTouchEvent * @param deltaY - Change in Y in pixels, passed through from from
* - true if this scroll operation is the result of a touch * overScrollBy call
* event, passed through from from overScrollBy call * @param scrollY - Current Y scroll value in pixels before applying deltaY,
* passed through from from overScrollBy call
* @param isTouchEvent - true if this scroll operation is the result of a
* touch event, passed through from from overScrollBy call
*/ */
static void overScrollBy(final PullToRefreshBase<?> view, final int deltaY, final int scrollY, public static void overScrollBy(final PullToRefreshBase<?> view, final int deltaX, final int scrollX,
final boolean isTouchEvent) { final int deltaY, final int scrollY, final boolean isTouchEvent) {
overScrollBy(view, deltaY, scrollY, 0, isTouchEvent); overScrollBy(view, deltaX, scrollX, deltaY, scrollY, 0, isTouchEvent);
} }
/** /**
@ -57,81 +58,116 @@ final class OverscrollHelper {
* function. This version of the call is used for Views that need to specify * function. This version of the call is used for Views that need to specify
* a Scroll Range but scroll back to it's edge correctly. * a Scroll Range but scroll back to it's edge correctly.
* *
* @param view * @param view - PullToRefreshView that is calling this.
* - PullToRefreshView that is calling this. * @param deltaX - Change in X in pixels, passed through from from
* @param deltaY * overScrollBy call
* - Change in Y in pixels, passed through from from overScrollBy * @param scrollX - Current X scroll value in pixels before applying deltaY,
* call
* @param scrollY
* - Current Y scroll value in pixels before applying deltaY,
* passed through from from overScrollBy call * passed through from from overScrollBy call
* @param scrollRange * @param deltaY - Change in Y in pixels, passed through from from
* - Scroll Range of the View, specifically needed for ScrollView * overScrollBy call
* @param isTouchEvent * @param scrollY - Current Y scroll value in pixels before applying deltaY,
* - true if this scroll operation is the result of a touch * passed through from from overScrollBy call
* event, passed through from from overScrollBy call * @param scrollRange - Scroll Range of the View, specifically needed for
* ScrollView
* @param isTouchEvent - true if this scroll operation is the result of a
* touch event, passed through from from overScrollBy call
*/ */
static void overScrollBy(final PullToRefreshBase<?> view, final int deltaY, final int scrollY, public static void overScrollBy(final PullToRefreshBase<?> view, final int deltaX, final int scrollX,
final int scrollRange, final boolean isTouchEvent) { final int deltaY, final int scrollY, final int scrollRange, final boolean isTouchEvent) {
overScrollBy(view, deltaY, scrollY, scrollRange, 0, DEFAULT_OVERSCROLL_SCALE, isTouchEvent); overScrollBy(view, deltaX, scrollX, deltaY, scrollY, scrollRange, 0, DEFAULT_OVERSCROLL_SCALE, isTouchEvent);
} }
/** /**
* Helper method for Overscrolling that encapsulates all of the necessary * Helper method for Overscrolling that encapsulates all of the necessary
* function. This is the advanced version of the call. * function. This is the advanced version of the call.
* *
* @param view * @param view - PullToRefreshView that is calling this.
* - PullToRefreshView that is calling this. * @param deltaX - Change in X in pixels, passed through from from
* @param deltaY * overScrollBy call
* - Change in Y in pixels, passed through from from overScrollBy * @param scrollX - Current X scroll value in pixels before applying deltaY,
* call
* @param scrollY
* - Current Y scroll value in pixels before applying deltaY,
* passed through from from overScrollBy call * passed through from from overScrollBy call
* @param scrollRange * @param deltaY - Change in Y in pixels, passed through from from
* - Scroll Range of the View, specifically needed for ScrollView * overScrollBy call
* @param fuzzyThreshold * @param scrollY - Current Y scroll value in pixels before applying deltaY,
* - Threshold for which the values how fuzzy we should treat the * passed through from from overScrollBy call
* other values. Needed for WebView as it doesn't always scroll * @param scrollRange - Scroll Range of the View, specifically needed for
* back to it's edge. 0 = no fuzziness. * ScrollView
* @param scaleFactor * @param fuzzyThreshold - Threshold for which the values how fuzzy we
* - Scale Factor for overscroll amount * should treat the other values. Needed for WebView as it
* @param isTouchEvent * doesn't always scroll back to it's edge. 0 = no fuzziness.
* - true if this scroll operation is the result of a touch * @param scaleFactor - Scale Factor for overscroll amount
* event, passed through from from overScrollBy call * @param isTouchEvent - true if this scroll operation is the result of a
* touch event, passed through from from overScrollBy call
*/ */
static void overScrollBy(final PullToRefreshBase<?> view, final int deltaY, final int scrollY, public static void overScrollBy(final PullToRefreshBase<?> view, final int deltaX, final int scrollX,
final int scrollRange, final int fuzzyThreshold, final float scaleFactor, final boolean isTouchEvent) { final int deltaY, final int scrollY, final int scrollRange, final int fuzzyThreshold,
final float scaleFactor, final boolean isTouchEvent) {
// Check that OverScroll is enabled final int deltaValue, currentScrollValue, scrollValue;
if (view.isPullToRefreshOverScrollEnabled()) { switch (view.getPullToRefreshScrollDirection()) {
case HORIZONTAL:
deltaValue = deltaX;
scrollValue = scrollX;
currentScrollValue = view.getScrollX();
break;
case VERTICAL:
default:
deltaValue = deltaY;
scrollValue = scrollY;
currentScrollValue = view.getScrollY();
break;
}
// Check that OverScroll is enabled and that we're not currently
// refreshing.
if (view.isPullToRefreshOverScrollEnabled() && !view.isRefreshing()) {
final Mode mode = view.getMode(); final Mode mode = view.getMode();
// Check that we're not disabled, and the event isn't from touch // Check that Pull-to-Refresh is enabled, and the event isn't from
if (mode != Mode.DISABLED && !isTouchEvent && deltaY != 0) { // touch
final int newY = (deltaY + scrollY); if (mode.permitsPullToRefresh() && !isTouchEvent && deltaValue != 0) {
final int newScrollValue = (deltaValue + scrollValue);
if (PullToRefreshBase.DEBUG) { if (PullToRefreshBase.DEBUG) {
Log.d(LOG_TAG, "OverScroll. DeltaY: " + deltaY + ", ScrollY: " + scrollY + ", NewY: " + newY Log.d(LOG_TAG, "OverScroll. DeltaX: " + deltaX + ", ScrollX: " + scrollX + ", DeltaY: " + deltaY
+ ", ScrollRange: " + scrollRange); + ", ScrollY: " + scrollY + ", NewY: " + newScrollValue + ", ScrollRange: " + scrollRange
+ ", CurrentScroll: " + currentScrollValue);
} }
if (newY < (0 - fuzzyThreshold)) { if (newScrollValue < (0 - fuzzyThreshold)) {
// Check the mode supports the overscroll direction, and // Check the mode supports the overscroll direction, and
// then move scroll // then move scroll
if (mode.canPullDown()) { if (mode.showHeaderLoadingLayout()) {
view.setHeaderScroll((int) (scaleFactor * (view.getScrollY() + newY))); // If we're currently at zero, we're about to start
// overscrolling, so change the state
if (currentScrollValue == 0) {
view.setState(State.OVERSCROLLING);
}
view.setHeaderScroll((int) (scaleFactor * (currentScrollValue + newScrollValue)));
} }
} else if (newY > (scrollRange + fuzzyThreshold)) { } else if (newScrollValue > (scrollRange + fuzzyThreshold)) {
// Check the mode supports the overscroll direction, and // Check the mode supports the overscroll direction, and
// then move scroll // then move scroll
if (mode.canPullUp()) { if (mode.showFooterLoadingLayout()) {
view.setHeaderScroll((int) (scaleFactor * (view.getScrollY() + newY - scrollRange))); // If we're currently at zero, we're about to start
// overscrolling, so change the state
if (currentScrollValue == 0) {
view.setState(State.OVERSCROLLING);
}
view.setHeaderScroll((int) (scaleFactor * (currentScrollValue + newScrollValue - scrollRange)));
} }
} else if (Math.abs(newY) <= fuzzyThreshold || Math.abs(newY - scrollRange) <= fuzzyThreshold) { } else if (Math.abs(newScrollValue) <= fuzzyThreshold
|| Math.abs(newScrollValue - scrollRange) <= fuzzyThreshold) {
// Means we've stopped overscrolling, so scroll back to 0 // Means we've stopped overscrolling, so scroll back to 0
view.smoothScrollToLonger(0); view.setState(State.RESET);
} }
} else if (isTouchEvent && State.OVERSCROLLING == view.getState()) {
// This condition means that we were overscrolling from a fling,
// but the user has touched the View and is now overscrolling
// from touch instead. We need to just reset.
view.setState(State.RESET);
} }
} }
} }

View File

@ -19,7 +19,6 @@ import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -30,6 +29,7 @@ import android.widget.Adapter;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListAdapter; import android.widget.ListAdapter;
import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor; import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor;
@ -38,7 +38,23 @@ import com.handmark.pulltorefresh.library.internal.IndicatorLayout;
public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extends PullToRefreshBase<T> implements public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extends PullToRefreshBase<T> implements
OnScrollListener { OnScrollListener {
private int mSavedLastVisibleIndex = -1; private static FrameLayout.LayoutParams convertEmptyViewLayoutParams(ViewGroup.LayoutParams lp) {
FrameLayout.LayoutParams newLp = null;
if (null != lp) {
newLp = new FrameLayout.LayoutParams(lp);
if (lp instanceof LinearLayout.LayoutParams) {
newLp.gravity = ((LinearLayout.LayoutParams) lp).gravity;
} else {
newLp.gravity = Gravity.CENTER;
}
}
return newLp;
}
private boolean mLastItemVisible;
private OnScrollListener mOnScrollListener; private OnScrollListener mOnScrollListener;
private OnLastItemVisibleListener mOnLastItemVisibleListener; private OnLastItemVisibleListener mOnLastItemVisibleListener;
private View mEmptyView; private View mEmptyView;
@ -64,14 +80,17 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
mRefreshableView.setOnScrollListener(this); mRefreshableView.setOnScrollListener(this);
} }
abstract public ContextMenuInfo getContextMenuInfo(); public PullToRefreshAdapterViewBase(Context context, Mode mode, AnimationStyle animStyle) {
super(context, mode, animStyle);
mRefreshableView.setOnScrollListener(this);
}
/** /**
* Gets whether an indicator graphic should be displayed when the View is in * Gets whether an indicator graphic should be displayed when the View is in
* a state where a Pull-to-Refresh can happen. An example of this state is * a state where a Pull-to-Refresh can happen. An example of this state is
* when the Adapter View is scrolled to the top and the mode is set to * when the Adapter View is scrolled to the top and the mode is set to
* {@link Mode#PULL_DOWN_TO_REFRESH}. The default value is <var>true</var> * {@link Mode#PULL_FROM_START}. The default value is <var>true</var> if
* if {@link PullToRefreshBase#isPullToRefreshOverScrollEnabled() * {@link PullToRefreshBase#isPullToRefreshOverScrollEnabled()
* isPullToRefreshOverScrollEnabled()} returns false. * isPullToRefreshOverScrollEnabled()} returns false.
* *
* @return true if the indicators will be shown * @return true if the indicators will be shown
@ -85,26 +104,15 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
if (DEBUG) { if (DEBUG) {
Log.d(LOG_TAG, "First Visible: " + firstVisibleItem + ". Visible Count: " + visibleItemCount Log.d(LOG_TAG, "First Visible: " + firstVisibleItem + ". Visible Count: " + visibleItemCount
+ ". Total Items: " + totalItemCount); + ". Total Items:" + totalItemCount);
} }
// If we have a OnItemVisibleListener, do check... /**
* Set whether the Last Item is Visible. lastVisibleItemIndex is a
* zero-based index, so we minus one totalItemCount to check
*/
if (null != mOnLastItemVisibleListener) { if (null != mOnLastItemVisibleListener) {
mLastItemVisible = (totalItemCount > 0) && (firstVisibleItem + visibleItemCount >= totalItemCount - 1);
// Detect whether the last visible item has changed
final int lastVisibleItemIndex = firstVisibleItem + visibleItemCount;
/**
* Check that the last item has changed, we have any items, and that
* the last item is visible. lastVisibleItemIndex is a zero-based
* index, so we add one to it to check against totalItemCount.
*/
if (visibleItemCount > 0 && (lastVisibleItemIndex + 1) == totalItemCount) {
if (lastVisibleItemIndex != mSavedLastVisibleIndex) {
mSavedLastVisibleIndex = lastVisibleItemIndex;
mOnLastItemVisibleListener.onLastItemVisible();
}
}
} }
// If we're showing the indicator, check positions... // If we're showing the indicator, check positions...
@ -118,19 +126,27 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
} }
} }
public final void onScrollStateChanged(final AbsListView view, final int scrollState) { public final void onScrollStateChanged(final AbsListView view, final int state) {
/**
* Check that the scrolling has stopped, and that the last item is
* visible.
*/
if (state == OnScrollListener.SCROLL_STATE_IDLE && null != mOnLastItemVisibleListener && mLastItemVisible) {
mOnLastItemVisibleListener.onLastItemVisible();
}
if (null != mOnScrollListener) { if (null != mOnScrollListener) {
mOnScrollListener.onScrollStateChanged(view, scrollState); mOnScrollListener.onScrollStateChanged(view, state);
} }
} }
/** /**
* Pass-through method for {@link PullToRefreshBase#getRefreshableView() * Pass-through method for {@link PullToRefreshBase#getRefreshableView()
* getRefreshableView()}.{@link AdapterView#setAdapter(ListAdapter) * getRefreshableView()}.
* {@link AdapterView#setAdapter(android.widget.Adapter)}
* setAdapter(adapter)}. This is just for convenience! * setAdapter(adapter)}. This is just for convenience!
* *
* @param adapter * @param adapter - Adapter to set
* - Adapter to set
*/ */
public void setAdapter(ListAdapter adapter) { public void setAdapter(ListAdapter adapter) {
((AdapterView<ListAdapter>) mRefreshableView).setAdapter(adapter); ((AdapterView<ListAdapter>) mRefreshableView).setAdapter(adapter);
@ -138,17 +154,16 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
/** /**
* Sets the Empty View to be used by the Adapter View. * Sets the Empty View to be used by the Adapter View.
* * <p/>
* We need it handle it ourselves so that we can Pull-to-Refresh when the * We need it handle it ourselves so that we can Pull-to-Refresh when the
* Empty View is shown. * Empty View is shown.
* * <p/>
* Please note, you do <strong>not</strong> usually need to call this method * Please note, you do <strong>not</strong> usually need to call this method
* yourself. Calling setEmptyView on the AdapterView will automatically call * yourself. Calling setEmptyView on the AdapterView will automatically call
* this method and set everything up. This includes when the Android * this method and set everything up. This includes when the Android
* Framework automatically sets the Empty View based on it's ID. * Framework automatically sets the Empty View based on it's ID.
* *
* @param newEmptyView * @param newEmptyView - Empty View to be used
* - Empty View to be used
*/ */
public final void setEmptyView(View newEmptyView) { public final void setEmptyView(View newEmptyView) {
FrameLayout refreshableViewWrapper = getRefreshableViewWrapper(); FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();
@ -168,8 +183,14 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
((ViewGroup) newEmptyViewParent).removeView(newEmptyView); ((ViewGroup) newEmptyViewParent).removeView(newEmptyView);
} }
refreshableViewWrapper.addView(newEmptyView, ViewGroup.LayoutParams.MATCH_PARENT, // We need to convert any LayoutParams so that it works in our
ViewGroup.LayoutParams.MATCH_PARENT); // FrameLayout
FrameLayout.LayoutParams lp = convertEmptyViewLayoutParams(newEmptyView.getLayoutParams());
if (null != lp) {
refreshableViewWrapper.addView(newEmptyView, lp);
} else {
refreshableViewWrapper.addView(newEmptyView);
}
} }
if (mRefreshableView instanceof EmptyViewMethodAccessor) { if (mRefreshableView instanceof EmptyViewMethodAccessor) {
@ -186,8 +207,7 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
* {@link AdapterView#setOnItemClickListener(OnItemClickListener) * {@link AdapterView#setOnItemClickListener(OnItemClickListener)
* setOnItemClickListener(listener)}. This is just for convenience! * setOnItemClickListener(listener)}. This is just for convenience!
* *
* @param listener * @param listener - OnItemClickListener to use
* - OnItemClickListener to use
*/ */
public void setOnItemClickListener(OnItemClickListener listener) { public void setOnItemClickListener(OnItemClickListener listener) {
mRefreshableView.setOnItemClickListener(listener); mRefreshableView.setOnItemClickListener(listener);
@ -209,10 +229,9 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
* Sets whether an indicator graphic should be displayed when the View is in * Sets whether an indicator graphic should be displayed when the View is in
* a state where a Pull-to-Refresh can happen. An example of this state is * a state where a Pull-to-Refresh can happen. An example of this state is
* when the Adapter View is scrolled to the top and the mode is set to * when the Adapter View is scrolled to the top and the mode is set to
* {@link Mode#PULL_DOWN_TO_REFRESH} * {@link Mode#PULL_FROM_START}
* *
* @param showIndicator * @param showIndicator - true if the indicators should be shown.
* - true if the indicators should be shown.
*/ */
public void setShowIndicator(boolean showIndicator) { public void setShowIndicator(boolean showIndicator) {
mShowIndicator = showIndicator; mShowIndicator = showIndicator;
@ -224,25 +243,30 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
// If not, then remove then // If not, then remove then
removeIndicatorViews(); removeIndicatorViews();
} }
}; }
;
@Override @Override
void onPullToRefresh() { protected void onPullToRefresh() {
super.onPullToRefresh(); super.onPullToRefresh();
if (getShowIndicatorInternal()) { if (getShowIndicatorInternal()) {
switch (getCurrentMode()) { switch (getCurrentMode()) {
case PULL_UP_TO_REFRESH: case PULL_FROM_END:
mIndicatorIvBottom.pullToRefresh(); mIndicatorIvBottom.pullToRefresh();
break; break;
case PULL_DOWN_TO_REFRESH: case PULL_FROM_START:
mIndicatorIvTop.pullToRefresh(); mIndicatorIvTop.pullToRefresh();
break; break;
default:
// NO-OP
break;
} }
} }
} }
void onRefreshing(boolean doScroll) { protected void onRefreshing(boolean doScroll) {
super.onRefreshing(doScroll); super.onRefreshing(doScroll);
if (getShowIndicatorInternal()) { if (getShowIndicatorInternal()) {
@ -251,23 +275,26 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
} }
@Override @Override
void onReleaseToRefresh() { protected void onReleaseToRefresh() {
super.onReleaseToRefresh(); super.onReleaseToRefresh();
if (getShowIndicatorInternal()) { if (getShowIndicatorInternal()) {
switch (getCurrentMode()) { switch (getCurrentMode()) {
case PULL_UP_TO_REFRESH: case PULL_FROM_END:
mIndicatorIvBottom.releaseToRefresh(); mIndicatorIvBottom.releaseToRefresh();
break; break;
case PULL_DOWN_TO_REFRESH: case PULL_FROM_START:
mIndicatorIvTop.releaseToRefresh(); mIndicatorIvTop.releaseToRefresh();
break; break;
default:
// NO-OP
break;
} }
} }
} }
@Override @Override
void onReset() { protected void onReset() {
super.onReset(); super.onReset();
if (getShowIndicatorInternal()) { if (getShowIndicatorInternal()) {
@ -281,11 +308,11 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
mShowIndicator = a.getBoolean(R.styleable.PullToRefresh_ptrShowIndicator, !isPullToRefreshOverScrollEnabled()); mShowIndicator = a.getBoolean(R.styleable.PullToRefresh_ptrShowIndicator, !isPullToRefreshOverScrollEnabled());
} }
protected boolean isReadyForPullDown() { protected boolean isReadyForPullStart() {
return isFirstItemVisible(); return isFirstItemVisible();
} }
protected boolean isReadyForPullUp() { protected boolean isReadyForPullEnd() {
return isLastItemVisible(); return isLastItemVisible();
} }
@ -313,31 +340,31 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
Mode mode = getMode(); Mode mode = getMode();
FrameLayout refreshableViewWrapper = getRefreshableViewWrapper(); FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();
if (mode.canPullDown() && null == mIndicatorIvTop) { if (mode.showHeaderLoadingLayout() && null == mIndicatorIvTop) {
// If the mode can pull down, and we don't have one set already // If the mode can pull down, and we don't have one set already
mIndicatorIvTop = new IndicatorLayout(getContext(), Mode.PULL_DOWN_TO_REFRESH); mIndicatorIvTop = new IndicatorLayout(getContext(), Mode.PULL_FROM_START);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT); ViewGroup.LayoutParams.WRAP_CONTENT);
params.rightMargin = getResources().getDimensionPixelSize(R.dimen.indicator_right_padding); params.rightMargin = getResources().getDimensionPixelSize(R.dimen.indicator_right_padding);
params.gravity = Gravity.TOP | Gravity.RIGHT; params.gravity = Gravity.TOP | Gravity.RIGHT;
refreshableViewWrapper.addView(mIndicatorIvTop, params); refreshableViewWrapper.addView(mIndicatorIvTop, params);
} else if (!mode.canPullDown() && null != mIndicatorIvTop) { } else if (!mode.showHeaderLoadingLayout() && null != mIndicatorIvTop) {
// If we can't pull down, but have a View then remove it // If we can't pull down, but have a View then remove it
refreshableViewWrapper.removeView(mIndicatorIvTop); refreshableViewWrapper.removeView(mIndicatorIvTop);
mIndicatorIvTop = null; mIndicatorIvTop = null;
} }
if (mode.canPullUp() && null == mIndicatorIvBottom) { if (mode.showFooterLoadingLayout() && null == mIndicatorIvBottom) {
// If the mode can pull down, and we don't have one set already // If the mode can pull down, and we don't have one set already
mIndicatorIvBottom = new IndicatorLayout(getContext(), Mode.PULL_UP_TO_REFRESH); mIndicatorIvBottom = new IndicatorLayout(getContext(), Mode.PULL_FROM_END);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT); ViewGroup.LayoutParams.WRAP_CONTENT);
params.rightMargin = getResources().getDimensionPixelSize(R.dimen.indicator_right_padding); params.rightMargin = getResources().getDimensionPixelSize(R.dimen.indicator_right_padding);
params.gravity = Gravity.BOTTOM | Gravity.RIGHT; params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
refreshableViewWrapper.addView(mIndicatorIvBottom, params); refreshableViewWrapper.addView(mIndicatorIvBottom, params);
} else if (!mode.canPullUp() && null != mIndicatorIvBottom) { } else if (!mode.showFooterLoadingLayout() && null != mIndicatorIvBottom) {
// If we can't pull down, but have a View then remove it // If we can't pull down, but have a View then remove it
refreshableViewWrapper.removeView(mIndicatorIvBottom); refreshableViewWrapper.removeView(mIndicatorIvBottom);
mIndicatorIvBottom = null; mIndicatorIvBottom = null;
@ -427,7 +454,7 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
private void updateIndicatorViewsVisibility() { private void updateIndicatorViewsVisibility() {
if (null != mIndicatorIvTop) { if (null != mIndicatorIvTop) {
if (!isRefreshing() && isReadyForPullDown()) { if (!isRefreshing() && isReadyForPullStart()) {
if (!mIndicatorIvTop.isVisible()) { if (!mIndicatorIvTop.isVisible()) {
mIndicatorIvTop.show(); mIndicatorIvTop.show();
} }
@ -439,7 +466,7 @@ public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extend
} }
if (null != mIndicatorIvBottom) { if (null != mIndicatorIvBottom) {
if (!isRefreshing() && isReadyForPullUp()) { if (!isRefreshing() && isReadyForPullEnd()) {
if (!mIndicatorIvBottom.isVisible()) { if (!mIndicatorIvBottom.isVisible()) {
mIndicatorIvBottom.show(); mIndicatorIvBottom.show();
} }

View File

@ -20,7 +20,6 @@ import android.content.Context;
import android.os.Build.VERSION; import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES; import android.os.Build.VERSION_CODES;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View; import android.view.View;
import android.widget.ExpandableListView; import android.widget.ExpandableListView;
@ -40,13 +39,17 @@ public class PullToRefreshExpandableListView extends PullToRefreshAdapterViewBas
super(context, mode); super(context, mode);
} }
@Override public PullToRefreshExpandableListView(Context context, Mode mode, AnimationStyle style) {
public ContextMenuInfo getContextMenuInfo() { super(context, mode, style);
return ((InternalExpandableListView) getRefreshableView()).getContextMenuInfo();
} }
@Override @Override
protected final ExpandableListView createRefreshableView(Context context, AttributeSet attrs) { public final Orientation getPullToRefreshScrollDirection() {
return Orientation.VERTICAL;
}
@Override
protected ExpandableListView createRefreshableView(Context context, AttributeSet attrs) {
final ExpandableListView lv; final ExpandableListView lv;
if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
lv = new InternalExpandableListViewSDK9(context, attrs); lv = new InternalExpandableListViewSDK9(context, attrs);
@ -65,10 +68,6 @@ public class PullToRefreshExpandableListView extends PullToRefreshAdapterViewBas
super(context, attrs); super(context, attrs);
} }
public ContextMenuInfo getContextMenuInfo() {
return super.getContextMenuInfo();
}
@Override @Override
public void setEmptyView(View emptyView) { public void setEmptyView(View emptyView) {
PullToRefreshExpandableListView.this.setEmptyView(emptyView); PullToRefreshExpandableListView.this.setEmptyView(emptyView);
@ -95,7 +94,8 @@ public class PullToRefreshExpandableListView extends PullToRefreshAdapterViewBas
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
// Does all of the hard work... // Does all of the hard work...
OverscrollHelper.overScrollBy(PullToRefreshExpandableListView.this, deltaY, scrollY, isTouchEvent); OverscrollHelper.overScrollBy(PullToRefreshExpandableListView.this, deltaX, scrollX, deltaY, scrollY,
isTouchEvent);
return returnValue; return returnValue;
} }

View File

@ -20,7 +20,6 @@ import android.content.Context;
import android.os.Build.VERSION; import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES; import android.os.Build.VERSION_CODES;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View; import android.view.View;
import android.widget.GridView; import android.widget.GridView;
@ -40,9 +39,13 @@ public class PullToRefreshGridView extends PullToRefreshAdapterViewBase<GridView
super(context, mode); super(context, mode);
} }
public PullToRefreshGridView(Context context, Mode mode, AnimationStyle style) {
super(context, mode, style);
}
@Override @Override
public ContextMenuInfo getContextMenuInfo() { public final Orientation getPullToRefreshScrollDirection() {
return ((InternalGridView) getRefreshableView()).getContextMenuInfo(); return Orientation.VERTICAL;
} }
@Override @Override
@ -65,11 +68,6 @@ public class PullToRefreshGridView extends PullToRefreshAdapterViewBase<GridView
super(context, attrs); super(context, attrs);
} }
@Override
public ContextMenuInfo getContextMenuInfo() {
return super.getContextMenuInfo();
}
@Override @Override
public void setEmptyView(View emptyView) { public void setEmptyView(View emptyView) {
PullToRefreshGridView.this.setEmptyView(emptyView); PullToRefreshGridView.this.setEmptyView(emptyView);
@ -96,7 +94,7 @@ public class PullToRefreshGridView extends PullToRefreshAdapterViewBase<GridView
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
// Does all of the hard work... // Does all of the hard work...
OverscrollHelper.overScrollBy(PullToRefreshGridView.this, deltaY, scrollY, isTouchEvent); OverscrollHelper.overScrollBy(PullToRefreshGridView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent);
return returnValue; return returnValue;
} }

View File

@ -0,0 +1,110 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.library;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.view.View;
import android.widget.HorizontalScrollView;
public class PullToRefreshHorizontalScrollView extends PullToRefreshBase<HorizontalScrollView> {
public PullToRefreshHorizontalScrollView(Context context) {
super(context);
}
public PullToRefreshHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PullToRefreshHorizontalScrollView(Context context, Mode mode) {
super(context, mode);
}
public PullToRefreshHorizontalScrollView(Context context, Mode mode, AnimationStyle style) {
super(context, mode, style);
}
@Override
public final Orientation getPullToRefreshScrollDirection() {
return Orientation.HORIZONTAL;
}
@Override
protected HorizontalScrollView createRefreshableView(Context context, AttributeSet attrs) {
HorizontalScrollView scrollView;
if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
scrollView = new InternalHorizontalScrollViewSDK9(context, attrs);
} else {
scrollView = new HorizontalScrollView(context, attrs);
}
scrollView.setId(R.id.scrollview);
return scrollView;
}
@Override
protected boolean isReadyForPullStart() {
return mRefreshableView.getScrollX() == 0;
}
@Override
protected boolean isReadyForPullEnd() {
View scrollViewChild = mRefreshableView.getChildAt(0);
if (null != scrollViewChild) {
return mRefreshableView.getScrollX() >= (scrollViewChild.getWidth() - getWidth());
}
return false;
}
@TargetApi(9)
final class InternalHorizontalScrollViewSDK9 extends HorizontalScrollView {
public InternalHorizontalScrollViewSDK9(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
// Does all of the hard work...
OverscrollHelper.overScrollBy(PullToRefreshHorizontalScrollView.this, deltaX, scrollX, deltaY, scrollY,
getScrollRange(), isTouchEvent);
return returnValue;
}
/**
* Taken from the AOSP ScrollView source
*/
private int getScrollRange() {
int scrollRange = 0;
if (getChildCount() > 0) {
View child = getChildAt(0);
scrollRange = Math.max(0, child.getWidth() - (getWidth() - getPaddingLeft() - getPaddingRight()));
}
return scrollRange;
}
}
}

View File

@ -19,11 +19,11 @@ import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION; import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES; import android.os.Build.VERSION_CODES;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ListAdapter; import android.widget.ListAdapter;
@ -39,124 +39,80 @@ public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView
private FrameLayout mLvFooterLoadingFrame; private FrameLayout mLvFooterLoadingFrame;
private boolean mListViewExtrasEnabled;
public PullToRefreshListView(Context context) { public PullToRefreshListView(Context context) {
super(context); super(context);
setDisableScrollingWhileRefreshing(false);
} }
public PullToRefreshListView(Context context, AttributeSet attrs) { public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
setDisableScrollingWhileRefreshing(false);
} }
public PullToRefreshListView(Context context, Mode mode) { public PullToRefreshListView(Context context, Mode mode) {
super(context, mode); super(context, mode);
setDisableScrollingWhileRefreshing(false); }
public PullToRefreshListView(Context context, Mode mode, AnimationStyle style) {
super(context, mode, style);
} }
@Override @Override
public ContextMenuInfo getContextMenuInfo() { public final Orientation getPullToRefreshScrollDirection() {
return ((InternalListView) getRefreshableView()).getContextMenuInfo(); return Orientation.VERTICAL;
} }
@Override @Override
public void setLastUpdatedLabel(CharSequence label) { protected void onRefreshing(final boolean doScroll) {
super.setLastUpdatedLabel(label); /**
* If we're not showing the Refreshing view, or the list is empty, the
if (null != mHeaderLoadingView) { * the header/footer views won't show so we use the normal method.
mHeaderLoadingView.setSubHeaderText(label); */
}
if (null != mFooterLoadingView) {
mFooterLoadingView.setSubHeaderText(label);
}
}
@Override
public void setLoadingDrawable(Drawable drawable, Mode mode) {
super.setLoadingDrawable(drawable, mode);
if (null != mHeaderLoadingView && mode.canPullDown()) {
mHeaderLoadingView.setLoadingDrawable(drawable);
}
if (null != mFooterLoadingView && mode.canPullUp()) {
mFooterLoadingView.setLoadingDrawable(drawable);
}
}
public void setPullLabel(CharSequence pullLabel, Mode mode) {
super.setPullLabel(pullLabel, mode);
if (null != mHeaderLoadingView && mode.canPullDown()) {
mHeaderLoadingView.setPullLabel(pullLabel);
}
if (null != mFooterLoadingView && mode.canPullUp()) {
mFooterLoadingView.setPullLabel(pullLabel);
}
}
public void setRefreshingLabel(CharSequence refreshingLabel, Mode mode) {
super.setRefreshingLabel(refreshingLabel, mode);
if (null != mHeaderLoadingView && mode.canPullDown()) {
mHeaderLoadingView.setRefreshingLabel(refreshingLabel);
}
if (null != mFooterLoadingView && mode.canPullUp()) {
mFooterLoadingView.setRefreshingLabel(refreshingLabel);
}
}
public void setReleaseLabel(CharSequence releaseLabel, Mode mode) {
super.setReleaseLabel(releaseLabel, mode);
if (null != mHeaderLoadingView && mode.canPullDown()) {
mHeaderLoadingView.setReleaseLabel(releaseLabel);
}
if (null != mFooterLoadingView && mode.canPullUp()) {
mFooterLoadingView.setReleaseLabel(releaseLabel);
}
}
@Override
void onRefreshing(final boolean doScroll) {
// If we're not showing the Refreshing view, or the list is empty, then
// the header/footer views won't show so we use the
// normal method
ListAdapter adapter = mRefreshableView.getAdapter(); ListAdapter adapter = mRefreshableView.getAdapter();
if (!getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) { if (!mListViewExtrasEnabled || !getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) {
super.onRefreshing(doScroll); super.onRefreshing(doScroll);
return; return;
} }
super.onRefreshing(false); super.onRefreshing(false);
final LoadingLayout originalLoadingLayout, listViewLoadingLayout; final LoadingLayout origLoadingView, listViewLoadingView, oppositeListViewLoadingView;
final int selection, scrollToY; final int selection, scrollToY;
switch (getCurrentMode()) { switch (getCurrentMode()) {
case PULL_UP_TO_REFRESH: case MANUAL_REFRESH_ONLY:
originalLoadingLayout = getFooterLayout(); case PULL_FROM_END:
listViewLoadingLayout = mFooterLoadingView; origLoadingView = getFooterLayout();
listViewLoadingView = mFooterLoadingView;
oppositeListViewLoadingView = mHeaderLoadingView;
selection = mRefreshableView.getCount() - 1; selection = mRefreshableView.getCount() - 1;
scrollToY = getScrollY() - getFooterHeight(); scrollToY = getScrollY() - getFooterSize();
break; break;
case PULL_DOWN_TO_REFRESH: case PULL_FROM_START:
default: default:
originalLoadingLayout = getHeaderLayout(); origLoadingView = getHeaderLayout();
listViewLoadingLayout = mHeaderLoadingView; listViewLoadingView = mHeaderLoadingView;
oppositeListViewLoadingView = mFooterLoadingView;
selection = 0; selection = 0;
scrollToY = getScrollY() + getHeaderHeight(); scrollToY = getScrollY() + getHeaderSize();
break; break;
} }
// Hide our original Loading View // Hide our original Loading View
originalLoadingLayout.setVisibility(View.INVISIBLE); origLoadingView.reset();
origLoadingView.hideAllViews();
// Show the ListView Loading View and set it to refresh // Make sure the opposite end is hidden too
listViewLoadingLayout.setVisibility(View.VISIBLE); oppositeListViewLoadingView.setVisibility(View.GONE);
listViewLoadingLayout.refreshing();
// Show the ListView Loading View and set it to refresh.
listViewLoadingView.setVisibility(View.VISIBLE);
listViewLoadingView.refreshing();
if (doScroll) { if (doScroll) {
// We need to disable the automatic visibility changes for now
disableLoadingLayoutVisibilityChanges();
// We scroll slightly so that the ListView's header/footer is at the // We scroll slightly so that the ListView's header/footer is at the
// same Y position as our normal header/footer // same Y position as our normal header/footer
setHeaderScroll(scrollToY); setHeaderScroll(scrollToY);
@ -171,59 +127,81 @@ public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView
} }
@Override @Override
void onReset() { protected void onReset() {
/**
// If we're not showing the Refreshing view, or the list is empty, then * If the extras are not enabled, just call up to super and return.
// the header/footer views won't show so we use the */
// normal method if (!mListViewExtrasEnabled) {
ListAdapter adapter = mRefreshableView.getAdapter();
if (!getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) {
super.onReset(); super.onReset();
return; return;
} }
LoadingLayout originalLoadingLayout, listViewLoadingLayout; final LoadingLayout originalLoadingLayout, listViewLoadingLayout;
int scrollToHeight, selection; final int scrollToHeight, selection;
boolean scrollLvToEdge; final boolean scrollLvToEdge;
switch (getCurrentMode()) { switch (getCurrentMode()) {
case PULL_UP_TO_REFRESH: case MANUAL_REFRESH_ONLY:
case PULL_FROM_END:
originalLoadingLayout = getFooterLayout(); originalLoadingLayout = getFooterLayout();
listViewLoadingLayout = mFooterLoadingView; listViewLoadingLayout = mFooterLoadingView;
selection = mRefreshableView.getCount() - 1; selection = mRefreshableView.getCount() - 1;
scrollToHeight = getFooterHeight(); scrollToHeight = getFooterSize();
scrollLvToEdge = Math.abs(mRefreshableView.getLastVisiblePosition() - selection) <= 1; scrollLvToEdge = Math.abs(mRefreshableView.getLastVisiblePosition() - selection) <= 1;
break; break;
case PULL_DOWN_TO_REFRESH: case PULL_FROM_START:
default: default:
originalLoadingLayout = getHeaderLayout(); originalLoadingLayout = getHeaderLayout();
listViewLoadingLayout = mHeaderLoadingView; listViewLoadingLayout = mHeaderLoadingView;
scrollToHeight = -getHeaderHeight(); scrollToHeight = -getHeaderSize();
selection = 0; selection = 0;
scrollLvToEdge = Math.abs(mRefreshableView.getFirstVisiblePosition() - selection) <= 1; scrollLvToEdge = Math.abs(mRefreshableView.getFirstVisiblePosition() - selection) <= 1;
break; break;
} }
// Set our Original View to Visible // If the ListView header loading layout is showing, then we need to
originalLoadingLayout.setVisibility(View.VISIBLE); // flip so that the original one is showing instead
if (listViewLoadingLayout.getVisibility() == View.VISIBLE) {
/** // Set our Original View to Visible
* Scroll so the View is at the same Y as the ListView header/footer, originalLoadingLayout.showInvisibleViews();
* but only scroll if: we've pulled to refresh, it's positioned
* correctly, and we're currently showing the ListViewLoadingLayout // Hide the ListView Header/Footer
*/ listViewLoadingLayout.setVisibility(View.GONE);
if (scrollLvToEdge && getState() != State.MANUAL_REFRESHING
&& listViewLoadingLayout.getVisibility() == View.VISIBLE) { /**
mRefreshableView.setSelection(selection); * Scroll so the View is at the same Y as the ListView
setHeaderScroll(scrollToHeight); * header/footer, but only scroll if: we've pulled to refresh, it's
* positioned correctly
*/
if (scrollLvToEdge && getState() != State.MANUAL_REFRESHING) {
mRefreshableView.setSelection(selection);
setHeaderScroll(scrollToHeight);
}
} }
// Hide the ListView Header/Footer // Finally, call up to super
listViewLoadingLayout.setVisibility(View.GONE);
super.onReset(); super.onReset();
} }
@Override
protected LoadingLayoutProxy createLoadingLayoutProxy(final boolean includeStart, final boolean includeEnd) {
LoadingLayoutProxy proxy = super.createLoadingLayoutProxy(includeStart, includeEnd);
if (mListViewExtrasEnabled) {
final Mode mode = getMode();
if (includeStart && mode.showHeaderLoadingLayout()) {
proxy.addLayout(mHeaderLoadingView);
}
if (includeEnd && mode.showFooterLoadingLayout()) {
proxy.addLayout(mFooterLoadingView);
}
}
return proxy;
}
protected ListView createListView(Context context, AttributeSet attrs) { protected ListView createListView(Context context, AttributeSet attrs) {
final ListView lv; final ListView lv;
if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
@ -235,32 +213,46 @@ public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView
} }
@Override @Override
protected final ListView createRefreshableView(Context context, AttributeSet attrs) { protected ListView createRefreshableView(Context context, AttributeSet attrs) {
ListView lv = createListView(context, attrs); ListView lv = createListView(context, attrs);
// Get Styles from attrs
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullToRefresh);
// Create Loading Views ready for use later
FrameLayout frame = new FrameLayout(context);
mHeaderLoadingView = createLoadingLayout(context, Mode.PULL_DOWN_TO_REFRESH, a);
frame.addView(mHeaderLoadingView, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
mHeaderLoadingView.setVisibility(View.GONE);
lv.addHeaderView(frame, null, false);
mLvFooterLoadingFrame = new FrameLayout(context);
mFooterLoadingView = createLoadingLayout(context, Mode.PULL_UP_TO_REFRESH, a);
mLvFooterLoadingFrame.addView(mFooterLoadingView, FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
mFooterLoadingView.setVisibility(View.GONE);
a.recycle();
// Set it to this so it can be used in ListActivity/ListFragment // Set it to this so it can be used in ListActivity/ListFragment
lv.setId(android.R.id.list); lv.setId(android.R.id.list);
return lv; return lv;
} }
@Override
protected void handleStyledAttributes(TypedArray a) {
super.handleStyledAttributes(a);
mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true);
if (mListViewExtrasEnabled) {
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL);
// Create Loading Views ready for use later
FrameLayout frame = new FrameLayout(getContext());
mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a);
mHeaderLoadingView.setVisibility(View.GONE);
frame.addView(mHeaderLoadingView, lp);
mRefreshableView.addHeaderView(frame, null, false);
mLvFooterLoadingFrame = new FrameLayout(getContext());
mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a);
mFooterLoadingView.setVisibility(View.GONE);
mLvFooterLoadingFrame.addView(mFooterLoadingView, lp);
/**
* If the value for Scrolling While Refreshing hasn't been
* explicitly set via XML, enable Scrolling While Refreshing.
*/
if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) {
setScrollingWhileRefreshingEnabled(true);
}
}
}
@TargetApi(9) @TargetApi(9)
final class InternalListViewSDK9 extends InternalListView { final class InternalListViewSDK9 extends InternalListView {
@ -276,7 +268,7 @@ public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
// Does all of the hard work... // Does all of the hard work...
OverscrollHelper.overScrollBy(PullToRefreshListView.this, deltaY, scrollY, isTouchEvent); OverscrollHelper.overScrollBy(PullToRefreshListView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent);
return returnValue; return returnValue;
} }
@ -291,27 +283,38 @@ public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView
} }
@Override @Override
public void draw(Canvas canvas) { protected void dispatchDraw(Canvas canvas) {
/** /**
* This is a bit hacky, but ListView has got a bug in it when using * This is a bit hacky, but Samsung's ListView has got a bug in it
* Header/Footer Views and the list is empty. This masks the issue * when using Header/Footer Views and the list is empty. This masks
* so that it doesn't cause an FC. See Issue #66. * the issue so that it doesn't cause an FC. See Issue #66.
*/ */
try { try {
super.draw(canvas); super.dispatchDraw(canvas);
} catch (Exception e) { } catch (IndexOutOfBoundsException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public ContextMenuInfo getContextMenuInfo() { @Override
return super.getContextMenuInfo(); public boolean dispatchTouchEvent(MotionEvent ev) {
/**
* This is a bit hacky, but Samsung's ListView has got a bug in it
* when using Header/Footer Views and the list is empty. This masks
* the issue so that it doesn't cause an FC. See Issue #66.
*/
try {
return super.dispatchTouchEvent(ev);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
return false;
}
} }
@Override @Override
public void setAdapter(ListAdapter adapter) { public void setAdapter(ListAdapter adapter) {
// Add the Footer View at the last possible moment // Add the Footer View at the last possible moment
if (!mAddedLvFooter) { if (null != mLvFooterLoadingFrame && !mAddedLvFooter) {
addFooterView(mLvFooterLoadingFrame, null, false); addFooterView(mLvFooterLoadingFrame, null, false);
mAddedLvFooter = true; mAddedLvFooter = true;
} }

View File

@ -25,10 +25,27 @@ import android.widget.ScrollView;
public class PullToRefreshScrollView extends PullToRefreshBase<ScrollView> { public class PullToRefreshScrollView extends PullToRefreshBase<ScrollView> {
public PullToRefreshScrollView(Context context) {
super(context);
}
public PullToRefreshScrollView(Context context, AttributeSet attrs) { public PullToRefreshScrollView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
public PullToRefreshScrollView(Context context, Mode mode) {
super(context, mode);
}
public PullToRefreshScrollView(Context context, Mode mode, AnimationStyle style) {
super(context, mode, style);
}
@Override
public final Orientation getPullToRefreshScrollDirection() {
return Orientation.VERTICAL;
}
@Override @Override
protected ScrollView createRefreshableView(Context context, AttributeSet attrs) { protected ScrollView createRefreshableView(Context context, AttributeSet attrs) {
ScrollView scrollView; ScrollView scrollView;
@ -43,12 +60,12 @@ public class PullToRefreshScrollView extends PullToRefreshBase<ScrollView> {
} }
@Override @Override
protected boolean isReadyForPullDown() { protected boolean isReadyForPullStart() {
return mRefreshableView.getScrollY() == 0; return mRefreshableView.getScrollY() == 0;
} }
@Override @Override
protected boolean isReadyForPullUp() { protected boolean isReadyForPullEnd() {
View scrollViewChild = mRefreshableView.getChildAt(0); View scrollViewChild = mRefreshableView.getChildAt(0);
if (null != scrollViewChild) { if (null != scrollViewChild) {
return mRefreshableView.getScrollY() >= (scrollViewChild.getHeight() - getHeight()); return mRefreshableView.getScrollY() >= (scrollViewChild.getHeight() - getHeight());
@ -71,8 +88,8 @@ public class PullToRefreshScrollView extends PullToRefreshBase<ScrollView> {
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
// Does all of the hard work... // Does all of the hard work...
OverscrollHelper OverscrollHelper.overScrollBy(PullToRefreshScrollView.this, deltaX, scrollX, deltaY, scrollY,
.overScrollBy(PullToRefreshScrollView.this, deltaY, scrollY, getScrollRange(), isTouchEvent); getScrollRange(), isTouchEvent);
return returnValue; return returnValue;
} }

View File

@ -77,6 +77,21 @@ public class PullToRefreshWebView extends PullToRefreshBase<WebView> {
mRefreshableView.setWebChromeClient(defaultWebChromeClient); mRefreshableView.setWebChromeClient(defaultWebChromeClient);
} }
public PullToRefreshWebView(Context context, Mode mode, AnimationStyle style) {
super(context, mode, style);
/**
* Added so that by default, Pull-to-Refresh refreshes the page
*/
setOnRefreshListener(defaultOnRefreshListener);
mRefreshableView.setWebChromeClient(defaultWebChromeClient);
}
@Override
public final Orientation getPullToRefreshScrollDirection() {
return Orientation.VERTICAL;
}
@Override @Override
protected WebView createRefreshableView(Context context, AttributeSet attrs) { protected WebView createRefreshableView(Context context, AttributeSet attrs) {
WebView webView; WebView webView;
@ -91,12 +106,12 @@ public class PullToRefreshWebView extends PullToRefreshBase<WebView> {
} }
@Override @Override
protected boolean isReadyForPullDown() { protected boolean isReadyForPullStart() {
return mRefreshableView.getScrollY() == 0; return mRefreshableView.getScrollY() == 0;
} }
@Override @Override
protected boolean isReadyForPullUp() { protected boolean isReadyForPullEnd() {
float exactContentHeight = FloatMath.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale()); float exactContentHeight = FloatMath.floor(mRefreshableView.getContentHeight() * mRefreshableView.getScale());
return mRefreshableView.getScrollY() >= (exactContentHeight - mRefreshableView.getHeight()); return mRefreshableView.getScrollY() >= (exactContentHeight - mRefreshableView.getHeight());
} }
@ -136,8 +151,8 @@ public class PullToRefreshWebView extends PullToRefreshBase<WebView> {
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
// Does all of the hard work... // Does all of the hard work...
OverscrollHelper.overScrollBy(PullToRefreshWebView.this, deltaY, scrollY, getScrollRange(), OverscrollHelper.overScrollBy(PullToRefreshWebView.this, deltaX, scrollX, deltaY, scrollY,
OVERSCROLL_FUZZY_THRESHOLD, OVERSCROLL_SCALE_FACTOR, isTouchEvent); getScrollRange(), OVERSCROLL_FUZZY_THRESHOLD, OVERSCROLL_SCALE_FACTOR, isTouchEvent);
return returnValue; return returnValue;
} }

View File

@ -27,7 +27,7 @@ import com.handmark.pulltorefresh.library.PullToRefreshWebView;
* An advanced version of {@link PullToRefreshWebView} which delegates the * An advanced version of {@link PullToRefreshWebView} which delegates the
* triggering of the PullToRefresh gesture to the Javascript running within the * triggering of the PullToRefresh gesture to the Javascript running within the
* WebView. This means that you should only use this class if: * WebView. This means that you should only use this class if:
* * <p/>
* <ul> * <ul>
* <li>{@link PullToRefreshWebView} doesn't work correctly because you're using * <li>{@link PullToRefreshWebView} doesn't work correctly because you're using
* <code>overflow:scroll</code> or something else which means * <code>overflow:scroll</code> or something else which means
@ -35,14 +35,15 @@ import com.handmark.pulltorefresh.library.PullToRefreshWebView;
* <li>You control the web content being displayed, as you need to write some * <li>You control the web content being displayed, as you need to write some
* Javascript callbacks.</li> * Javascript callbacks.</li>
* </ul> * </ul>
* <p /> * <p/>
* * <p/>
* The way this call works is that when a PullToRefresh gesture is in action, * The way this call works is that when a PullToRefresh gesture is in action,
* the following Javascript methods will be called: * the following Javascript methods will be called:
* <code>isReadyForPullDown()</code> and <code>isReadyForPullUp()</code>, it is * <code>isReadyForPullDown()</code> and <code>isReadyForPullUp()</code>, it is
* your job to calculate whether the view is in a state where a PullToRefresh * your job to calculate whether the view is in a state where a PullToRefresh
* can happen, and return the result via the callback mechanism. An example can * can happen, and return the result via the callback mechanism. An example can
* be seen below: * be seen below:
* <p/>
* *
* <pre> * <pre>
* function isReadyForPullDown() { * function isReadyForPullDown() {
@ -92,7 +93,7 @@ public class PullToRefreshWebView2 extends PullToRefreshWebView {
} }
@Override @Override
protected boolean isReadyForPullDown() { protected boolean isReadyForPullStart() {
// Call Javascript... // Call Javascript...
getRefreshableView().loadUrl(DEF_JS_READY_PULL_DOWN_CALL); getRefreshableView().loadUrl(DEF_JS_READY_PULL_DOWN_CALL);
@ -103,7 +104,7 @@ public class PullToRefreshWebView2 extends PullToRefreshWebView {
} }
@Override @Override
protected boolean isReadyForPullUp() { protected boolean isReadyForPullEnd() {
// Call Javascript... // Call Javascript...
getRefreshableView().loadUrl(DEF_JS_READY_PULL_UP_CALL); getRefreshableView().loadUrl(DEF_JS_READY_PULL_UP_CALL);

View File

@ -35,8 +35,7 @@ public class SoundPullEventListener<V extends View> implements PullToRefreshBase
/** /**
* Constructor * Constructor
* *
* @param context * @param context - Context
* - Context
*/ */
public SoundPullEventListener(Context context) { public SoundPullEventListener(Context context) {
mContext = context; mContext = context;
@ -55,14 +54,12 @@ public class SoundPullEventListener<V extends View> implements PullToRefreshBase
* Set the Sounds to be played when a Pull Event happens. You specify which * Set the Sounds to be played when a Pull Event happens. You specify which
* sound plays for which events by calling this method multiple times for * sound plays for which events by calling this method multiple times for
* each event. * each event.
* * <p/>
* If you've already set a sound for a certain event, and add another sound * If you've already set a sound for a certain event, and add another sound
* for that event, only the new sound will be played. * for that event, only the new sound will be played.
* *
* @param event * @param event - The event for which the sound will be played.
* - The event for which the sound will be played. * @param resId - Resource Id of the sound file to be played (e.g.
* @param resId
* - Resource Id of the sound file to be played (e.g.
* <var>R.raw.pull_sound</var>) * <var>R.raw.pull_sound</var>)
*/ */
public void addSoundEvent(State event, int resId) { public void addSoundEvent(State event, int resId) {

View File

@ -28,8 +28,7 @@ public interface EmptyViewMethodAccessor {
/** /**
* Calls upto AdapterView.setEmptyView() * Calls upto AdapterView.setEmptyView()
* *
* @param View * @param emptyView - to set as Empty View
* to set as Empty View
*/ */
public void setEmptyViewInternal(View emptyView); public void setEmptyViewInternal(View emptyView);
@ -37,8 +36,7 @@ public interface EmptyViewMethodAccessor {
* Should call PullToRefreshBase.setEmptyView() which will then * Should call PullToRefreshBase.setEmptyView() which will then
* automatically call through to setEmptyViewInternal() * automatically call through to setEmptyViewInternal()
* *
* @param View * @param emptyView - to set as Empty View
* to set as Empty View
*/ */
public void setEmptyView(View emptyView); public void setEmptyView(View emptyView);

View File

@ -15,30 +15,35 @@
*******************************************************************************/ *******************************************************************************/
package com.handmark.pulltorefresh.library.internal; package com.handmark.pulltorefresh.library.internal;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.RotateAnimation; import android.view.animation.RotateAnimation;
import android.widget.ImageView.ScaleType;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode; import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
import com.handmark.pulltorefresh.library.R; import com.handmark.pulltorefresh.library.R;
@SuppressLint("ViewConstructor")
public class FlipLoadingLayout extends LoadingLayout { public class FlipLoadingLayout extends LoadingLayout {
static final int FLIP_ANIMATION_DURATION = 150; static final int FLIP_ANIMATION_DURATION = 150;
private final Animation mRotateAnimation, mResetRotateAnimation; private final Animation mRotateAnimation, mResetRotateAnimation;
public FlipLoadingLayout(Context context, Mode mode, TypedArray attrs) { public FlipLoadingLayout(Context context, final Mode mode, final Orientation scrollDirection, TypedArray attrs) {
super(context, mode, attrs); super(context, mode, scrollDirection, attrs);
final int rotateAngle = mode == Mode.PULL_DOWN_TO_REFRESH ? 180 : -180; final int rotateAngle = mode == Mode.PULL_FROM_START ? -180 : 180;
mRotateAnimation = new RotateAnimation(0, rotateAngle, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, mRotateAnimation = new RotateAnimation(0, rotateAngle, Animation.RELATIVE_TO_SELF, 0.5f,
0.5f); Animation.RELATIVE_TO_SELF, 0.5f);
mRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR); mRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR);
mRotateAnimation.setDuration(FLIP_ANIMATION_DURATION); mRotateAnimation.setDuration(FLIP_ANIMATION_DURATION);
mRotateAnimation.setFillAfter(true); mRotateAnimation.setFillAfter(true);
@ -52,20 +57,33 @@ public class FlipLoadingLayout extends LoadingLayout {
@Override @Override
protected void onLoadingDrawableSet(Drawable imageDrawable) { protected void onLoadingDrawableSet(Drawable imageDrawable) {
/**
* We need to set the width/height of the ImageView so that it is square
* with each side the size of the largest drawable dimension. This is so
* that it doesn't clip when rotated.
*/
if (null != imageDrawable) { if (null != imageDrawable) {
final int dHeight = imageDrawable.getIntrinsicHeight();
final int dWidth = imageDrawable.getIntrinsicWidth();
/**
* We need to set the width/height of the ImageView so that it is
* square with each side the size of the largest drawable dimension.
* This is so that it doesn't clip when rotated.
*/
ViewGroup.LayoutParams lp = mHeaderImage.getLayoutParams(); ViewGroup.LayoutParams lp = mHeaderImage.getLayoutParams();
lp.width = lp.height = Math.max(imageDrawable.getIntrinsicWidth(), imageDrawable.getIntrinsicHeight()); lp.width = lp.height = Math.max(dHeight, dWidth);
mHeaderImage.requestLayout(); mHeaderImage.requestLayout();
/**
* We now rotate the Drawable so that is at the correct rotation,
* and is centered.
*/
mHeaderImage.setScaleType(ScaleType.MATRIX);
Matrix matrix = new Matrix();
matrix.postTranslate((lp.width - dWidth) / 2f, (lp.height - dHeight) / 2f);
matrix.postRotate(getDrawableRotationAngle(), lp.width / 2f, lp.height / 2f);
mHeaderImage.setImageMatrix(matrix);
} }
} }
@Override @Override
protected void onPullYImpl(float scaleOfHeight) { protected void onPullImpl(float scaleOfLayout) {
// NO-OP // NO-OP
} }
@ -97,13 +115,32 @@ public class FlipLoadingLayout extends LoadingLayout {
} }
@Override @Override
protected int getDefaultTopDrawableResId() { protected int getDefaultDrawableResId() {
return R.drawable.default_ptr_flip_top; return R.drawable.default_ptr_flip;
} }
@Override private float getDrawableRotationAngle() {
protected int getDefaultBottomDrawableResId() { float angle = 0f;
return R.drawable.default_ptr_flip_bottom; switch (mMode) {
case PULL_FROM_END:
if (mScrollDirection == Orientation.HORIZONTAL) {
angle = 90f;
} else {
angle = 180f;
}
break;
case PULL_FROM_START:
if (mScrollDirection == Orientation.HORIZONTAL) {
angle = 270f;
}
break;
default:
break;
}
return angle;
} }
} }

View File

@ -15,7 +15,10 @@
*******************************************************************************/ *******************************************************************************/
package com.handmark.pulltorefresh.library.internal; package com.handmark.pulltorefresh.library.internal;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener; import android.view.animation.Animation.AnimationListener;
@ -25,10 +28,12 @@ import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation; import android.view.animation.RotateAnimation;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import com.handmark.pulltorefresh.library.PullToRefreshBase; import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.R; import com.handmark.pulltorefresh.library.R;
@SuppressLint("ViewConstructor")
public class IndicatorLayout extends FrameLayout implements AnimationListener { public class IndicatorLayout extends FrameLayout implements AnimationListener {
static final int DEFAULT_ROTATION_ANIMATION_DURATION = 150; static final int DEFAULT_ROTATION_ANIMATION_DURATION = 150;
@ -40,26 +45,33 @@ public class IndicatorLayout extends FrameLayout implements AnimationListener {
public IndicatorLayout(Context context, PullToRefreshBase.Mode mode) { public IndicatorLayout(Context context, PullToRefreshBase.Mode mode) {
super(context); super(context);
mArrowImageView = new ImageView(context); mArrowImageView = new ImageView(context);
Drawable arrowD = getResources().getDrawable(R.drawable.indicator_arrow);
mArrowImageView.setImageDrawable(arrowD);
final int padding = getResources().getDimensionPixelSize(R.dimen.indicator_internal_padding); final int padding = getResources().getDimensionPixelSize(R.dimen.indicator_internal_padding);
mArrowImageView.setPadding(padding, padding, padding, padding); mArrowImageView.setPadding(padding, padding, padding, padding);
addView(mArrowImageView); addView(mArrowImageView);
int inAnimResId, outAnimResId; int inAnimResId, outAnimResId;
switch (mode) { switch (mode) {
case PULL_UP_TO_REFRESH: case PULL_FROM_END:
inAnimResId = R.anim.slide_in_from_bottom; inAnimResId = R.anim.slide_in_from_bottom;
outAnimResId = R.anim.slide_out_to_bottom; outAnimResId = R.anim.slide_out_to_bottom;
setBackgroundResource(R.drawable.indicator_bg_bottom); setBackgroundResource(R.drawable.indicator_bg_bottom);
mArrowImageView.setImageResource(R.drawable.arrow_up);
// Rotate Arrow so it's pointing the correct way
mArrowImageView.setScaleType(ScaleType.MATRIX);
Matrix matrix = new Matrix();
matrix.setRotate(180f, arrowD.getIntrinsicWidth() / 2f, arrowD.getIntrinsicHeight() / 2f);
mArrowImageView.setImageMatrix(matrix);
break; break;
default: default:
case PULL_DOWN_TO_REFRESH: case PULL_FROM_START:
inAnimResId = R.anim.slide_in_from_top; inAnimResId = R.anim.slide_in_from_top;
outAnimResId = R.anim.slide_out_to_top; outAnimResId = R.anim.slide_out_to_top;
setBackgroundResource(R.drawable.indicator_bg_top); setBackgroundResource(R.drawable.indicator_bg_top);
mArrowImageView.setImageResource(R.drawable.arrow_down);
break; break;
} }

View File

@ -15,10 +15,11 @@
*******************************************************************************/ *******************************************************************************/
package com.handmark.pulltorefresh.library.internal; package com.handmark.pulltorefresh.library.internal;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Color; import android.graphics.Typeface;
import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
@ -26,57 +27,80 @@ import android.util.TypedValue;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator; import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator; import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import com.handmark.pulltorefresh.library.ILoadingLayout;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode; import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
import com.handmark.pulltorefresh.library.R; import com.handmark.pulltorefresh.library.R;
public abstract class LoadingLayout extends LinearLayout { @SuppressLint("ViewConstructor")
public abstract class LoadingLayout extends FrameLayout implements ILoadingLayout {
static final String LOG_TAG = "PullToRefresh-LoadingLayout";
static final Interpolator ANIMATION_INTERPOLATOR = new LinearInterpolator(); static final Interpolator ANIMATION_INTERPOLATOR = new LinearInterpolator();
private FrameLayout mInnerLayout;
protected final ImageView mHeaderImage; protected final ImageView mHeaderImage;
protected final ProgressBar mHeaderProgress; protected final ProgressBar mHeaderProgress;
private boolean mUseIntrinisicAnimation; private boolean mUseIntrinsicAnimation;
private final TextView mHeaderText; private final TextView mHeaderText;
private final TextView mSubHeaderText; private final TextView mSubHeaderText;
protected final Mode mMode;
protected final Orientation mScrollDirection;
private CharSequence mPullLabel; private CharSequence mPullLabel;
private CharSequence mRefreshingLabel; private CharSequence mRefreshingLabel;
private CharSequence mReleaseLabel; private CharSequence mReleaseLabel;
public LoadingLayout(Context context, final Mode mode, TypedArray attrs) { public LoadingLayout(Context context, final Mode mode, final Orientation scrollDirection, TypedArray attrs) {
super(context); super(context);
mMode = mode;
mScrollDirection = scrollDirection;
setGravity(Gravity.CENTER_VERTICAL); switch (scrollDirection) {
case HORIZONTAL:
LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_horizontal, this);
break;
case VERTICAL:
default:
LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_vertical, this);
break;
}
final int tbPadding = getResources().getDimensionPixelSize(R.dimen.header_footer_top_bottom_padding); mInnerLayout = (FrameLayout) findViewById(R.id.fl_inner);
final int lrPadding = getResources().getDimensionPixelSize(R.dimen.header_footer_left_right_padding); mHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_text);
setPadding(lrPadding, tbPadding, lrPadding, tbPadding); mHeaderProgress = (ProgressBar) mInnerLayout.findViewById(R.id.pull_to_refresh_progress);
mSubHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_sub_text);
mHeaderImage = (ImageView) mInnerLayout.findViewById(R.id.pull_to_refresh_image);
LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header, this); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mInnerLayout.getLayoutParams();
mHeaderText = (TextView) findViewById(R.id.pull_to_refresh_text);
mHeaderProgress = (ProgressBar) findViewById(R.id.pull_to_refresh_progress);
mSubHeaderText = (TextView) findViewById(R.id.pull_to_refresh_sub_text);
mHeaderImage = (ImageView) findViewById(R.id.pull_to_refresh_image);
switch (mode) { switch (mode) {
case PULL_UP_TO_REFRESH: case PULL_FROM_END:
lp.gravity = scrollDirection == Orientation.VERTICAL ? Gravity.TOP : Gravity.LEFT;
// Load in labels // Load in labels
mPullLabel = context.getString(R.string.pull_to_refresh_from_bottom_pull_label); mPullLabel = context.getString(R.string.pull_to_refresh_from_bottom_pull_label);
mRefreshingLabel = context.getString(R.string.pull_to_refresh_from_bottom_refreshing_label); mRefreshingLabel = context.getString(R.string.pull_to_refresh_from_bottom_refreshing_label);
mReleaseLabel = context.getString(R.string.pull_to_refresh_from_bottom_release_label); mReleaseLabel = context.getString(R.string.pull_to_refresh_from_bottom_release_label);
break; break;
case PULL_DOWN_TO_REFRESH: case PULL_FROM_START:
default: default:
lp.gravity = scrollDirection == Orientation.VERTICAL ? Gravity.BOTTOM : Gravity.RIGHT;
// Load in labels // Load in labels
mPullLabel = context.getString(R.string.pull_to_refresh_pull_label); mPullLabel = context.getString(R.string.pull_to_refresh_pull_label);
mRefreshingLabel = context.getString(R.string.pull_to_refresh_refreshing_label); mRefreshingLabel = context.getString(R.string.pull_to_refresh_refreshing_label);
@ -84,18 +108,10 @@ public abstract class LoadingLayout extends LinearLayout {
break; break;
} }
if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderTextColor)) {
ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderTextColor);
setTextColor(null != colors ? colors : ColorStateList.valueOf(Color.BLACK));
}
if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderSubTextColor)) {
ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderSubTextColor);
setSubTextColor(null != colors ? colors : ColorStateList.valueOf(Color.BLACK));
}
if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderBackground)) { if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderBackground)) {
Drawable background = attrs.getDrawable(R.styleable.PullToRefresh_ptrHeaderBackground); Drawable background = attrs.getDrawable(R.styleable.PullToRefresh_ptrHeaderBackground);
if (null != background) { if (null != background) {
setBackgroundDrawable(background); ViewCompat.setBackground(this, background);
} }
} }
@ -110,6 +126,20 @@ public abstract class LoadingLayout extends LinearLayout {
setSubTextAppearance(styleID.data); setSubTextAppearance(styleID.data);
} }
// Text Color attrs need to be set after TextAppearance attrs
if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderTextColor)) {
ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderTextColor);
if (null != colors) {
setTextColor(colors);
}
}
if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderSubTextColor)) {
ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderSubTextColor);
if (null != colors) {
setSubTextColor(colors);
}
}
// Try and get defined drawable from Attrs // Try and get defined drawable from Attrs
Drawable imageDrawable = null; Drawable imageDrawable = null;
if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawable)) { if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawable)) {
@ -118,19 +148,30 @@ public abstract class LoadingLayout extends LinearLayout {
// Check Specific Drawable from Attrs, these overrite the generic // Check Specific Drawable from Attrs, these overrite the generic
// drawable attr above // drawable attr above
if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableTop) && mode == Mode.PULL_DOWN_TO_REFRESH) { switch (mode) {
imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableTop); case PULL_FROM_START:
} else if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableBottom) && mode == Mode.PULL_UP_TO_REFRESH) { default:
imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableTop); if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableStart)) {
imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableStart);
} else if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableTop)) {
Utils.warnDeprecation("ptrDrawableTop", "ptrDrawableStart");
imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableTop);
}
break;
case PULL_FROM_END:
if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableEnd)) {
imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableEnd);
} else if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableBottom)) {
Utils.warnDeprecation("ptrDrawableBottom", "ptrDrawableEnd");
imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableBottom);
}
break;
} }
// If we don't have a user defined drawable, load the default // If we don't have a user defined drawable, load the default
if (null == imageDrawable) { if (null == imageDrawable) {
if (mode == Mode.PULL_DOWN_TO_REFRESH) { imageDrawable = context.getResources().getDrawable(getDefaultDrawableResId());
imageDrawable = context.getResources().getDrawable(getDefaultBottomDrawableResId());
} else {
imageDrawable = context.getResources().getDrawable(getDefaultTopDrawableResId());
}
} }
// Set Drawable, and save width/height // Set Drawable, and save width/height
@ -139,61 +180,115 @@ public abstract class LoadingLayout extends LinearLayout {
reset(); reset();
} }
public final void onPullY(float scaleOfHeight) { public final void setHeight(int height) {
if (!mUseIntrinisicAnimation) { ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) getLayoutParams();
onPullYImpl(scaleOfHeight); lp.height = height;
requestLayout();
}
public final void setWidth(int width) {
ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) getLayoutParams();
lp.width = width;
requestLayout();
}
public final int getContentSize() {
switch (mScrollDirection) {
case HORIZONTAL:
return mInnerLayout.getWidth();
case VERTICAL:
default:
return mInnerLayout.getHeight();
}
}
public final void hideAllViews() {
if (View.VISIBLE == mHeaderText.getVisibility()) {
mHeaderText.setVisibility(View.INVISIBLE);
}
if (View.VISIBLE == mHeaderProgress.getVisibility()) {
mHeaderProgress.setVisibility(View.INVISIBLE);
}
if (View.VISIBLE == mHeaderImage.getVisibility()) {
mHeaderImage.setVisibility(View.INVISIBLE);
}
if (View.VISIBLE == mSubHeaderText.getVisibility()) {
mSubHeaderText.setVisibility(View.INVISIBLE);
}
}
public final void onPull(float scaleOfLayout) {
if (!mUseIntrinsicAnimation) {
onPullImpl(scaleOfLayout);
} }
} }
public final void pullToRefresh() { public final void pullToRefresh() {
mHeaderText.setText(mPullLabel); if (null != mHeaderText) {
mHeaderText.setText(mPullLabel);
}
// Now call the callback // Now call the callback
pullToRefreshImpl(); pullToRefreshImpl();
} }
public final void refreshing() { public final void refreshing() {
mHeaderText.setText(mRefreshingLabel); if (null != mHeaderText) {
mHeaderText.setText(mRefreshingLabel);
}
if (mUseIntrinisicAnimation) { if (mUseIntrinsicAnimation) {
((AnimationDrawable) mHeaderImage.getDrawable()).start(); ((AnimationDrawable) mHeaderImage.getDrawable()).start();
} else { } else {
// Now call the callback // Now call the callback
refreshingImpl(); refreshingImpl();
} }
mSubHeaderText.setVisibility(View.GONE); if (null != mSubHeaderText) {
mSubHeaderText.setVisibility(View.GONE);
}
} }
public final void releaseToRefresh() { public final void releaseToRefresh() {
mHeaderText.setText(mReleaseLabel); if (null != mHeaderText) {
mHeaderText.setText(mReleaseLabel);
}
// Now call the callback // Now call the callback
releaseToRefreshImpl(); releaseToRefreshImpl();
} }
public final void reset() { public final void reset() {
mHeaderText.setText(mPullLabel); if (null != mHeaderText) {
mHeaderText.setText(mPullLabel);
}
mHeaderImage.setVisibility(View.VISIBLE); mHeaderImage.setVisibility(View.VISIBLE);
if (mUseIntrinisicAnimation) { if (mUseIntrinsicAnimation) {
((AnimationDrawable) mHeaderImage.getDrawable()).stop(); ((AnimationDrawable) mHeaderImage.getDrawable()).stop();
} else { } else {
// Now call the callback // Now call the callback
resetImpl(); resetImpl();
} }
if (TextUtils.isEmpty(mSubHeaderText.getText())) { if (null != mSubHeaderText) {
mSubHeaderText.setVisibility(View.GONE); if (TextUtils.isEmpty(mSubHeaderText.getText())) {
} else { mSubHeaderText.setVisibility(View.GONE);
mSubHeaderText.setVisibility(View.VISIBLE); } else {
mSubHeaderText.setVisibility(View.VISIBLE);
}
} }
} }
@Override
public void setLastUpdatedLabel(CharSequence label) {
setSubHeaderText(label);
}
public final void setLoadingDrawable(Drawable imageDrawable) { public final void setLoadingDrawable(Drawable imageDrawable) {
// Set Drawable // Set Drawable
mHeaderImage.setImageDrawable(imageDrawable); mHeaderImage.setImageDrawable(imageDrawable);
mUseIntrinisicAnimation = (imageDrawable instanceof AnimationDrawable); mUseIntrinsicAnimation = (imageDrawable instanceof AnimationDrawable);
// Now call the callback // Now call the callback
onLoadingDrawableSet(imageDrawable); onLoadingDrawableSet(imageDrawable);
@ -211,52 +306,35 @@ public abstract class LoadingLayout extends LinearLayout {
mReleaseLabel = releaseLabel; mReleaseLabel = releaseLabel;
} }
public void setSubHeaderText(CharSequence label) { @Override
if (TextUtils.isEmpty(label)) { public void setTextTypeface(Typeface tf) {
mSubHeaderText.setVisibility(View.GONE); mHeaderText.setTypeface(tf);
} else { }
mSubHeaderText.setText(label);
public final void showInvisibleViews() {
if (View.INVISIBLE == mHeaderText.getVisibility()) {
mHeaderText.setVisibility(View.VISIBLE);
}
if (View.INVISIBLE == mHeaderProgress.getVisibility()) {
mHeaderProgress.setVisibility(View.VISIBLE);
}
if (View.INVISIBLE == mHeaderImage.getVisibility()) {
mHeaderImage.setVisibility(View.VISIBLE);
}
if (View.INVISIBLE == mSubHeaderText.getVisibility()) {
mSubHeaderText.setVisibility(View.VISIBLE); mSubHeaderText.setVisibility(View.VISIBLE);
} }
} }
public void setSubTextAppearance(int value) {
mSubHeaderText.setTextAppearance(getContext(), value);
}
public void setSubTextColor(ColorStateList color) {
mSubHeaderText.setTextColor(color);
}
public void setSubTextColor(int color) {
setSubTextColor(ColorStateList.valueOf(color));
}
public void setTextAppearance(int value) {
mHeaderText.setTextAppearance(getContext(), value);
mSubHeaderText.setTextAppearance(getContext(), value);
}
public void setTextColor(ColorStateList color) {
mHeaderText.setTextColor(color);
mSubHeaderText.setTextColor(color);
}
public void setTextColor(int color) {
setTextColor(ColorStateList.valueOf(color));
}
/** /**
* Callbacks for derivative Layouts * Callbacks for derivative Layouts
*/ */
protected abstract int getDefaultBottomDrawableResId(); protected abstract int getDefaultDrawableResId();
protected abstract int getDefaultTopDrawableResId();
protected abstract void onLoadingDrawableSet(Drawable imageDrawable); protected abstract void onLoadingDrawableSet(Drawable imageDrawable);
protected abstract void onPullYImpl(float scaleOfHeight); protected abstract void onPullImpl(float scaleOfLayout);
protected abstract void pullToRefreshImpl(); protected abstract void pullToRefreshImpl();
@ -266,4 +344,45 @@ public abstract class LoadingLayout extends LinearLayout {
protected abstract void resetImpl(); protected abstract void resetImpl();
private void setSubHeaderText(CharSequence label) {
if (null != mSubHeaderText) {
if (TextUtils.isEmpty(label)) {
mSubHeaderText.setVisibility(View.GONE);
} else {
mSubHeaderText.setText(label);
mSubHeaderText.setVisibility(View.VISIBLE);
}
}
}
private void setSubTextAppearance(int value) {
if (null != mSubHeaderText) {
mSubHeaderText.setTextAppearance(getContext(), value);
}
}
private void setSubTextColor(ColorStateList color) {
if (null != mSubHeaderText) {
mSubHeaderText.setTextColor(color);
}
}
private void setTextAppearance(int value) {
if (null != mHeaderText) {
mHeaderText.setTextAppearance(getContext(), value);
}
if (null != mSubHeaderText) {
mSubHeaderText.setTextAppearance(getContext(), value);
}
}
private void setTextColor(ColorStateList color) {
if (null != mHeaderText) {
mHeaderText.setTextColor(color);
}
if (null != mSubHeaderText) {
mSubHeaderText.setTextColor(color);
}
}
} }

View File

@ -24,6 +24,7 @@ import android.view.animation.RotateAnimation;
import android.widget.ImageView.ScaleType; import android.widget.ImageView.ScaleType;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode; import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
import com.handmark.pulltorefresh.library.R; import com.handmark.pulltorefresh.library.R;
public class RotateLoadingLayout extends LoadingLayout { public class RotateLoadingLayout extends LoadingLayout {
@ -35,8 +36,12 @@ public class RotateLoadingLayout extends LoadingLayout {
private float mRotationPivotX, mRotationPivotY; private float mRotationPivotX, mRotationPivotY;
public RotateLoadingLayout(Context context, Mode mode, TypedArray attrs) { private final boolean mRotateDrawableWhilePulling;
super(context, mode, attrs);
public RotateLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) {
super(context, mode, scrollDirection, attrs);
mRotateDrawableWhilePulling = attrs.getBoolean(R.styleable.PullToRefresh_ptrRotateDrawableWhilePulling, true);
mHeaderImage.setScaleType(ScaleType.MATRIX); mHeaderImage.setScaleType(ScaleType.MATRIX);
mHeaderImageMatrix = new Matrix(); mHeaderImageMatrix = new Matrix();
@ -57,8 +62,15 @@ public class RotateLoadingLayout extends LoadingLayout {
} }
} }
protected void onPullYImpl(float scaleOfHeight) { protected void onPullImpl(float scaleOfLayout) {
mHeaderImageMatrix.setRotate(scaleOfHeight * 90, mRotationPivotX, mRotationPivotY); float angle;
if (mRotateDrawableWhilePulling) {
angle = scaleOfLayout * 90f;
} else {
angle = Math.max(0f, Math.min(180f, scaleOfLayout * 360f - 180f));
}
mHeaderImageMatrix.setRotate(angle, mRotationPivotX, mRotationPivotY);
mHeaderImage.setImageMatrix(mHeaderImageMatrix); mHeaderImage.setImageMatrix(mHeaderImageMatrix);
} }
@ -91,12 +103,7 @@ public class RotateLoadingLayout extends LoadingLayout {
} }
@Override @Override
protected int getDefaultTopDrawableResId() { protected int getDefaultDrawableResId() {
return R.drawable.default_ptr_rotate;
}
@Override
protected int getDefaultBottomDrawableResId() {
return R.drawable.default_ptr_rotate; return R.drawable.default_ptr_rotate;
} }

View File

@ -1,28 +0,0 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.library.internal;
import android.annotation.TargetApi;
import android.view.View;
@TargetApi(16)
public class SDK16 {
public static void postOnAnimation(View view, Runnable runnable) {
view.postOnAnimation(runnable);
}
}

View File

@ -0,0 +1,13 @@
package com.handmark.pulltorefresh.library.internal;
import android.util.Log;
public class Utils {
static final String LOG_TAG = "PullToRefresh";
public static void warnDeprecation(String depreacted, String replacement) {
Log.w(LOG_TAG, "You're using the deprecated " + depreacted + " attr, please switch over to " + replacement);
}
}

View File

@ -0,0 +1,70 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.library.internal;
import android.annotation.TargetApi;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.view.View;
@SuppressWarnings("deprecation")
public class ViewCompat {
public static void postOnAnimation(View view, Runnable runnable) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
SDK16.postOnAnimation(view, runnable);
} else {
view.postDelayed(runnable, 16);
}
}
public static void setBackground(View view, Drawable background) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
SDK16.setBackground(view, background);
} else {
view.setBackgroundDrawable(background);
}
}
public static void setLayerType(View view, int layerType) {
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
SDK11.setLayerType(view, layerType);
}
}
@TargetApi(11)
static class SDK11 {
public static void setLayerType(View view, int layerType) {
view.setLayerType(layerType, null);
}
}
@TargetApi(16)
static class SDK16 {
public static void postOnAnimation(View view, Runnable runnable) {
view.postOnAnimation(runnable);
}
public static void setBackground(View view, Drawable background) {
view.setBackground(background);
}
}
}

View File

@ -4,7 +4,7 @@
<groupId>com.github.chrisbanes.pulltorefresh</groupId> <groupId>com.github.chrisbanes.pulltorefresh</groupId>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>1.4.2</version> <version>2.1.1</version>
<name>Android-PullToRefresh Project</name> <name>Android-PullToRefresh Project</name>
<description>Implementation of the Pull-to-Refresh UI Pattern for Android.</description> <description>Implementation of the Pull-to-Refresh UI Pattern for Android.</description>
<url>https://github.com/chrisbanes/Android-PullToRefresh</url> <url>https://github.com/chrisbanes/Android-PullToRefresh</url>
@ -24,7 +24,7 @@
<url>https://github.com/chrisbanes/Android-PullToRefresh</url> <url>https://github.com/chrisbanes/Android-PullToRefresh</url>
<connection>scm:git:git://github.com/chrisbanes/Android-PullToRefresh.git</connection> <connection>scm:git:git://github.com/chrisbanes/Android-PullToRefresh.git</connection>
<developerConnection>scm:git:git@github.com:chrisbanes/Android-PullToRefresh.git</developerConnection> <developerConnection>scm:git:git@github.com:chrisbanes/Android-PullToRefresh.git</developerConnection>
<tag>v1.4.2</tag> <tag>v2.1.1</tag>
</scm> </scm>
<developers> <developers>
<developer> <developer>
@ -65,6 +65,10 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version> <version>2.3.2</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.handmark.pulltorefresh.samples" package="com.handmark.pulltorefresh.samples"
android:versionCode="1420" android:versionCode="2110"
android:versionName="1.4.2" > android:versionName="2.1.1" >
<uses-sdk <uses-sdk
android:minSdkVersion="4" android:minSdkVersion="4"
android:targetSdkVersion="10" /> android:targetSdkVersion="15" />
<application <application
android:hardwareAccelerated="true"
android:icon="@drawable/icon" android:icon="@drawable/icon"
android:label="@string/app_name" android:label="@string/app_name" >
android:theme="@android:style/Theme.Light" >
<activity <activity
android:name=".LauncherActivity" android:name=".LauncherActivity"
android:label="PullToRefresh Samples" > android:label="PullToRefresh Samples" >
@ -29,6 +29,10 @@
android:name=".PullToRefreshListFragmentActivity" android:name=".PullToRefreshListFragmentActivity"
android:label="PtR ListView Fragment" > android:label="PtR ListView Fragment" >
</activity> </activity>
<activity
android:name=".PullToRefreshListInViewPagerActivity"
android:label="PtR ListView in ViewPager" >
</activity>
<activity <activity
android:name=".PullToRefreshGridActivity" android:name=".PullToRefreshGridActivity"
android:label="PtR GridView" > android:label="PtR GridView" >
@ -45,6 +49,14 @@
android:name=".PullToRefreshScrollViewActivity" android:name=".PullToRefreshScrollViewActivity"
android:label="PtR ScrollView" > android:label="PtR ScrollView" >
</activity> </activity>
<activity
android:name=".PullToRefreshHorizontalScrollViewActivity"
android:label="PtR HorizontalScrollView" >
</activity>
<activity
android:name=".PullToRefreshViewPagerActivity"
android:label="PtR ViewPager" >
</activity>
<activity <activity
android:name=".PullToRefreshWebView2Activity" android:name=".PullToRefreshWebView2Activity"
android:label="PtR WebView Advanced" > android:label="PtR WebView Advanced" >

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -10,7 +10,7 @@
<parent> <parent>
<groupId>com.github.chrisbanes.pulltorefresh</groupId> <groupId>com.github.chrisbanes.pulltorefresh</groupId>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<version>1.4.2</version> <version>2.1.1</version>
</parent> </parent>
<dependencies> <dependencies>
@ -30,6 +30,12 @@
<type>apklib</type> <type>apklib</type>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>extra-viewpager</artifactId>
<type>apklib</type>
<version>${project.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -11,3 +11,4 @@
target=android-15 target=android-15
android.library.reference.1=../library android.library.reference.1=../library
android.library.reference.2=../extras/PullToRefreshListFragment android.library.reference.2=../extras/PullToRefreshListFragment
android.library.reference.3=../extras/PullToRefreshViewPager

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -1,17 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" > android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- The PullToRefreshExpandableListView replaces a standard ExpandableListView widget. --> <!-- The PullToRefreshExpandableListView replaces a standard ExpandableListView widget. -->
<com.handmark.pulltorefresh.library.PullToRefreshExpandableListView <com.handmark.pulltorefresh.library.PullToRefreshExpandableListView
xmlns:ptr="http://schemas.android.com/apk/res-auto" xmlns:ptr="http://schemas.android.com/apk/res-auto"
android:id="@+id/pull_refresh_expandable_list" android:id="@+id/pull_refresh_expandable_list"
android:layout_height="fill_parent"
android:layout_width="fill_parent" android:layout_width="fill_parent"
ptr:ptrAdapterViewBackground="@android:color/white" android:layout_height="fill_parent"
ptr:ptrHeaderBackground="@android:color/darker_gray" ptr:ptrHeaderBackground="@android:color/darker_gray"
ptr:ptrHeaderTextColor="@android:color/white" ptr:ptrHeaderTextColor="@android:color/white"
ptr:ptrMode="pullUpFromBottom" /> ptr:ptrMode="pullUpFromBottom" />

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- The PullToRefreshScrollView replaces a standard PullToRefreshScrollView widget. -->
<com.handmark.pulltorefresh.library.PullToRefreshHorizontalScrollView
xmlns:ptr="http://schemas.android.com/apk/res-auto"
android:id="@+id/pull_refresh_horizontalscrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
ptr:ptrAnimationStyle="flip"
ptr:ptrMode="both" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<TextView
style="@style/HorizScrollViewItem"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#ff99cc00" />
<TextView
style="@style/HorizScrollViewItem"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#ffff4444" />
<TextView
style="@style/HorizScrollViewItem"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#ff33b5e5" />
<TextView
style="@style/HorizScrollViewItem"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#ffcc0000" />
<TextView
style="@style/HorizScrollViewItem"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#ffffbb33" />
<TextView
style="@style/HorizScrollViewItem"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#ff00ddff" />
<TextView
style="@style/HorizScrollViewItem"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#ff669900" />
</LinearLayout>
</com.handmark.pulltorefresh.library.PullToRefreshHorizontalScrollView>
</LinearLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- The PullToRefreshListView replaces a standard ListView widget. -->
<android.support.v4.view.ViewPager
android:id="@+id/vp_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<!-- The PullToRefreshScrollView replaces a standard PullToRefreshScrollView widget. -->
<com.handmark.pulltorefresh.extras.viewpager.PullToRefreshViewPager
xmlns:ptr="http://schemas.android.com/apk/res-auto"
android:id="@+id/pull_refresh_viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
ptr:ptrAnimationStyle="flip"
ptr:ptrHeaderBackground="@android:color/darker_gray"
ptr:ptrMode="both" />
</FrameLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<com.handmark.pulltorefresh.library.PullToRefreshListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ptr="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
ptr:ptrHeaderBackground="@android:color/darker_gray" />

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="HorizScrollViewItem">
<item name="android:paddingRight">50dp</item>
<item name="android:paddingLeft">50dp</item>
<item name="android:gravity">center</item>
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
<item name="android:text">Sample Item</item>
</style>
</resources>

View File

@ -25,7 +25,7 @@ import android.widget.ListView;
public class LauncherActivity extends ListActivity { public class LauncherActivity extends ListActivity {
public static final String[] options = { "ListView", "ExpandableListView", "GridView", "WebView", "ScrollView", public static final String[] options = { "ListView", "ExpandableListView", "GridView", "WebView", "ScrollView",
"ListView Fragment", "WebView Advanced" }; "Horizontal ScrollView", "ViewPager", "ListView Fragment", "WebView Advanced", "ListView in ViewPager" };
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -55,11 +55,20 @@ public class LauncherActivity extends ListActivity {
intent = new Intent(this, PullToRefreshScrollViewActivity.class); intent = new Intent(this, PullToRefreshScrollViewActivity.class);
break; break;
case 5: case 5:
intent = new Intent(this, PullToRefreshListFragmentActivity.class); intent = new Intent(this, PullToRefreshHorizontalScrollViewActivity.class);
break; break;
case 6: case 6:
intent = new Intent(this, PullToRefreshViewPagerActivity.class);
break;
case 7:
intent = new Intent(this, PullToRefreshListFragmentActivity.class);
break;
case 8:
intent = new Intent(this, PullToRefreshWebView2Activity.class); intent = new Intent(this, PullToRefreshWebView2Activity.class);
break; break;
case 9:
intent = new Intent(this, PullToRefreshListInViewPagerActivity.class);
break;
} }
startActivity(intent); startActivity(intent);

View File

@ -16,9 +16,7 @@
package com.handmark.pulltorefresh.samples; package com.handmark.pulltorefresh.samples;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -34,7 +32,10 @@ import com.handmark.pulltorefresh.library.PullToRefreshExpandableListView;
public final class PullToRefreshExpandableListActivity extends ExpandableListActivity { public final class PullToRefreshExpandableListActivity extends ExpandableListActivity {
private static final String KEY = "key"; private static final String KEY = "key";
private LinkedList<String> mListItems, mGroupItems;
private List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
private List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>();
private PullToRefreshExpandableListView mPullRefreshListView; private PullToRefreshExpandableListView mPullRefreshListView;
private SimpleExpandableListAdapter mAdapter; private SimpleExpandableListAdapter mAdapter;
@ -55,13 +56,6 @@ public final class PullToRefreshExpandableListActivity extends ExpandableListAct
} }
}); });
mListItems = new LinkedList<String>();
mListItems.addAll(Arrays.asList(mChildStrings));
mGroupItems = new LinkedList<String>();
mGroupItems.addAll(Arrays.asList(mGroupStrings));
List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>();
for (String group : mGroupStrings) { for (String group : mGroupStrings) {
Map<String, String> groupMap1 = new HashMap<String, String>(); Map<String, String> groupMap1 = new HashMap<String, String>();
groupData.add(groupMap1); groupData.add(groupMap1);
@ -96,7 +90,18 @@ public final class PullToRefreshExpandableListActivity extends ExpandableListAct
@Override @Override
protected void onPostExecute(String[] result) { protected void onPostExecute(String[] result) {
mListItems.addFirst("Added after refresh..."); Map<String, String> newMap = new HashMap<String, String>();
newMap.put(KEY, "Added after refresh...");
groupData.add(newMap);
List<Map<String, String>> childList = new ArrayList<Map<String, String>>();
for (String string : mChildStrings) {
Map<String, String> childMap = new HashMap<String, String>();
childMap.put(KEY, string);
childList.add(childMap);
}
childData.add(childList);
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
// Call onRefreshComplete when the list has been refreshed. // Call onRefreshComplete when the list has been refreshed.
@ -106,8 +111,7 @@ public final class PullToRefreshExpandableListActivity extends ExpandableListAct
} }
} }
private final String[] mChildStrings = { "Child One", "Child Two", "Child Three", "Child Four", "Child Five", private String[] mChildStrings = { "Child One", "Child Two", "Child Three", "Child Four", "Child Five", "Child Six" };
"Child Six" };
private final String[] mGroupStrings = { "Group One", "Group Two", "Group Three" }; private String[] mGroupStrings = { "Group One", "Group Two", "Group Three" };
} }

View File

@ -116,7 +116,7 @@ public final class PullToRefreshGridActivity extends Activity {
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem setModeItem = menu.findItem(MENU_SET_MODE); MenuItem setModeItem = menu.findItem(MENU_SET_MODE);
setModeItem.setTitle(mPullRefreshGridView.getMode() == Mode.BOTH ? "Change to MODE_PULL_DOWN" setModeItem.setTitle(mPullRefreshGridView.getMode() == Mode.BOTH ? "Change to MODE_PULL_FROM_START"
: "Change to MODE_PULL_BOTH"); : "Change to MODE_PULL_BOTH");
return super.onPrepareOptionsMenu(menu); return super.onPrepareOptionsMenu(menu);
@ -127,7 +127,7 @@ public final class PullToRefreshGridActivity extends Activity {
switch (item.getItemId()) { switch (item.getItemId()) {
case MENU_SET_MODE: case MENU_SET_MODE:
mPullRefreshGridView mPullRefreshGridView
.setMode(mPullRefreshGridView.getMode() == Mode.BOTH ? Mode.PULL_DOWN_TO_REFRESH .setMode(mPullRefreshGridView.getMode() == Mode.BOTH ? Mode.PULL_FROM_START
: Mode.BOTH); : Mode.BOTH);
break; break;
} }

View File

@ -0,0 +1,73 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.samples;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.HorizontalScrollView;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener;
import com.handmark.pulltorefresh.library.PullToRefreshHorizontalScrollView;
public final class PullToRefreshHorizontalScrollViewActivity extends Activity {
PullToRefreshHorizontalScrollView mPullRefreshScrollView;
HorizontalScrollView mScrollView;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ptr_horizontalscrollview);
mPullRefreshScrollView = (PullToRefreshHorizontalScrollView) findViewById(R.id.pull_refresh_horizontalscrollview);
mPullRefreshScrollView.setOnRefreshListener(new OnRefreshListener<HorizontalScrollView>() {
@Override
public void onRefresh(PullToRefreshBase<HorizontalScrollView> refreshView) {
new GetDataTask().execute();
}
});
mScrollView = mPullRefreshScrollView.getRefreshableView();
}
private class GetDataTask extends AsyncTask<Void, Void, String[]> {
@Override
protected String[] doInBackground(Void... params) {
// Simulates a background job.
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
}
return null;
}
@Override
protected void onPostExecute(String[] result) {
// Do some stuff here
// Call onRefreshComplete when the list has been refreshed.
mPullRefreshScrollView.onRefreshComplete();
super.onPostExecute(result);
}
}
}

View File

@ -22,8 +22,12 @@ import android.app.ListActivity;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ListView; import android.widget.ListView;
import android.widget.Toast; import android.widget.Toast;
@ -41,6 +45,7 @@ public final class PullToRefreshListActivity extends ListActivity {
static final int MENU_MANUAL_REFRESH = 0; static final int MENU_MANUAL_REFRESH = 0;
static final int MENU_DISABLE_SCROLL = 1; static final int MENU_DISABLE_SCROLL = 1;
static final int MENU_SET_MODE = 2; static final int MENU_SET_MODE = 2;
static final int MENU_DEMO = 3;
private LinkedList<String> mListItems; private LinkedList<String> mListItems;
private PullToRefreshListView mPullRefreshListView; private PullToRefreshListView mPullRefreshListView;
@ -58,9 +63,11 @@ public final class PullToRefreshListActivity extends ListActivity {
mPullRefreshListView.setOnRefreshListener(new OnRefreshListener<ListView>() { mPullRefreshListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
@Override @Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) { public void onRefresh(PullToRefreshBase<ListView> refreshView) {
mPullRefreshListView.setLastUpdatedLabel(DateUtils.formatDateTime(getApplicationContext(), String label = DateUtils.formatDateTime(getApplicationContext(), System.currentTimeMillis(),
System.currentTimeMillis(), DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);
| DateUtils.FORMAT_ABBREV_ALL));
// Update the LastUpdatedLabel
refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(label);
// Do work to refresh the list here. // Do work to refresh the list here.
new GetDataTask().execute(); new GetDataTask().execute();
@ -78,6 +85,9 @@ public final class PullToRefreshListActivity extends ListActivity {
ListView actualListView = mPullRefreshListView.getRefreshableView(); ListView actualListView = mPullRefreshListView.getRefreshableView();
// Need to use the Actual ListView when registering for Context Menu
registerForContextMenu(actualListView);
mListItems = new LinkedList<String>(); mListItems = new LinkedList<String>();
mListItems.addAll(Arrays.asList(mStrings)); mListItems.addAll(Arrays.asList(mStrings));
@ -125,22 +135,36 @@ public final class PullToRefreshListActivity extends ListActivity {
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, MENU_MANUAL_REFRESH, 0, "Manual Refresh"); menu.add(0, MENU_MANUAL_REFRESH, 0, "Manual Refresh");
menu.add(0, MENU_DISABLE_SCROLL, 1, menu.add(0, MENU_DISABLE_SCROLL, 1,
mPullRefreshListView.isDisableScrollingWhileRefreshing() ? "Enable Scrolling while Refreshing" mPullRefreshListView.isScrollingWhileRefreshingEnabled() ? "Disable Scrolling while Refreshing"
: "Disable Scrolling while Refreshing"); : "Enable Scrolling while Refreshing");
menu.add(0, MENU_SET_MODE, 0, mPullRefreshListView.getMode() == Mode.BOTH ? "Change to MODE_PULL_DOWN" menu.add(0, MENU_SET_MODE, 0, mPullRefreshListView.getMode() == Mode.BOTH ? "Change to MODE_PULL_DOWN"
: "Change to MODE_PULL_BOTH"); : "Change to MODE_PULL_BOTH");
menu.add(0, MENU_DEMO, 0, "Demo");
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
menu.setHeaderTitle("Item: " + getListView().getItemAtPosition(info.position));
menu.add("Item 1");
menu.add("Item 2");
menu.add("Item 3");
menu.add("Item 4");
super.onCreateContextMenu(menu, v, menuInfo);
}
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem disableItem = menu.findItem(MENU_DISABLE_SCROLL); MenuItem disableItem = menu.findItem(MENU_DISABLE_SCROLL);
disableItem disableItem
.setTitle(mPullRefreshListView.isDisableScrollingWhileRefreshing() ? "Enable Scrolling while Refreshing" .setTitle(mPullRefreshListView.isScrollingWhileRefreshingEnabled() ? "Disable Scrolling while Refreshing"
: "Disable Scrolling while Refreshing"); : "Enable Scrolling while Refreshing");
MenuItem setModeItem = menu.findItem(MENU_SET_MODE); MenuItem setModeItem = menu.findItem(MENU_SET_MODE);
setModeItem.setTitle(mPullRefreshListView.getMode() == Mode.BOTH ? "Change to MODE_PULL_DOWN" setModeItem.setTitle(mPullRefreshListView.getMode() == Mode.BOTH ? "Change to MODE_FROM_START"
: "Change to MODE_PULL_BOTH"); : "Change to MODE_PULL_BOTH");
return super.onPrepareOptionsMenu(menu); return super.onPrepareOptionsMenu(menu);
@ -155,13 +179,16 @@ public final class PullToRefreshListActivity extends ListActivity {
mPullRefreshListView.setRefreshing(false); mPullRefreshListView.setRefreshing(false);
break; break;
case MENU_DISABLE_SCROLL: case MENU_DISABLE_SCROLL:
mPullRefreshListView.setDisableScrollingWhileRefreshing(!mPullRefreshListView mPullRefreshListView.setScrollingWhileRefreshingEnabled(!mPullRefreshListView
.isDisableScrollingWhileRefreshing()); .isScrollingWhileRefreshingEnabled());
break; break;
case MENU_SET_MODE: case MENU_SET_MODE:
mPullRefreshListView.setMode(mPullRefreshListView.getMode() == Mode.BOTH ? Mode.PULL_DOWN_TO_REFRESH mPullRefreshListView.setMode(mPullRefreshListView.getMode() == Mode.BOTH ? Mode.PULL_FROM_START
: Mode.BOTH); : Mode.BOTH);
break; break;
case MENU_DEMO:
mPullRefreshListView.demo();
break;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);

View File

@ -0,0 +1,110 @@
package com.handmark.pulltorefresh.samples;
import java.util.Arrays;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
public class PullToRefreshListInViewPagerActivity extends Activity implements OnRefreshListener<ListView> {
private static final String[] STRINGS = { "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance",
"Ackawi", "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
"Allgauer Emmentaler", "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
"Allgauer Emmentaler" };
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ptr_list_in_vp);
mViewPager = (ViewPager) findViewById(R.id.vp_list);
mViewPager.setAdapter(new ListViewPagerAdapter());
}
private class ListViewPagerAdapter extends PagerAdapter {
@Override
public View instantiateItem(ViewGroup container, int position) {
Context context = container.getContext();
PullToRefreshListView plv = (PullToRefreshListView) LayoutInflater.from(context).inflate(
R.layout.layout_listview_in_viewpager, container, false);
ListAdapter adapter = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1,
Arrays.asList(STRINGS));
plv.setAdapter(adapter);
plv.setOnRefreshListener(PullToRefreshListInViewPagerActivity.this);
// Now just add ListView to ViewPager and return it
container.addView(plv, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
return plv;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getCount() {
return 3;
}
}
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
new GetDataTask(refreshView).execute();
}
private static class GetDataTask extends AsyncTask<Void, Void, Void> {
PullToRefreshBase<?> mRefreshedView;
public GetDataTask(PullToRefreshBase<?> refreshedView) {
mRefreshedView = refreshedView;
}
@Override
protected Void doInBackground(Void... params) {
// Simulates a background job.
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
}
return null;
}
@Override
protected void onPostExecute(Void result) {
mRefreshedView.onRefreshComplete();
super.onPostExecute(result);
}
}
}

View File

@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.samples;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import com.handmark.pulltorefresh.extras.viewpager.PullToRefreshViewPager;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshBase.OnRefreshListener;
public class PullToRefreshViewPagerActivity extends Activity implements OnRefreshListener<ViewPager> {
private PullToRefreshViewPager mPullToRefreshViewPager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ptr_viewpager);
mPullToRefreshViewPager = (PullToRefreshViewPager) findViewById(R.id.pull_refresh_viewpager);
mPullToRefreshViewPager.setOnRefreshListener(this);
ViewPager vp = mPullToRefreshViewPager.getRefreshableView();
vp.setAdapter(new SamplePagerAdapter());
}
@Override
public void onRefresh(PullToRefreshBase<ViewPager> refreshView) {
new GetDataTask().execute();
}
static class SamplePagerAdapter extends PagerAdapter {
private static int[] sDrawables = { R.drawable.wallpaper, R.drawable.wallpaper, R.drawable.wallpaper,
R.drawable.wallpaper, R.drawable.wallpaper, R.drawable.wallpaper };
@Override
public int getCount() {
return sDrawables.length;
}
@Override
public View instantiateItem(ViewGroup container, int position) {
ImageView imageView = new ImageView(container.getContext());
imageView.setImageResource(sDrawables[position]);
// Now just add ImageView to ViewPager and return it
container.addView(imageView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
private class GetDataTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
// Simulates a background job.
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
}
return null;
}
@Override
protected void onPostExecute(Void result) {
mPullToRefreshViewPager.onRefreshComplete();
super.onPostExecute(result);
}
}
}