├── .gitignore ├── README.md ├── android-pull-to-refresh.png ├── build.gradle ├── libraryproject ├── .project ├── AndroidManifest.xml ├── build.gradle ├── proguard.cfg ├── res │ ├── drawable-hdpi │ │ └── ptr_pulltorefresh_arrow.png │ ├── drawable-ldpi │ │ └── ptr_pulltorefresh_arrow.png │ ├── drawable-mdpi │ │ └── ptr_pulltorefresh_arrow.png │ ├── layout │ │ └── ptr_header.xml │ └── values │ │ ├── ptr_default_style.xml │ │ └── strings.xml └── src │ └── eu │ └── erikw │ └── PullToRefreshListView.java ├── sampleproject ├── .classpath ├── .project ├── AndroidManifest.xml ├── build.gradle ├── proguard.cfg ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-ldpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── layout │ │ ├── list_item.xml │ │ └── main.xml │ └── values │ │ ├── ptr_style.xml │ │ └── strings.xml └── src │ └── eu │ └── erikw │ └── pulltorefresh │ └── sample │ └── PullToRefreshListViewSampleActivity.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | .settings 3 | local.properties 4 | project.properties 5 | bin 6 | gen 7 | .classpath 8 | 9 | # From https://github.com/github/gitignore/raw/master/Android.gitignore 10 | # built application files 11 | *.apk 12 | *.ap_ 13 | 14 | # files for the dex VM 15 | *.dex 16 | 17 | # Java class files 18 | *.class 19 | 20 | # generated GUI files 21 | *R.java 22 | 23 | *~ 24 | 25 | # IntelliJ IDE 26 | *.iml 27 | .idea 28 | out 29 | 30 | build.xml 31 | proguard-project.txt 32 | ant.properties 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android 'Pull to Refresh' ListView library 2 | 3 | ![Screenshot](https://github.com/erikwt/PullToRefresh-ListView/raw/master/android-pull-to-refresh.png) 4 | 5 | Demo video: http://www.youtube.com/watch?v=VjmdELnm3GI 6 | 7 | ## Project 8 | A generic, customizable, open source Android ListView implementation that has 'Pull to Refresh' functionality. This ListView can be used as a replacement of the normal Android android.widget.ListView class. 9 | 10 | ``` java 11 | /** 12 | * Users of this library should implement OnRefreshListener and call setOnRefreshListener(..) 13 | * to get notified on refresh events. The using class should call onRefreshComplete() when 14 | * refreshing is finished. 15 | * 16 | * The using class can call setRefreshing() to set the state explicitly to refreshing. This 17 | * is useful when you want to show the spinner and 'Refreshing' text when the 18 | * refresh was not triggered by 'Pull to Refresh', for example on start. 19 | * 20 | * @author Erik Wallentinsen 21 | */ 22 | ``` 23 | 24 | 25 | ## Features 26 | * Drop-in replacement for the android.widget.ListView widget 27 | * Nice graphics (thanks to johannilsson - see credits) 28 | * Animations; bouncing animation and rotation animation (see [video](http://www.youtube.com/watch?v=VjmdELnm3GI)) 29 | * Easy to integrate in your Android project (see usage) 30 | * Works for any Android project targeting Android 1.6 (API level 4) and up 31 | * Highly customizable (using Android styles) 32 | 33 | 34 | ## Info 35 | Feel free to ask questions, report bugs and request features at dev at erikw dot eu 36 | or on the PullToRefresh-ListView github [issue](https://github.com/erikwt/PullToRefresh-ListView/issues) page. 37 | You can also hit me up on [twitter](http://www.twitter.com/ewallentinsen) if that's your thing. 38 | 39 | 40 | ## Usage 41 | 42 | ### Example project 43 | Check out the [example project](https://github.com/erikwt/PullToRefresh-ListView/tree/master/sampleproject) 44 | in this repository for an implementation example. There is also moretechnical documentation available as 45 | javadoc in the [library project code](https://github.com/erikwt/PullToRefresh-ListView/blob/master/libraryproject/src/eu/erikw/PullToRefreshListView.java). 46 | 47 | ### Layout 48 | 49 | ``` xml 50 | 54 | 58 | ``` 59 | 60 | ### Activity 61 | 62 | ``` java 63 | // Set a listener to be invoked when the list should be refreshed. 64 | PullToRefreshListView listView = (PullToRefreshListView) findViewById(R.id.pull_to_refresh_listview); 65 | listView.setOnRefreshListener(new OnRefreshListener() { 66 | 67 | @Override 68 | public void onRefresh() { 69 | // Your code to refresh the list contents 70 | 71 | // ... 72 | 73 | // Make sure you call listView.onRefreshComplete() 74 | // when the loading is done. This can be done from here or any 75 | // other place, like on a broadcast receive from your loading 76 | // service or the onPostExecute of your AsyncTask. 77 | 78 | listView.onRefreshComplete(); 79 | } 80 | }); 81 | 82 | ``` 83 | 84 | ### Style 85 | To change the looks of the 'PullToRefresh' ListView, you can override the styles that are defined in the library project. 86 | Default, the looks are very basic (see screenshot above), with black text on a white background. You can change every 87 | aspect to your needs though, like the arrow image, text size, text color and background. 88 | 89 | To do so, override the style attributes to your liking, like the following example: 90 | 91 | ``` xml 92 | 98 | ``` 99 | 100 | The various styles you can override are; 101 | 102 | * ptr_headerContainer 103 | * ptr_header 104 | * ptr_arrow 105 | * ptr_spinner 106 | * ptr_text 107 | 108 | The default attributes can be found in the [library project](https://github.com/erikwt/PullToRefresh-ListView/blob/master/libraryproject/res/values/default_style.xml) 109 | 110 | 111 | ## Author 112 | I’m a young, enthusiastic hacker from Amsterdam. I study computer science at the VU (Free University) and my work mostly involves Android programming. I do a lot of hacking in my spare time, resulting in many projects I want to share with the world. 113 | 114 | * Twitter: [@ewallentinsen](http://www.twitter.com/ewallentinsen) 115 | * Blog: http://www.erikw.eu 116 | 117 | 118 | ## Other projects 119 | This project might not be the best library for you to use in your project, depending on your likes and needs. Consider 120 | using these great 'Pull to Refresh' libraries; 121 | 122 | * chrisbanes: https://github.com/chrisbanes/Android-PullToRefresh 123 | * johannilsson: https://github.com/johannilsson/android-pulltorefresh 124 | 125 | 126 | ## Credits 127 | * johannilsson for the original PullToRefresh project and some graphics: https://github.com/johannilsson/android-pulltorefresh 128 | * chrisbanes for the layout of this README and for inspiring me to opensource this project as well (http://github.com/chrisbanes/Android-PullToRefresh) 129 | 130 | 131 | ## License 132 | Copyright (c) 2012 - Erik Wallentinsen 133 | 134 | Licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) 135 | 136 | -------------------------------------------------------------------------------- /android-pull-to-refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikwt/PullToRefresh-ListView/d58bb213351a246c2602f38755fa30fc4df1a066/android-pull-to-refresh.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:0.12.+' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | ext { 17 | isLibrary = false 18 | 19 | // Fill out the proper values here and uncomment. 20 | // See also https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide 21 | // Upload it with: gradle uploadArchives 22 | // sonatypeUsername = 'yourusername' 23 | // sonatypePassword = 'yourpassword' 24 | // sonatypeRepo = 'the-repo' 25 | // sonatypeSnapshotRepo = 'https://oss.sonatype.org/content/repositories/snapshots/' 26 | } 27 | } 28 | 29 | subprojects { 30 | afterEvaluate { Project project -> 31 | ext.pluginContainer = project.getPlugins() 32 | if(ext.pluginContainer.hasPlugin("android") || ext.pluginContainer.hasPlugin("android-library")) { 33 | android { 34 | compileSdkVersion 19 35 | buildToolsVersion '19.1.0' 36 | 37 | android { 38 | lintOptions { 39 | abortOnError false 40 | } 41 | } 42 | 43 | defaultConfig { 44 | minSdkVersion 4 45 | targetSdkVersion 19 46 | versionCode 1 47 | versionName "1.0" 48 | } 49 | } 50 | } 51 | if(project.isLibrary && rootProject.hasProperty('sonatypeUsername') && rootProject.hasProperty('sonatypePassword')) { 52 | configure(project) { 53 | apply plugin: 'maven' 54 | apply plugin: 'signing' 55 | 56 | signing { 57 | required { has("release") && gradle.taskGraph.hasTask("uploadArchives") } 58 | sign configurations.archives 59 | } 60 | 61 | uploadArchives { 62 | repositories.mavenDeployer { 63 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 64 | 65 | repository(url: sonatypeRepo) { 66 | authentication(userName: sonatypeUsername , password: sonatypePassword) 67 | releases(updatePolicy: 'always') 68 | } 69 | 70 | snapshotRepository(url: sonatypeSnapshotRepo) { 71 | authentication(userName: sonatypeUsername , password: sonatypePassword) 72 | snapshots(updatePolicy: 'always') 73 | } 74 | 75 | pom.project { 76 | name project.pomName 77 | version project.version 78 | groupId project.group 79 | packaging project.pomPackaging 80 | artifactId project.pomArtifactId 81 | description project.pomDescription 82 | url 'https://github.com/erikwt/PullToRefresh-ListView' 83 | 84 | scm { 85 | url 'scm:git@github.com:erikwt/PullToRefresh-ListView.git' 86 | connection 'scm:git@github.com:erikwt/PullToRefresh-ListView.git' 87 | developerConnection 'scm:git@github.com:erikwt/PullToRefresh-ListView.git' 88 | } 89 | 90 | licenses { 91 | license { 92 | name 'The Apache Software License, Version 2.0' 93 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 94 | distribution 'repo' 95 | } 96 | } 97 | 98 | developers { 99 | developer { 100 | id 'erikwt' 101 | name 'Erik Wallentinsen' 102 | email '' 103 | } 104 | } 105 | } 106 | } 107 | } 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /libraryproject/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | PullToRefreshListView 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /libraryproject/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /libraryproject/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'android-library' 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:0.12.+' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | ext { 17 | isLibrary = true 18 | pomPackaging = "aar" 19 | pomArtifactId = "PullToRefresh-ListView" 20 | pomName = "Android 'Pull to Refresh' ListView library" 21 | pomDescription = 'A generic, customizable, open source Android ListView implementation that has "Pull to Refresh" functionality. This ListView can be used as a replacement of the normal Android android.widget.ListView class.' 22 | } 23 | 24 | 25 | android { 26 | compileSdkVersion 19 27 | buildToolsVersion "19.1.0" 28 | 29 | defaultConfig { 30 | minSdkVersion 4 31 | targetSdkVersion 19 32 | versionCode 1 33 | versionName "1.0" 34 | } 35 | 36 | lintOptions { 37 | abortOnError false 38 | } 39 | 40 | sourceSets { 41 | main { 42 | manifest.srcFile 'AndroidManifest.xml' 43 | java.srcDirs = ['src'] 44 | res.srcDirs = ['res'] 45 | } 46 | } 47 | 48 | buildTypes { 49 | release { 50 | runProguard true 51 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' 52 | } 53 | } 54 | } 55 | 56 | repositories { 57 | mavenCentral() 58 | mavenLocal() 59 | } 60 | 61 | dependencies { 62 | } 63 | 64 | -------------------------------------------------------------------------------- /libraryproject/proguard.cfg: -------------------------------------------------------------------------------- 1 | -optimizationpasses 5 2 | -dontusemixedcaseclassnames 3 | -dontskipnonpubliclibraryclasses 4 | -dontpreverify 5 | -verbose 6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 7 | 8 | -keepattributes InnerClasses 9 | 10 | 11 | -keep class **.R 12 | -keep class **.R$* { 13 | ; 14 | } 15 | 16 | -keep public class eu.erikw.PullToRefreshListView { 17 | *; 18 | } 19 | -keep public class eu.erikw.PullToRefreshListView$* { 20 | *; 21 | } 22 | 23 | 24 | 25 | -keepclasseswithmembernames class * { 26 | native ; 27 | } 28 | 29 | -keepclasseswithmembernames class * { 30 | public (android.content.Context, android.util.AttributeSet); 31 | } 32 | 33 | -keepclasseswithmembernames class * { 34 | public (android.content.Context, android.util.AttributeSet, int); 35 | } 36 | 37 | -keepclassmembers enum * { 38 | public static **[] values(); 39 | public static ** valueOf(java.lang.String); 40 | } 41 | 42 | -keep class * implements android.os.Parcelable { 43 | public static final android.os.Parcelable$Creator *; 44 | } 45 | -------------------------------------------------------------------------------- /libraryproject/res/drawable-hdpi/ptr_pulltorefresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikwt/PullToRefresh-ListView/d58bb213351a246c2602f38755fa30fc4df1a066/libraryproject/res/drawable-hdpi/ptr_pulltorefresh_arrow.png -------------------------------------------------------------------------------- /libraryproject/res/drawable-ldpi/ptr_pulltorefresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikwt/PullToRefresh-ListView/d58bb213351a246c2602f38755fa30fc4df1a066/libraryproject/res/drawable-ldpi/ptr_pulltorefresh_arrow.png -------------------------------------------------------------------------------- /libraryproject/res/drawable-mdpi/ptr_pulltorefresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikwt/PullToRefresh-ListView/d58bb213351a246c2602f38755fa30fc4df1a066/libraryproject/res/drawable-mdpi/ptr_pulltorefresh_arrow.png -------------------------------------------------------------------------------- /libraryproject/res/layout/ptr_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /libraryproject/res/values/ptr_default_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 15 | 16 | 23 | 24 | 31 | 32 | 39 | 40 | 49 | 50 | 57 | -------------------------------------------------------------------------------- /libraryproject/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pull to refresh 4 | Release to refresh 5 | Refreshing… 6 | Updated: %1$s 7 | 8 | -------------------------------------------------------------------------------- /libraryproject/src/eu/erikw/PullToRefreshListView.java: -------------------------------------------------------------------------------- 1 | package eu.erikw; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.util.Log; 6 | import android.view.*; 7 | import android.view.ViewTreeObserver.OnGlobalLayoutListener; 8 | import android.view.animation.*; 9 | import android.view.animation.Animation.AnimationListener; 10 | import android.widget.*; 11 | 12 | import java.text.SimpleDateFormat; 13 | import java.util.Date; 14 | 15 | /** 16 | * A generic, customizable Android ListView implementation that has 'Pull to Refresh' functionality. 17 | *

18 | * This ListView can be used in place of the normal Android android.widget.ListView class. 19 | *

20 | * Users of this class should implement OnRefreshListener and call setOnRefreshListener(..) 21 | * to get notified on refresh events. The using class should call onRefreshComplete() when 22 | * refreshing is finished. 23 | *

24 | * The using class can call setRefreshing() to set the state explicitly to refreshing. This 25 | * is useful when you want to show the spinner and 'Refreshing' text when the 26 | * refresh was not triggered by 'Pull to Refresh', for example on start. 27 | *

28 | * For more information, visit the project page: 29 | * https://github.com/erikwt/PullToRefresh-ListView 30 | * 31 | * @author Erik Wallentinsen 32 | * @version 1.3.0 33 | */ 34 | public class PullToRefreshListView extends ListView{ 35 | 36 | private static final float PULL_RESISTANCE = 1.7f; 37 | private static final int BOUNCE_ANIMATION_DURATION = 700; 38 | private static final int BOUNCE_ANIMATION_DELAY = 100; 39 | private static final float BOUNCE_OVERSHOOT_TENSION = 1.4f; 40 | private static final int ROTATE_ARROW_ANIMATION_DURATION = 250; 41 | 42 | private static enum State{ 43 | PULL_TO_REFRESH, 44 | RELEASE_TO_REFRESH, 45 | REFRESHING 46 | } 47 | 48 | /** 49 | * Interface to implement when you want to get notified of 'pull to refresh' 50 | * events. 51 | * Call setOnRefreshListener(..) to activate an OnRefreshListener. 52 | */ 53 | public interface OnRefreshListener{ 54 | 55 | /** 56 | * Method to be called when a refresh is requested 57 | */ 58 | public void onRefresh(); 59 | } 60 | 61 | private static int measuredHeaderHeight; 62 | 63 | private boolean scrollbarEnabled; 64 | private boolean bounceBackHeader; 65 | private boolean lockScrollWhileRefreshing; 66 | private boolean showLastUpdatedText; 67 | private String pullToRefreshText; 68 | private String releaseToRefreshText; 69 | private String refreshingText; 70 | private String lastUpdatedText; 71 | private SimpleDateFormat lastUpdatedDateFormat = new SimpleDateFormat("dd/MM HH:mm"); 72 | 73 | private float previousY; 74 | private int headerPadding; 75 | private boolean hasResetHeader; 76 | private long lastUpdated = -1; 77 | private State state; 78 | private LinearLayout headerContainer; 79 | private RelativeLayout header; 80 | private RotateAnimation flipAnimation; 81 | private RotateAnimation reverseFlipAnimation; 82 | private ImageView image; 83 | private ProgressBar spinner; 84 | private TextView text; 85 | private TextView lastUpdatedTextView; 86 | private OnItemClickListener onItemClickListener; 87 | private OnItemLongClickListener onItemLongClickListener; 88 | private OnRefreshListener onRefreshListener; 89 | 90 | private float mScrollStartY; 91 | private final int IDLE_DISTANCE = 5; 92 | 93 | public PullToRefreshListView(Context context){ 94 | super(context); 95 | init(); 96 | } 97 | 98 | public PullToRefreshListView(Context context, AttributeSet attrs){ 99 | super(context, attrs); 100 | init(); 101 | } 102 | 103 | public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle){ 104 | super(context, attrs, defStyle); 105 | init(); 106 | } 107 | 108 | @Override 109 | public void setOnItemClickListener(OnItemClickListener onItemClickListener){ 110 | this.onItemClickListener = onItemClickListener; 111 | } 112 | 113 | @Override 114 | public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener){ 115 | this.onItemLongClickListener = onItemLongClickListener; 116 | } 117 | 118 | /** 119 | * Activate an OnRefreshListener to get notified on 'pull to refresh' 120 | * events. 121 | * 122 | * @param onRefreshListener The OnRefreshListener to get notified 123 | */ 124 | public void setOnRefreshListener(OnRefreshListener onRefreshListener){ 125 | this.onRefreshListener = onRefreshListener; 126 | } 127 | 128 | /** 129 | * @return If the list is in 'Refreshing' state 130 | */ 131 | public boolean isRefreshing(){ 132 | return state == State.REFRESHING; 133 | } 134 | 135 | /** 136 | * Default is false. When lockScrollWhileRefreshing is set to true, the list 137 | * cannot scroll when in 'refreshing' mode. It's 'locked' on refreshing. 138 | * 139 | * @param lockScrollWhileRefreshing 140 | */ 141 | public void setLockScrollWhileRefreshing(boolean lockScrollWhileRefreshing){ 142 | this.lockScrollWhileRefreshing = lockScrollWhileRefreshing; 143 | } 144 | 145 | /** 146 | * Default is false. Show the last-updated date/time in the 'Pull ro Refresh' 147 | * header. See 'setLastUpdatedDateFormat' to set the date/time formatting. 148 | * 149 | * @param showLastUpdatedText 150 | */ 151 | public void setShowLastUpdatedText(boolean showLastUpdatedText){ 152 | this.showLastUpdatedText = showLastUpdatedText; 153 | if(!showLastUpdatedText) lastUpdatedTextView.setVisibility(View.GONE); 154 | } 155 | 156 | /** 157 | * Default: "dd/MM HH:mm". Set the format in which the last-updated 158 | * date/time is shown. Meaningless if 'showLastUpdatedText == false (default)'. 159 | * See 'setShowLastUpdatedText'. 160 | * 161 | * @param lastUpdatedDateFormat 162 | */ 163 | public void setLastUpdatedDateFormat(SimpleDateFormat lastUpdatedDateFormat){ 164 | this.lastUpdatedDateFormat = lastUpdatedDateFormat; 165 | } 166 | 167 | /** 168 | * Explicitly set the state to refreshing. This 169 | * is useful when you want to show the spinner and 'Refreshing' text when 170 | * the refresh was not triggered by 'pull to refresh', for example on start. 171 | */ 172 | public void setRefreshing(){ 173 | state = State.REFRESHING; 174 | scrollTo(0, 0); 175 | setUiRefreshing(); 176 | setHeaderPadding(0); 177 | } 178 | 179 | /** 180 | * Set the state back to 'pull to refresh'. Call this method when refreshing 181 | * the data is finished. 182 | */ 183 | public void onRefreshComplete(){ 184 | state = State.PULL_TO_REFRESH; 185 | resetHeader(); 186 | lastUpdated = System.currentTimeMillis(); 187 | } 188 | 189 | /** 190 | * Change the label text on state 'Pull to Refresh' 191 | * 192 | * @param pullToRefreshText Text 193 | */ 194 | public void setTextPullToRefresh(String pullToRefreshText){ 195 | this.pullToRefreshText = pullToRefreshText; 196 | if(state == State.PULL_TO_REFRESH){ 197 | text.setText(pullToRefreshText); 198 | } 199 | } 200 | 201 | /** 202 | * Change the label text on state 'Release to Refresh' 203 | * 204 | * @param releaseToRefreshText Text 205 | */ 206 | public void setTextReleaseToRefresh(String releaseToRefreshText){ 207 | this.releaseToRefreshText = releaseToRefreshText; 208 | if(state == State.RELEASE_TO_REFRESH){ 209 | text.setText(releaseToRefreshText); 210 | } 211 | } 212 | 213 | /** 214 | * Change the label text on state 'Refreshing' 215 | * 216 | * @param refreshingText Text 217 | */ 218 | public void setTextRefreshing(String refreshingText){ 219 | this.refreshingText = refreshingText; 220 | if(state == State.REFRESHING){ 221 | text.setText(refreshingText); 222 | } 223 | } 224 | 225 | private void init(){ 226 | setVerticalFadingEdgeEnabled(false); 227 | 228 | headerContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.ptr_header, null); 229 | header = (RelativeLayout) headerContainer.findViewById(R.id.ptr_id_header); 230 | text = (TextView) header.findViewById(R.id.ptr_id_text); 231 | lastUpdatedTextView = (TextView) header.findViewById(R.id.ptr_id_last_updated); 232 | image = (ImageView) header.findViewById(R.id.ptr_id_image); 233 | spinner = (ProgressBar) header.findViewById(R.id.ptr_id_spinner); 234 | 235 | pullToRefreshText = getContext().getString(R.string.ptr_pull_to_refresh); 236 | releaseToRefreshText = getContext().getString(R.string.ptr_release_to_refresh); 237 | refreshingText = getContext().getString(R.string.ptr_refreshing); 238 | lastUpdatedText = getContext().getString(R.string.ptr_last_updated); 239 | 240 | flipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); 241 | flipAnimation.setInterpolator(new LinearInterpolator()); 242 | flipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION); 243 | flipAnimation.setFillAfter(true); 244 | 245 | reverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); 246 | reverseFlipAnimation.setInterpolator(new LinearInterpolator()); 247 | reverseFlipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION); 248 | reverseFlipAnimation.setFillAfter(true); 249 | 250 | addHeaderView(headerContainer); 251 | setState(State.PULL_TO_REFRESH); 252 | scrollbarEnabled = isVerticalScrollBarEnabled(); 253 | 254 | ViewTreeObserver vto = header.getViewTreeObserver(); 255 | vto.addOnGlobalLayoutListener(new PTROnGlobalLayoutListener()); 256 | 257 | super.setOnItemClickListener(new PTROnItemClickListener()); 258 | super.setOnItemLongClickListener(new PTROnItemLongClickListener()); 259 | } 260 | 261 | private void setHeaderPadding(int padding){ 262 | headerPadding = padding; 263 | 264 | MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) header.getLayoutParams(); 265 | mlp.setMargins(0, Math.round(padding), 0, 0); 266 | header.setLayoutParams(mlp); 267 | } 268 | 269 | @Override 270 | public boolean onTouchEvent(MotionEvent event){ 271 | if(lockScrollWhileRefreshing 272 | && (state == State.REFRESHING || getAnimation() != null && !getAnimation().hasEnded())){ 273 | return true; 274 | } 275 | 276 | switch(event.getAction()){ 277 | case MotionEvent.ACTION_DOWN: 278 | if(getFirstVisiblePosition() == 0){ 279 | previousY = event.getY(); 280 | } 281 | else { 282 | previousY = -1; 283 | } 284 | 285 | // Remember where have we started 286 | mScrollStartY = event.getY(); 287 | 288 | break; 289 | 290 | case MotionEvent.ACTION_UP: 291 | if(previousY != -1 && (state == State.RELEASE_TO_REFRESH || getFirstVisiblePosition() == 0)){ 292 | switch(state){ 293 | case RELEASE_TO_REFRESH: 294 | setState(State.REFRESHING); 295 | bounceBackHeader(); 296 | 297 | break; 298 | 299 | case PULL_TO_REFRESH: 300 | resetHeader(); 301 | break; 302 | } 303 | } 304 | break; 305 | 306 | case MotionEvent.ACTION_MOVE: 307 | if(previousY != -1 && getFirstVisiblePosition() == 0 && Math.abs(mScrollStartY-event.getY()) > IDLE_DISTANCE){ 308 | float y = event.getY(); 309 | float diff = y - previousY; 310 | if(diff > 0) diff /= PULL_RESISTANCE; 311 | previousY = y; 312 | 313 | int newHeaderPadding = Math.max(Math.round(headerPadding + diff), -header.getHeight()); 314 | 315 | if(newHeaderPadding != headerPadding && state != State.REFRESHING){ 316 | setHeaderPadding(newHeaderPadding); 317 | 318 | if(state == State.PULL_TO_REFRESH && headerPadding > 0){ 319 | setState(State.RELEASE_TO_REFRESH); 320 | 321 | image.clearAnimation(); 322 | image.startAnimation(flipAnimation); 323 | }else if(state == State.RELEASE_TO_REFRESH && headerPadding < 0){ 324 | setState(State.PULL_TO_REFRESH); 325 | 326 | image.clearAnimation(); 327 | image.startAnimation(reverseFlipAnimation); 328 | } 329 | } 330 | } 331 | 332 | break; 333 | } 334 | 335 | return super.onTouchEvent(event); 336 | } 337 | 338 | private void bounceBackHeader(){ 339 | int yTranslate = state == State.REFRESHING ? 340 | header.getHeight() - headerContainer.getHeight() : 341 | -headerContainer.getHeight() - headerContainer.getTop() + getPaddingTop();; 342 | 343 | TranslateAnimation bounceAnimation = new TranslateAnimation( 344 | TranslateAnimation.ABSOLUTE, 0, 345 | TranslateAnimation.ABSOLUTE, 0, 346 | TranslateAnimation.ABSOLUTE, 0, 347 | TranslateAnimation.ABSOLUTE, yTranslate); 348 | 349 | bounceAnimation.setDuration(BOUNCE_ANIMATION_DURATION); 350 | bounceAnimation.setFillEnabled(true); 351 | bounceAnimation.setFillAfter(false); 352 | bounceAnimation.setFillBefore(true); 353 | bounceAnimation.setInterpolator(new OvershootInterpolator(BOUNCE_OVERSHOOT_TENSION)); 354 | bounceAnimation.setAnimationListener(new HeaderAnimationListener(yTranslate)); 355 | 356 | startAnimation(bounceAnimation); 357 | } 358 | 359 | private void resetHeader(){ 360 | if(getFirstVisiblePosition() > 0){ 361 | setHeaderPadding(-header.getHeight()); 362 | setState(State.PULL_TO_REFRESH); 363 | return; 364 | } 365 | 366 | if(getAnimation() != null && !getAnimation().hasEnded()){ 367 | bounceBackHeader = true; 368 | }else{ 369 | bounceBackHeader(); 370 | } 371 | } 372 | 373 | private void setUiRefreshing(){ 374 | spinner.setVisibility(View.VISIBLE); 375 | image.clearAnimation(); 376 | image.setVisibility(View.INVISIBLE); 377 | text.setText(refreshingText); 378 | } 379 | 380 | private void setState(State state){ 381 | this.state = state; 382 | switch(state){ 383 | case PULL_TO_REFRESH: 384 | spinner.setVisibility(View.INVISIBLE); 385 | image.setVisibility(View.VISIBLE); 386 | text.setText(pullToRefreshText); 387 | 388 | if(showLastUpdatedText && lastUpdated != -1){ 389 | lastUpdatedTextView.setVisibility(View.VISIBLE); 390 | lastUpdatedTextView.setText(String.format(lastUpdatedText, lastUpdatedDateFormat.format(new Date(lastUpdated)))); 391 | } 392 | 393 | break; 394 | 395 | case RELEASE_TO_REFRESH: 396 | spinner.setVisibility(View.INVISIBLE); 397 | image.setVisibility(View.VISIBLE); 398 | text.setText(releaseToRefreshText); 399 | break; 400 | 401 | case REFRESHING: 402 | setUiRefreshing(); 403 | 404 | lastUpdated = System.currentTimeMillis(); 405 | if(onRefreshListener == null){ 406 | setState(State.PULL_TO_REFRESH); 407 | }else{ 408 | onRefreshListener.onRefresh(); 409 | } 410 | 411 | break; 412 | } 413 | } 414 | 415 | @Override 416 | protected void onScrollChanged(int l, int t, int oldl, int oldt){ 417 | super.onScrollChanged(l, t, oldl, oldt); 418 | 419 | if(!hasResetHeader){ 420 | if(measuredHeaderHeight > 0 && state != State.REFRESHING){ 421 | setHeaderPadding(-measuredHeaderHeight); 422 | } 423 | 424 | hasResetHeader = true; 425 | } 426 | } 427 | 428 | private class HeaderAnimationListener implements AnimationListener{ 429 | 430 | private int height, translation; 431 | private State stateAtAnimationStart; 432 | 433 | public HeaderAnimationListener(int translation){ 434 | this.translation = translation; 435 | } 436 | 437 | @Override 438 | public void onAnimationStart(Animation animation){ 439 | stateAtAnimationStart = state; 440 | 441 | android.view.ViewGroup.LayoutParams lp = getLayoutParams(); 442 | height = lp.height; 443 | lp.height = getHeight() - translation; 444 | setLayoutParams(lp); 445 | 446 | if(scrollbarEnabled){ 447 | setVerticalScrollBarEnabled(false); 448 | } 449 | } 450 | 451 | @Override 452 | public void onAnimationEnd(Animation animation){ 453 | setHeaderPadding(stateAtAnimationStart == State.REFRESHING ? 0 : -measuredHeaderHeight - headerContainer.getTop()); 454 | setSelection(0); 455 | 456 | android.view.ViewGroup.LayoutParams lp = getLayoutParams(); 457 | lp.height = height; 458 | setLayoutParams(lp); 459 | 460 | if(scrollbarEnabled){ 461 | setVerticalScrollBarEnabled(true); 462 | } 463 | 464 | if(bounceBackHeader){ 465 | bounceBackHeader = false; 466 | 467 | postDelayed(new Runnable(){ 468 | 469 | @Override 470 | public void run(){ 471 | resetHeader(); 472 | } 473 | }, BOUNCE_ANIMATION_DELAY); 474 | }else if(stateAtAnimationStart != State.REFRESHING){ 475 | setState(State.PULL_TO_REFRESH); 476 | } 477 | } 478 | 479 | @Override 480 | public void onAnimationRepeat(Animation animation){} 481 | } 482 | 483 | private class PTROnGlobalLayoutListener implements OnGlobalLayoutListener{ 484 | 485 | @Override 486 | public void onGlobalLayout(){ 487 | int initialHeaderHeight = header.getHeight(); 488 | 489 | if(initialHeaderHeight > 0){ 490 | measuredHeaderHeight = initialHeaderHeight; 491 | 492 | if(measuredHeaderHeight > 0 && state != State.REFRESHING){ 493 | setHeaderPadding(-measuredHeaderHeight); 494 | requestLayout(); 495 | } 496 | } 497 | 498 | getViewTreeObserver().removeGlobalOnLayoutListener(this); 499 | } 500 | } 501 | 502 | private class PTROnItemClickListener implements OnItemClickListener{ 503 | 504 | @Override 505 | public void onItemClick(AdapterView adapterView, View view, int position, long id){ 506 | hasResetHeader = false; 507 | 508 | if(onItemClickListener != null && state == State.PULL_TO_REFRESH){ 509 | // Passing up onItemClick. Correct position with the number of header views 510 | onItemClickListener.onItemClick(adapterView, view, position - getHeaderViewsCount(), id); 511 | } 512 | } 513 | } 514 | 515 | private class PTROnItemLongClickListener implements OnItemLongClickListener{ 516 | 517 | @Override 518 | public boolean onItemLongClick(AdapterView adapterView, View view, int position, long id){ 519 | hasResetHeader = false; 520 | 521 | if(onItemLongClickListener != null && state == State.PULL_TO_REFRESH){ 522 | // Passing up onItemLongClick. Correct position with the number of header views 523 | return onItemLongClickListener.onItemLongClick(adapterView, view, position - getHeaderViewsCount(), id); 524 | } 525 | 526 | return false; 527 | } 528 | } 529 | } 530 | -------------------------------------------------------------------------------- /sampleproject/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sampleproject/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | PullToRefresh SampleProject 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /sampleproject/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /sampleproject/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'android-library' 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:0.12.+' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | android { 17 | compileSdkVersion 19 18 | buildToolsVersion "19.1.0" 19 | 20 | defaultConfig { 21 | minSdkVersion 4 22 | targetSdkVersion 19 23 | versionCode 1 24 | versionName "1.0" 25 | } 26 | 27 | lintOptions { 28 | abortOnError false 29 | } 30 | 31 | sourceSets { 32 | main { 33 | manifest.srcFile 'AndroidManifest.xml' 34 | java.srcDirs = ['src'] 35 | res.srcDirs = ['res'] 36 | } 37 | } 38 | } 39 | 40 | repositories { 41 | mavenCentral() 42 | mavenLocal() 43 | } 44 | 45 | dependencies { 46 | compile project(':libraryproject') 47 | } 48 | -------------------------------------------------------------------------------- /sampleproject/proguard.cfg: -------------------------------------------------------------------------------- 1 | -optimizationpasses 5 2 | -dontusemixedcaseclassnames 3 | -dontskipnonpubliclibraryclasses 4 | -dontpreverify 5 | -verbose 6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 7 | 8 | -keep public class * extends android.app.Activity 9 | -keep public class * extends android.app.Application 10 | -keep public class * extends android.app.Service 11 | -keep public class * extends android.content.BroadcastReceiver 12 | -keep public class * extends android.content.ContentProvider 13 | -keep public class * extends android.app.backup.BackupAgentHelper 14 | -keep public class * extends android.preference.Preference 15 | -keep public class com.android.vending.licensing.ILicensingService 16 | 17 | -keepclasseswithmembernames class * { 18 | native ; 19 | } 20 | 21 | -keepclasseswithmembers class * { 22 | public (android.content.Context, android.util.AttributeSet); 23 | } 24 | 25 | -keepclasseswithmembers class * { 26 | public (android.content.Context, android.util.AttributeSet, int); 27 | } 28 | 29 | -keepclassmembers class * extends android.app.Activity { 30 | public void *(android.view.View); 31 | } 32 | 33 | -keepclassmembers enum * { 34 | public static **[] values(); 35 | public static ** valueOf(java.lang.String); 36 | } 37 | 38 | -keep class * implements android.os.Parcelable { 39 | public static final android.os.Parcelable$Creator *; 40 | } 41 | -------------------------------------------------------------------------------- /sampleproject/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikwt/PullToRefresh-ListView/d58bb213351a246c2602f38755fa30fc4df1a066/sampleproject/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sampleproject/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikwt/PullToRefresh-ListView/d58bb213351a246c2602f38755fa30fc4df1a066/sampleproject/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /sampleproject/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikwt/PullToRefresh-ListView/d58bb213351a246c2602f38755fa30fc4df1a066/sampleproject/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sampleproject/res/layout/list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 15 | -------------------------------------------------------------------------------- /sampleproject/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 18 | 19 | -------------------------------------------------------------------------------- /sampleproject/res/values/ptr_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 24 | 25 | 31 | 32 | -------------------------------------------------------------------------------- /sampleproject/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello World, PullToRefreshListViewSampleActivity! 5 | PullToRefresh SampleProject 6 | Edit 7 | Delete 8 | 9 | -------------------------------------------------------------------------------- /sampleproject/src/eu/erikw/pulltorefresh/sample/PullToRefreshListViewSampleActivity.java: -------------------------------------------------------------------------------- 1 | package eu.erikw.pulltorefresh.sample; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.ContextMenu; 7 | import android.view.ContextMenu.ContextMenuInfo; 8 | import android.view.LayoutInflater; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.AdapterView; 14 | import android.widget.AdapterView.AdapterContextMenuInfo; 15 | import android.widget.AdapterView.OnItemClickListener; 16 | import android.widget.AdapterView.OnItemLongClickListener; 17 | import android.widget.ArrayAdapter; 18 | import android.widget.TextView; 19 | import android.widget.Toast; 20 | import eu.erikw.PullToRefreshListView; 21 | import eu.erikw.PullToRefreshListView.OnRefreshListener; 22 | import eu.erikw.pulltorefresh.sample.PullToRefreshListViewSampleActivity.PullToRefreshListViewSampleAdapter.ViewHolder; 23 | 24 | import java.util.ArrayList; 25 | 26 | public class PullToRefreshListViewSampleActivity extends Activity { 27 | 28 | 29 | 30 | private PullToRefreshListView listView; 31 | private PullToRefreshListViewSampleAdapter adapter; 32 | 33 | // IDs for the context menu actions 34 | private final int idEdit = 1; 35 | private final int idDelete = 2; 36 | 37 | @Override 38 | public void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setContentView(R.layout.main); 41 | 42 | listView = (PullToRefreshListView) findViewById(R.id.pull_to_refresh_listview); 43 | 44 | // OPTIONAL: Disable scrolling when list is refreshing 45 | // listView.setLockScrollWhileRefreshing(false); 46 | 47 | // OPTIONAL: Uncomment this if you want the Pull to Refresh header to show the 'last updated' time 48 | // listView.setShowLastUpdatedText(true); 49 | 50 | // OPTIONAL: Uncomment this if you want to override the date/time format of the 'last updated' field 51 | // listView.setLastUpdatedDateFormat(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")); 52 | 53 | // OPTIONAL: Uncomment this if you want to override the default strings 54 | // listView.setTextPullToRefresh("Pull to Refresh"); 55 | // listView.setTextReleaseToRefresh("Release to Refresh"); 56 | // listView.setTextRefreshing("Refreshing"); 57 | 58 | // MANDATORY: Set the onRefreshListener on the list. You could also use 59 | // listView.setOnRefreshListener(this); and let this Activity 60 | // implement OnRefreshListener. 61 | listView.setOnRefreshListener(new OnRefreshListener() { 62 | 63 | @Override 64 | public void onRefresh() { 65 | // Your code to refresh the list contents goes here 66 | 67 | // for example: 68 | // If this is a webservice call, it might be asynchronous so 69 | // you would have to call listView.onRefreshComplete(); when 70 | // the webservice returns the data 71 | adapter.loadData(); 72 | 73 | // Make sure you call listView.onRefreshComplete() 74 | // when the loading is done. This can be done from here or any 75 | // other place, like on a broadcast receive from your loading 76 | // service or the onPostExecute of your AsyncTask. 77 | 78 | // For the sake of this sample, the code will pause here to 79 | // force a delay when invoking the refresh 80 | listView.postDelayed(new Runnable() { 81 | 82 | 83 | @Override 84 | public void run() { 85 | listView.onRefreshComplete(); 86 | } 87 | }, 2000); 88 | } 89 | }); 90 | 91 | adapter = new PullToRefreshListViewSampleAdapter() {}; 92 | listView.setAdapter(adapter); 93 | 94 | // Request the adapter to load the data 95 | adapter.loadData(); 96 | 97 | // click listener 98 | listView.setOnItemClickListener(new OnItemClickListener() { 99 | 100 | @Override 101 | public void onItemClick(AdapterView arg0, View arg1, int arg2, 102 | long arg3) { 103 | 104 | ViewHolder viewHolder = (ViewHolder) arg1.getTag(); 105 | if (viewHolder.name != null){ 106 | Toast.makeText(PullToRefreshListViewSampleActivity.this, viewHolder.name.getText(), Toast.LENGTH_SHORT).show(); 107 | } 108 | } 109 | }); 110 | 111 | // Register the context menu for actions 112 | registerForContextMenu(listView); 113 | } 114 | 115 | 116 | /** 117 | * Create the context menu with the Edit and Delete options 118 | */ 119 | @Override 120 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 121 | super.onCreateContextMenu(menu, v, menuInfo); 122 | 123 | // Add any actions you need. Implement the logic in onContextItemSelected 124 | menu.add(Menu.NONE, idEdit, Menu.NONE, R.string.edit); 125 | menu.add(Menu.NONE, idDelete, Menu.NONE, R.string.delete); 126 | } 127 | 128 | /** 129 | * Event called after an option from the context menu is selected 130 | */ 131 | @Override 132 | public boolean onContextItemSelected(MenuItem item) { 133 | AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); 134 | 135 | switch (item.getItemId()) { 136 | case idEdit: 137 | 138 | // Put your code here for Edit action 139 | // just as an example a toast message 140 | Toast.makeText(this, getString(R.string.edit) + " " + adapter.getItem(info.position-1), Toast.LENGTH_SHORT).show(); 141 | return true; 142 | case idDelete: 143 | 144 | // Put your code here for Delete action 145 | // just as an example a toast message 146 | Toast.makeText(this, getString(R.string.delete) + " " + adapter.getItem(info.position-1), Toast.LENGTH_SHORT).show(); 147 | return true; 148 | default: 149 | return super.onContextItemSelected(item); 150 | } 151 | } 152 | 153 | 154 | /** 155 | * The adapter used to display the results in the list 156 | * 157 | */ 158 | public abstract class PullToRefreshListViewSampleAdapter extends android.widget.BaseAdapter { 159 | 160 | private ArrayList items = new ArrayList();; 161 | 162 | public class ViewHolder { 163 | public String id; 164 | public TextView name; 165 | } 166 | 167 | /** 168 | * Loads the data. 169 | */ 170 | public void loadData() { 171 | 172 | // Here add your code to load the data for example from a webservice or DB 173 | 174 | items = new ArrayList(); 175 | 176 | items.add("Ajax Amsterdam"); 177 | items.add("Barcelona"); 178 | items.add("Manchester United"); 179 | items.add("Chelsea"); 180 | items.add("Real Madrid"); 181 | items.add("Bayern Munchen"); 182 | items.add("Internazionale"); 183 | items.add("Valencia"); 184 | items.add("Arsenal"); 185 | items.add("AS Roma"); 186 | items.add("Tottenham Hotspur"); 187 | items.add("PSV"); 188 | items.add("Olympique Lyon"); 189 | items.add("AC Milan"); 190 | items.add("Dortmund"); 191 | items.add("Schalke 04"); 192 | items.add("Twente"); 193 | items.add("Porto"); 194 | items.add("Juventus"); 195 | 196 | 197 | // MANDATORY: Notify that the data has changed 198 | notifyDataSetChanged(); 199 | } 200 | 201 | @Override 202 | public int getCount() { 203 | return items.size(); 204 | } 205 | 206 | @Override 207 | public Object getItem(int position) { 208 | return items.get(position); 209 | } 210 | 211 | @Override 212 | public long getItemId(int position) { 213 | return position; 214 | } 215 | 216 | @Override 217 | public View getView(int position, View convertView, ViewGroup parent) { 218 | View rowView = convertView; 219 | 220 | String record = (String) getItem(position); 221 | 222 | LayoutInflater inflater = PullToRefreshListViewSampleActivity.this.getLayoutInflater(); 223 | 224 | ViewHolder viewHolder = new ViewHolder(); 225 | 226 | if (convertView == null){ 227 | rowView = inflater.inflate(R.layout.list_item,null); 228 | 229 | viewHolder.name = (TextView) rowView.findViewById(R.id.textView1); 230 | 231 | rowView.setTag(viewHolder); 232 | } 233 | 234 | final ViewHolder holder = (ViewHolder) rowView.getTag(); 235 | 236 | holder.name.setText(record); 237 | 238 | return rowView; 239 | } 240 | } 241 | 242 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include "libraryproject", "sampleproject" 2 | --------------------------------------------------------------------------------