make layout main.xml
<?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 PullToRefresh-ListView replaces a standard ListView widget,
and has all the features android.widget.ListView has.
-->
<"your package name".sample.PullToRefreshListView
android:id="@+id/pull_to_refresh_listview"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:background="@android:color/white"
android:cacheColorHint="@android:color/white" />
</LinearLayout>
create layout name pull_to_refresh_header.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ptr_headerContainer" >
<RelativeLayout
android:id="@+id/header"
style="@style/ptr_header" >
<ImageView
android:id="@+id/image"
style="@style/ptr_arrow" />
<ProgressBar
android:id="@+id/spinner"
style="@style/ptr_spinner" />
<TextView
android:id="@+id/text"
style="@style/ptr_text" />
</RelativeLayout>
</LinearLayout>
create layout name list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:textColor="@android:color/black"
android:textSize="10pt"
android:padding="5dp"
android:background="@android:color/white"
android:singleLine="true" />
create file under values folder name default_style.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="ptr_headerContainer">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">0px</item>
<item name="android:gravity">bottom</item>
</style>
<style name="ptr_header">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">5dp</item>
</style>
<style name="ptr_arrow">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_centerVertical">true</item>
<item name="android:src">@drawable/ic_pulltorefresh_arrow</item>
<item name="android:paddingLeft">25dp</item>
<item name="android:paddingRight">25dp</item>
</style>
<style name="ptr_spinner" parent="@android:style/Widget.ProgressBar.Small">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_centerVertical">true</item>
<item name="android:indeterminate">true</item>
<item name="android:paddingLeft">25dp</item>
<item name="android:paddingRight">25dp</item>
</style>
<style name="ptr_text">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_centerHorizontal">true</item>
<item name="android:layout_centerVertical">true</item>
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">@android:color/black</item>
</style>
</resources>
put this below string in strings folder
<string name="ptr_pull_to_refresh">Pull to refresh</string>
<string name="ptr_release_to_refresh">Release to refresh</string>
<string name="ptr_refreshing">Refreshing</string>
create class name PullToRefreshListView.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
* A generic, customizable Android ListView implementation that has 'Pull to Refresh' functionality.
*
* This ListView can be used in place of the normal Android android.widget.ListView class.
*
* Users of this class should implement OnRefreshListener and call setOnRefreshListener(..)
* to get notified on refresh events. The using class should call onRefreshComplete() when
* refreshing is finished.
*
* The using class can call setRefreshing() to set the state explicitly to refreshing. This
* is useful when you want to show the spinner and 'Refreshing' text when the
* refresh was not triggered by 'Pull to Refresh', for example on start.
*
* For more information, visit the project page:
* https://github.com/erikwt/PullToRefresh-ListView
*
* @author Erik Wallentinsen <dev+ptr@erikw.eu>
* @version 1.0.0
*/
public class PullToRefreshListView extends ListView{
private static final float PULL_RESISTANCE = 1.7f;
private static final int BOUNCE_ANIMATION_DURATION = 700;
private static final int BOUNCE_ANIMATION_DELAY = 100;
private static final float BOUNCE_OVERSHOOT_TENSION = 1.4f;
private static final int ROTATE_ARROW_ANIMATION_DURATION = 250;
private static enum State{
PULL_TO_REFRESH,
RELEASE_TO_REFRESH,
REFRESHING
}
/**
* Interface to implement when you want to get notified of 'pull to refresh'
* events.
* Call setOnRefreshListener(..) to activate an OnRefreshListener.
*/
public interface OnRefreshListener{
/**
* Method to be called when a refresh is requested
*/
public void onRefresh();
}
private static int measuredHeaderHeight;
private float previousY;
private int headerPadding;
private boolean scrollbarEnabled;
private boolean bounceBackHeader;
private boolean lockScrollWhileRefreshing;
private boolean hasResetHeader;
private String pullToRefreshText;
private String releaseToRefreshText;
private String refreshingText;
private State state;
private LinearLayout headerContainer;
private RelativeLayout header;
private RotateAnimation flipAnimation;
private RotateAnimation reverseFlipAnimation;
private ImageView image;
private ProgressBar spinner;
private TextView text;
private OnItemClickListener onItemClickListener;
private OnRefreshListener onRefreshListener;
public PullToRefreshListView(Context context){
super(context);
init();
}
public PullToRefreshListView(Context context, AttributeSet attrs){
super(context, attrs);
init();
}
public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
init();
}
@Override
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
/**
* Activate an OnRefreshListener to get notified on 'pull to refresh'
* events.
*
* @param onRefreshListener The OnRefreshListener to get notified
*/
public void setOnRefreshListener(OnRefreshListener onRefreshListener){
this.onRefreshListener = onRefreshListener;
}
/**
* @return If the list is in 'Refreshing' state
*/
public boolean isRefreshing(){
return state == State.REFRESHING;
}
/**
* Default is false. When lockScrollWhileRefreshing is set to true, the list
* cannot scroll when in 'refreshing' mode. It's 'locked' on refreshing.
*
* @param lockScrollWhileRefreshing
*/
public void setLockScrollWhileRefreshing(boolean lockScrollWhileRefreshing){
this.lockScrollWhileRefreshing = lockScrollWhileRefreshing;
}
/**
* Explicitly set the state to refreshing. This
* is useful when you want to show the spinner and 'Refreshing' text when
* the refresh was not triggered by 'pull to refresh', for example on start.
*/
public void setRefreshing(){
state = State.REFRESHING;
scrollTo(0, 0);
setUiRefreshing();
setHeaderPadding(0);
}
/**
* Set the state back to 'pull to refresh'. Call this method when refreshing
* the data is finished.
*/
public void onRefreshComplete(){
state = State.PULL_TO_REFRESH;
resetHeader();
}
/**
* Change the label text on state 'Pull to Refresh'
* @param pullToRefreshText Text
*/
public void setTextPullToRefresh(String pullToRefreshText){
this.pullToRefreshText = pullToRefreshText;
if(state == State.PULL_TO_REFRESH){
text.setText(pullToRefreshText);
}
}
/**
* Change the label text on state 'Release to Refresh'
* @param releaseToRefreshText Text
*/
public void setTextReleaseToRefresh(String releaseToRefreshText){
this.releaseToRefreshText = releaseToRefreshText;
if(state == State.RELEASE_TO_REFRESH){
text.setText(releaseToRefreshText);
}
}
/**
* Change the label text on state 'Refreshing'
* @param refreshingText Text
*/
public void setTextRefreshing(String refreshingText){
this.refreshingText = refreshingText;
if(state == State.REFRESHING){
text.setText(refreshingText);
}
}
private void init(){
setVerticalFadingEdgeEnabled(false);
headerContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.pull_to_refresh_header, null);
header = (RelativeLayout) headerContainer.findViewById(R.id.header);
text = (TextView) header.findViewById(R.id.text);
image = (ImageView) header.findViewById(R.id.image);
spinner = (ProgressBar) header.findViewById(R.id.spinner);
pullToRefreshText = getContext().getString(R.string.ptr_pull_to_refresh);
releaseToRefreshText = getContext().getString(R.string.ptr_release_to_refresh);
refreshingText = getContext().getString(R.string.ptr_refreshing);
flipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
flipAnimation.setInterpolator(new LinearInterpolator());
flipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION);
flipAnimation.setFillAfter(true);
reverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseFlipAnimation.setInterpolator(new LinearInterpolator());
reverseFlipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION);
reverseFlipAnimation.setFillAfter(true);
addHeaderView(headerContainer);
setState(State.PULL_TO_REFRESH);
scrollbarEnabled = isVerticalScrollBarEnabled();
ViewTreeObserver vto = header.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new PTROnGlobalLayoutListener());
super.setOnItemClickListener(new PTROnItemClickListener());
}
private void setHeaderPadding(int padding){
headerPadding = padding;
MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) header.getLayoutParams();
mlp.setMargins(0, padding, 0, 0);
header.setLayoutParams(mlp);
}
@Override
public boolean onTouchEvent(MotionEvent event){
if(lockScrollWhileRefreshing && state == State.REFRESHING){
return true;
}
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
if(getFirstVisiblePosition() == 0) previousY = event.getY();
else previousY = -1;
break;
case MotionEvent.ACTION_UP:
if(previousY != -1 && (state == State.RELEASE_TO_REFRESH || getFirstVisiblePosition() == 0)){
switch(state){
case RELEASE_TO_REFRESH:
setState(State.REFRESHING);
bounceBackHeader();
break;
case PULL_TO_REFRESH:
resetHeader();
break;
}
}
break;
case MotionEvent.ACTION_MOVE:
if(previousY != -1){
float y = event.getY();
float diff = y - previousY;
if(diff > 0) diff /= PULL_RESISTANCE;
previousY = y;
int newHeaderPadding = Math.max(headerPadding + Math.round(diff), -header.getHeight());
if(!lockScrollWhileRefreshing && state == State.REFRESHING && newHeaderPadding > 0){
newHeaderPadding = 0;
}
setHeaderPadding(newHeaderPadding);
if(state == State.PULL_TO_REFRESH && headerPadding > 0){
setState(State.RELEASE_TO_REFRESH);
image.clearAnimation();
image.startAnimation(flipAnimation);
}else if(state == State.RELEASE_TO_REFRESH && headerPadding < 0){
setState(State.PULL_TO_REFRESH);
image.clearAnimation();
image.startAnimation(reverseFlipAnimation);
}
}
break;
}
return super.onTouchEvent(event);
}
private void bounceBackHeader(){
int yTranslate = state == State.REFRESHING ? -(headerContainer.getHeight() - header.getHeight()) : -headerContainer.getHeight();
TranslateAnimation bounceAnimation = new TranslateAnimation(
TranslateAnimation.ABSOLUTE, 0,
TranslateAnimation.ABSOLUTE, 0,
TranslateAnimation.ABSOLUTE, 0,
TranslateAnimation.ABSOLUTE, yTranslate);
bounceAnimation.setDuration(BOUNCE_ANIMATION_DURATION);
bounceAnimation.setFillEnabled(true);
bounceAnimation.setFillAfter(false);
bounceAnimation.setFillBefore(true);
bounceAnimation.setInterpolator(new OvershootInterpolator(BOUNCE_OVERSHOOT_TENSION));
bounceAnimation.setAnimationListener(new HeaderAnimationListener());
startAnimation(bounceAnimation);
}
private void resetHeader(){
if(headerPadding == -header.getHeight() || getFirstVisiblePosition() > 0){
setState(State.PULL_TO_REFRESH);
return;
}
if(getAnimation() != null && !getAnimation().hasEnded()){
bounceBackHeader = true;
}else{
bounceBackHeader();
}
}
private void setUiRefreshing(){
spinner.setVisibility(View.VISIBLE);
image.clearAnimation();
image.setVisibility(View.INVISIBLE);
text.setText(refreshingText);
}
private void setState(State state){
this.state = state;
switch(state){
case PULL_TO_REFRESH:
spinner.setVisibility(View.INVISIBLE);
image.setVisibility(View.VISIBLE);
text.setText(pullToRefreshText);
break;
case RELEASE_TO_REFRESH:
spinner.setVisibility(View.INVISIBLE);
image.setVisibility(View.VISIBLE);
text.setText(releaseToRefreshText);
break;
case REFRESHING:
setUiRefreshing();
if(onRefreshListener == null){
setState(State.PULL_TO_REFRESH);
}else{
onRefreshListener.onRefresh();
}
break;
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if(!hasResetHeader){
if(measuredHeaderHeight > 0 && state != State.REFRESHING){
setHeaderPadding(-measuredHeaderHeight);
}
hasResetHeader = true;
}
}
private class HeaderAnimationListener implements AnimationListener{
private int height;
private State stateAtAnimationStart;
@Override
public void onAnimationStart(Animation animation){
stateAtAnimationStart = state;
android.view.ViewGroup.LayoutParams lp = getLayoutParams();
height = lp.height;
lp.height = getHeight() + headerContainer.getHeight();
setLayoutParams(lp);
if(scrollbarEnabled){
setVerticalScrollBarEnabled(false);
}
}
@Override
public void onAnimationEnd(Animation animation){
setHeaderPadding(stateAtAnimationStart == State.REFRESHING ? 0 : -header.getHeight());
android.view.ViewGroup.LayoutParams lp = getLayoutParams();
lp.height = height;
setLayoutParams(lp);
if(scrollbarEnabled){
setVerticalScrollBarEnabled(true);
}
if(bounceBackHeader){
bounceBackHeader = false;
postDelayed(new Runnable(){
@Override
public void run(){
bounceBackHeader();
}
}, BOUNCE_ANIMATION_DELAY);
}else if(stateAtAnimationStart != State.REFRESHING){
setState(State.PULL_TO_REFRESH);
}
}
@Override
public void onAnimationRepeat(Animation animation){}
}
private class PTROnGlobalLayoutListener implements OnGlobalLayoutListener{
@Override
public void onGlobalLayout() {
int initialHeaderHeight = header.getHeight();
if(initialHeaderHeight > 0){
measuredHeaderHeight = initialHeaderHeight;
if(measuredHeaderHeight > 0 && state != State.REFRESHING){
setHeaderPadding(-measuredHeaderHeight);
requestLayout();
}
}
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
private class PTROnItemClickListener implements OnItemClickListener{
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
hasResetHeader = false;
if(onItemClickListener != null){
onItemClickListener.onItemClick(adapterView, view, position, id);
}
}
}
}
create other new class name PullToRefreshListViewSampleActivity.java
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import eu.erikw.pulltorefresh.sample.PullToRefreshListView;
import eu.erikw.pulltorefresh.sample.PullToRefreshListView.OnRefreshListener;
public class PullToRefreshListViewSampleActivity extends Activity {
private static ArrayList<String> items;
static
{
items = new ArrayList<String>();
items.add("Android");
items.add("Blackberry");
items.add("I-phone");
items.add("Samsung");
items.add("Nokia");
items.add("Micromax");
items.add("Sony");
items.add("Relience");
}
private PullToRefreshListView listView;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
listView = (PullToRefreshListView) findViewById(R.id.pull_to_refresh_listview);
// Set the onRefreshListener on the list. You could also use
// listView.setOnRefreshListener(this); and let this Activity
// implement OnRefreshListener.
listView.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh()
{
// Your code to refresh the list contents goes here
// Make sure you call listView.onRefreshComplete()
// when the loading is done. This can be done from here or any
// other place, like on a broadcast receive from your loading
// service or the onPostExecute of your AsyncTask.
// For the sake of this sample, the code will pause here to
// force a delay when invoking the refresh
listView.postDelayed(new Runnable() {
@Override
public void run() {
listView.onRefreshComplete();
}
}, 2000);
}
});
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, items);
listView.setAdapter(adapter);
}
}
<?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 PullToRefresh-ListView replaces a standard ListView widget,
and has all the features android.widget.ListView has.
-->
<"your package name".sample.PullToRefreshListView
android:id="@+id/pull_to_refresh_listview"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:background="@android:color/white"
android:cacheColorHint="@android:color/white" />
</LinearLayout>
create layout name pull_to_refresh_header.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ptr_headerContainer" >
<RelativeLayout
android:id="@+id/header"
style="@style/ptr_header" >
<ImageView
android:id="@+id/image"
style="@style/ptr_arrow" />
<ProgressBar
android:id="@+id/spinner"
style="@style/ptr_spinner" />
<TextView
android:id="@+id/text"
style="@style/ptr_text" />
</RelativeLayout>
</LinearLayout>
create layout name list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:textColor="@android:color/black"
android:textSize="10pt"
android:padding="5dp"
android:background="@android:color/white"
android:singleLine="true" />
create file under values folder name default_style.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="ptr_headerContainer">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">0px</item>
<item name="android:gravity">bottom</item>
</style>
<style name="ptr_header">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">5dp</item>
</style>
<style name="ptr_arrow">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_centerVertical">true</item>
<item name="android:src">@drawable/ic_pulltorefresh_arrow</item>
<item name="android:paddingLeft">25dp</item>
<item name="android:paddingRight">25dp</item>
</style>
<style name="ptr_spinner" parent="@android:style/Widget.ProgressBar.Small">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_centerVertical">true</item>
<item name="android:indeterminate">true</item>
<item name="android:paddingLeft">25dp</item>
<item name="android:paddingRight">25dp</item>
</style>
<style name="ptr_text">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_centerHorizontal">true</item>
<item name="android:layout_centerVertical">true</item>
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">@android:color/black</item>
</style>
</resources>
put this below string in strings folder
<string name="ptr_pull_to_refresh">Pull to refresh</string>
<string name="ptr_release_to_refresh">Release to refresh</string>
<string name="ptr_refreshing">Refreshing</string>
create class name PullToRefreshListView.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
* A generic, customizable Android ListView implementation that has 'Pull to Refresh' functionality.
*
* This ListView can be used in place of the normal Android android.widget.ListView class.
*
* Users of this class should implement OnRefreshListener and call setOnRefreshListener(..)
* to get notified on refresh events. The using class should call onRefreshComplete() when
* refreshing is finished.
*
* The using class can call setRefreshing() to set the state explicitly to refreshing. This
* is useful when you want to show the spinner and 'Refreshing' text when the
* refresh was not triggered by 'Pull to Refresh', for example on start.
*
* For more information, visit the project page:
* https://github.com/erikwt/PullToRefresh-ListView
*
* @author Erik Wallentinsen <dev+ptr@erikw.eu>
* @version 1.0.0
*/
public class PullToRefreshListView extends ListView{
private static final float PULL_RESISTANCE = 1.7f;
private static final int BOUNCE_ANIMATION_DURATION = 700;
private static final int BOUNCE_ANIMATION_DELAY = 100;
private static final float BOUNCE_OVERSHOOT_TENSION = 1.4f;
private static final int ROTATE_ARROW_ANIMATION_DURATION = 250;
private static enum State{
PULL_TO_REFRESH,
RELEASE_TO_REFRESH,
REFRESHING
}
/**
* Interface to implement when you want to get notified of 'pull to refresh'
* events.
* Call setOnRefreshListener(..) to activate an OnRefreshListener.
*/
public interface OnRefreshListener{
/**
* Method to be called when a refresh is requested
*/
public void onRefresh();
}
private static int measuredHeaderHeight;
private float previousY;
private int headerPadding;
private boolean scrollbarEnabled;
private boolean bounceBackHeader;
private boolean lockScrollWhileRefreshing;
private boolean hasResetHeader;
private String pullToRefreshText;
private String releaseToRefreshText;
private String refreshingText;
private State state;
private LinearLayout headerContainer;
private RelativeLayout header;
private RotateAnimation flipAnimation;
private RotateAnimation reverseFlipAnimation;
private ImageView image;
private ProgressBar spinner;
private TextView text;
private OnItemClickListener onItemClickListener;
private OnRefreshListener onRefreshListener;
public PullToRefreshListView(Context context){
super(context);
init();
}
public PullToRefreshListView(Context context, AttributeSet attrs){
super(context, attrs);
init();
}
public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
init();
}
@Override
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
/**
* Activate an OnRefreshListener to get notified on 'pull to refresh'
* events.
*
* @param onRefreshListener The OnRefreshListener to get notified
*/
public void setOnRefreshListener(OnRefreshListener onRefreshListener){
this.onRefreshListener = onRefreshListener;
}
/**
* @return If the list is in 'Refreshing' state
*/
public boolean isRefreshing(){
return state == State.REFRESHING;
}
/**
* Default is false. When lockScrollWhileRefreshing is set to true, the list
* cannot scroll when in 'refreshing' mode. It's 'locked' on refreshing.
*
* @param lockScrollWhileRefreshing
*/
public void setLockScrollWhileRefreshing(boolean lockScrollWhileRefreshing){
this.lockScrollWhileRefreshing = lockScrollWhileRefreshing;
}
/**
* Explicitly set the state to refreshing. This
* is useful when you want to show the spinner and 'Refreshing' text when
* the refresh was not triggered by 'pull to refresh', for example on start.
*/
public void setRefreshing(){
state = State.REFRESHING;
scrollTo(0, 0);
setUiRefreshing();
setHeaderPadding(0);
}
/**
* Set the state back to 'pull to refresh'. Call this method when refreshing
* the data is finished.
*/
public void onRefreshComplete(){
state = State.PULL_TO_REFRESH;
resetHeader();
}
/**
* Change the label text on state 'Pull to Refresh'
* @param pullToRefreshText Text
*/
public void setTextPullToRefresh(String pullToRefreshText){
this.pullToRefreshText = pullToRefreshText;
if(state == State.PULL_TO_REFRESH){
text.setText(pullToRefreshText);
}
}
/**
* Change the label text on state 'Release to Refresh'
* @param releaseToRefreshText Text
*/
public void setTextReleaseToRefresh(String releaseToRefreshText){
this.releaseToRefreshText = releaseToRefreshText;
if(state == State.RELEASE_TO_REFRESH){
text.setText(releaseToRefreshText);
}
}
/**
* Change the label text on state 'Refreshing'
* @param refreshingText Text
*/
public void setTextRefreshing(String refreshingText){
this.refreshingText = refreshingText;
if(state == State.REFRESHING){
text.setText(refreshingText);
}
}
private void init(){
setVerticalFadingEdgeEnabled(false);
headerContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.pull_to_refresh_header, null);
header = (RelativeLayout) headerContainer.findViewById(R.id.header);
text = (TextView) header.findViewById(R.id.text);
image = (ImageView) header.findViewById(R.id.image);
spinner = (ProgressBar) header.findViewById(R.id.spinner);
pullToRefreshText = getContext().getString(R.string.ptr_pull_to_refresh);
releaseToRefreshText = getContext().getString(R.string.ptr_release_to_refresh);
refreshingText = getContext().getString(R.string.ptr_refreshing);
flipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
flipAnimation.setInterpolator(new LinearInterpolator());
flipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION);
flipAnimation.setFillAfter(true);
reverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseFlipAnimation.setInterpolator(new LinearInterpolator());
reverseFlipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION);
reverseFlipAnimation.setFillAfter(true);
addHeaderView(headerContainer);
setState(State.PULL_TO_REFRESH);
scrollbarEnabled = isVerticalScrollBarEnabled();
ViewTreeObserver vto = header.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new PTROnGlobalLayoutListener());
super.setOnItemClickListener(new PTROnItemClickListener());
}
private void setHeaderPadding(int padding){
headerPadding = padding;
MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) header.getLayoutParams();
mlp.setMargins(0, padding, 0, 0);
header.setLayoutParams(mlp);
}
@Override
public boolean onTouchEvent(MotionEvent event){
if(lockScrollWhileRefreshing && state == State.REFRESHING){
return true;
}
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
if(getFirstVisiblePosition() == 0) previousY = event.getY();
else previousY = -1;
break;
case MotionEvent.ACTION_UP:
if(previousY != -1 && (state == State.RELEASE_TO_REFRESH || getFirstVisiblePosition() == 0)){
switch(state){
case RELEASE_TO_REFRESH:
setState(State.REFRESHING);
bounceBackHeader();
break;
case PULL_TO_REFRESH:
resetHeader();
break;
}
}
break;
case MotionEvent.ACTION_MOVE:
if(previousY != -1){
float y = event.getY();
float diff = y - previousY;
if(diff > 0) diff /= PULL_RESISTANCE;
previousY = y;
int newHeaderPadding = Math.max(headerPadding + Math.round(diff), -header.getHeight());
if(!lockScrollWhileRefreshing && state == State.REFRESHING && newHeaderPadding > 0){
newHeaderPadding = 0;
}
setHeaderPadding(newHeaderPadding);
if(state == State.PULL_TO_REFRESH && headerPadding > 0){
setState(State.RELEASE_TO_REFRESH);
image.clearAnimation();
image.startAnimation(flipAnimation);
}else if(state == State.RELEASE_TO_REFRESH && headerPadding < 0){
setState(State.PULL_TO_REFRESH);
image.clearAnimation();
image.startAnimation(reverseFlipAnimation);
}
}
break;
}
return super.onTouchEvent(event);
}
private void bounceBackHeader(){
int yTranslate = state == State.REFRESHING ? -(headerContainer.getHeight() - header.getHeight()) : -headerContainer.getHeight();
TranslateAnimation bounceAnimation = new TranslateAnimation(
TranslateAnimation.ABSOLUTE, 0,
TranslateAnimation.ABSOLUTE, 0,
TranslateAnimation.ABSOLUTE, 0,
TranslateAnimation.ABSOLUTE, yTranslate);
bounceAnimation.setDuration(BOUNCE_ANIMATION_DURATION);
bounceAnimation.setFillEnabled(true);
bounceAnimation.setFillAfter(false);
bounceAnimation.setFillBefore(true);
bounceAnimation.setInterpolator(new OvershootInterpolator(BOUNCE_OVERSHOOT_TENSION));
bounceAnimation.setAnimationListener(new HeaderAnimationListener());
startAnimation(bounceAnimation);
}
private void resetHeader(){
if(headerPadding == -header.getHeight() || getFirstVisiblePosition() > 0){
setState(State.PULL_TO_REFRESH);
return;
}
if(getAnimation() != null && !getAnimation().hasEnded()){
bounceBackHeader = true;
}else{
bounceBackHeader();
}
}
private void setUiRefreshing(){
spinner.setVisibility(View.VISIBLE);
image.clearAnimation();
image.setVisibility(View.INVISIBLE);
text.setText(refreshingText);
}
private void setState(State state){
this.state = state;
switch(state){
case PULL_TO_REFRESH:
spinner.setVisibility(View.INVISIBLE);
image.setVisibility(View.VISIBLE);
text.setText(pullToRefreshText);
break;
case RELEASE_TO_REFRESH:
spinner.setVisibility(View.INVISIBLE);
image.setVisibility(View.VISIBLE);
text.setText(releaseToRefreshText);
break;
case REFRESHING:
setUiRefreshing();
if(onRefreshListener == null){
setState(State.PULL_TO_REFRESH);
}else{
onRefreshListener.onRefresh();
}
break;
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if(!hasResetHeader){
if(measuredHeaderHeight > 0 && state != State.REFRESHING){
setHeaderPadding(-measuredHeaderHeight);
}
hasResetHeader = true;
}
}
private class HeaderAnimationListener implements AnimationListener{
private int height;
private State stateAtAnimationStart;
@Override
public void onAnimationStart(Animation animation){
stateAtAnimationStart = state;
android.view.ViewGroup.LayoutParams lp = getLayoutParams();
height = lp.height;
lp.height = getHeight() + headerContainer.getHeight();
setLayoutParams(lp);
if(scrollbarEnabled){
setVerticalScrollBarEnabled(false);
}
}
@Override
public void onAnimationEnd(Animation animation){
setHeaderPadding(stateAtAnimationStart == State.REFRESHING ? 0 : -header.getHeight());
android.view.ViewGroup.LayoutParams lp = getLayoutParams();
lp.height = height;
setLayoutParams(lp);
if(scrollbarEnabled){
setVerticalScrollBarEnabled(true);
}
if(bounceBackHeader){
bounceBackHeader = false;
postDelayed(new Runnable(){
@Override
public void run(){
bounceBackHeader();
}
}, BOUNCE_ANIMATION_DELAY);
}else if(stateAtAnimationStart != State.REFRESHING){
setState(State.PULL_TO_REFRESH);
}
}
@Override
public void onAnimationRepeat(Animation animation){}
}
private class PTROnGlobalLayoutListener implements OnGlobalLayoutListener{
@Override
public void onGlobalLayout() {
int initialHeaderHeight = header.getHeight();
if(initialHeaderHeight > 0){
measuredHeaderHeight = initialHeaderHeight;
if(measuredHeaderHeight > 0 && state != State.REFRESHING){
setHeaderPadding(-measuredHeaderHeight);
requestLayout();
}
}
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
private class PTROnItemClickListener implements OnItemClickListener{
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
hasResetHeader = false;
if(onItemClickListener != null){
onItemClickListener.onItemClick(adapterView, view, position, id);
}
}
}
}
create other new class name PullToRefreshListViewSampleActivity.java
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import eu.erikw.pulltorefresh.sample.PullToRefreshListView;
import eu.erikw.pulltorefresh.sample.PullToRefreshListView.OnRefreshListener;
public class PullToRefreshListViewSampleActivity extends Activity {
private static ArrayList<String> items;
static
{
items = new ArrayList<String>();
items.add("Android");
items.add("Blackberry");
items.add("I-phone");
items.add("Samsung");
items.add("Nokia");
items.add("Micromax");
items.add("Sony");
items.add("Relience");
}
private PullToRefreshListView listView;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
listView = (PullToRefreshListView) findViewById(R.id.pull_to_refresh_listview);
// Set the onRefreshListener on the list. You could also use
// listView.setOnRefreshListener(this); and let this Activity
// implement OnRefreshListener.
listView.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh()
{
// Your code to refresh the list contents goes here
// Make sure you call listView.onRefreshComplete()
// when the loading is done. This can be done from here or any
// other place, like on a broadcast receive from your loading
// service or the onPostExecute of your AsyncTask.
// For the sake of this sample, the code will pause here to
// force a delay when invoking the refresh
listView.postDelayed(new Runnable() {
@Override
public void run() {
listView.onRefreshComplete();
}
}, 2000);
}
});
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, items);
listView.setAdapter(adapter);
}
}
No comments:
Post a Comment
Comments