I'm writing own Android application with ListView and PullToRefresh for refresh this list. After adding pull-to-refresh i've got that bug: when i'm pulling list to refresh some items were clicked. How i can fix it?
Here is code of my MainActivity:
package ua.iqw.mistinfo.news;
import android.os.Bundle;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View.OnTouchListener;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import ua.iqw.mistinfo.news.trace.ExceptionHandler;
import ua.iqw.mistinfo.news.PullToRefreshListView;
import ua.iqw.mistinfo.news.PullToRefreshListView.OnRefreshListener;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends ListActivity implements OnTouchListener{
ArrayList<ListData> news;
AsyncLoad asyncNews;
RefreshList refresh;
ProgressDialog spinner;
#Override
protected void onCreate(Bundle savedInstanceState) {
// ExceptionHandler.register(this,
// "http://errors.bazalt-cms.com/add-android/");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final PullToRefreshListView listView = (PullToRefreshListView)findViewById(android.R.id.list);
spinner = new ProgressDialog(MainActivity.this);
spinner.setMessage(getString(R.string.loading));
spinner.show();
Network net = new Network(this);
if (net.isNetworkAvailable() == true) {
Log.d("NETWORK", "Network is available!");
} else {
Toast.makeText(this, getString(R.string.connect_error),
Toast.LENGTH_LONG).show();
}
asyncNews = new AsyncLoad(MainActivity.this);
asyncNews.execute();
listView.setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh() {
refresh = new RefreshList(MainActivity.this, listView);
refresh.execute();
}
});
}
public void onResume() {
super.onResume();
if (spinner.isShowing()) {
spinner.dismiss();
}
}
public void onListItemClick(ListView parent, View v, int position, long id) {//listener for click on listView item
try {
news = asyncNews.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
ListData ld = news.get(position);
spinner.setMessage(getString(R.string.loading));
spinner.show();
Intent intent = new Intent(MainActivity.this, DetailsActivity.class);
intent.putExtra("id", ld.id);
startActivity(intent);
}
}
Is it possible to set some timeout for onListItemClick?
Or it can be solved in other way?
Please, help me!
P.S. sorry for my English)
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
public class PullToRefreshListView extends ListView implements OnScrollListener {
private static final int TAP_TO_REFRESH = 1;
private static final int PULL_TO_REFRESH = 2;
private static final int RELEASE_TO_REFRESH = 3;
private static final int REFRESHING = 4;
private static final String TAG = "PullToRefreshListView";
private OnRefreshListener mOnRefreshListener;
/**
* Listener that will receive notifications every time the list scrolls.
*/
private OnScrollListener mOnScrollListener;
private LayoutInflater mInflater;
private RelativeLayout mRefreshView;
private TextView mRefreshViewText;
private ImageView mRefreshViewImage;
private ProgressBar mRefreshViewProgress;
private TextView mRefreshViewLastUpdated;
private int mCurrentScrollState;
private int mRefreshState;
private RotateAnimation mFlipAnimation;
private RotateAnimation mReverseFlipAnimation;
private int mRefreshViewHeight;
private int mRefreshOriginalTopPadding;
private int mLastMotionY;
private boolean mBounceHack;
public PullToRefreshListView(Context context) {
super(context);
init(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
// Load all of the animations we need in code rather than through XML
mFlipAnimation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(250);
mFlipAnimation.setFillAfter(true);
mReverseFlipAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
mReverseFlipAnimation.setDuration(250);
mReverseFlipAnimation.setFillAfter(true);
mInflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mRefreshView = (RelativeLayout) mInflater.inflate(
R.layout.pull_to_refresh_header, this, false);
mRefreshViewText =
(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text);
mRefreshViewImage =
(ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image);
mRefreshViewProgress =
(ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress);
mRefreshViewLastUpdated =
(TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at);
mRefreshViewImage.setMinimumHeight(50);
mRefreshView.setOnClickListener(new OnClickRefreshListener());
mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();
mRefreshState = TAP_TO_REFRESH;
addHeaderView(mRefreshView);
super.setOnScrollListener(this);
measureView(mRefreshView);
mRefreshViewHeight = mRefreshView.getMeasuredHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setSelection(1);
}
#Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
setSelection(1);
}
/**
* Set the listener that will receive notifications every time the list
* scrolls.
*
* #param l The scroll listener.
*/
#Override
public void setOnScrollListener(AbsListView.OnScrollListener l) {
mOnScrollListener = l;
}
/**
* Register a callback to be invoked when this list should be refreshed.
*
* #param onRefreshListener The callback to run.
*/
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
mOnRefreshListener = onRefreshListener;
}
/**
* Set a text to represent when the list was last updated.
* #param lastUpdated Last updated at.
*/
public void setLastUpdated(CharSequence lastUpdated) {
if (lastUpdated != null) {
mRefreshViewLastUpdated.setVisibility(View.VISIBLE);
mRefreshViewLastUpdated.setText(lastUpdated);
} else {
mRefreshViewLastUpdated.setVisibility(View.GONE);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
final int y = (int) event.getY();
mBounceHack = false;
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (!isVerticalScrollBarEnabled()) {
setVerticalScrollBarEnabled(true);
}
if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
if ((mRefreshView.getBottom() >= mRefreshViewHeight
|| mRefreshView.getTop() >= 0)
&& mRefreshState == RELEASE_TO_REFRESH) {
// Initiate the refresh
mRefreshState = REFRESHING;
prepareForRefresh();
onRefresh();
} else if (mRefreshView.getBottom() < mRefreshViewHeight
|| mRefreshView.getTop() <= 0) {
// Abort refresh and scroll down below the refresh view
resetHeader();
setSelection(1);
}
}
break;
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
applyHeaderPadding(event);
break;
}
return super.onTouchEvent(event);
}
private void applyHeaderPadding(MotionEvent ev) {
// getHistorySize has been available since API 1
int pointerCount = ev.getHistorySize();
for (int p = 0; p < pointerCount; p++) {
if (mRefreshState == RELEASE_TO_REFRESH) {
if (isVerticalFadingEdgeEnabled()) {
setVerticalScrollBarEnabled(false);
}
int historicalY = (int) ev.getHistoricalY(p);
// Calculate the padding to apply, we divide by 1.7 to
// simulate a more resistant effect during pull.
int topPadding = (int) (((historicalY - mLastMotionY)
- mRefreshViewHeight) / 1.7);
mRefreshView.setPadding(
mRefreshView.getPaddingLeft(),
topPadding,
mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
}
}
/**
* Sets the header padding back to original size.
*/
private void resetHeaderPadding() {
mRefreshView.setPadding(
mRefreshView.getPaddingLeft(),
mRefreshOriginalTopPadding,
mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
/**
* Resets the header to the original state.
*/
private void resetHeader() {
if (mRefreshState != TAP_TO_REFRESH) {
mRefreshState = TAP_TO_REFRESH;
resetHeaderPadding();
// Set refresh view text to the pull label
mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);
// Replace refresh drawable with arrow drawable
mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);
// Clear the full rotation animation
mRefreshViewImage.clearAnimation();
// Hide progress bar and arrow.
mRefreshViewImage.setVisibility(View.GONE);
mRefreshViewProgress.setVisibility(View.GONE);
}
}
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0,
0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// When the refresh view is completely visible, change the text to say
// "Release to refresh..." and flip the arrow drawable.
if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL
&& mRefreshState != REFRESHING) {
if (firstVisibleItem == 0) {
mRefreshViewImage.setVisibility(View.VISIBLE);
if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20
|| mRefreshView.getTop() >= 0)
&& mRefreshState != RELEASE_TO_REFRESH) {
mRefreshViewText.setText(R.string.pull_to_refresh_release_label);
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mFlipAnimation);
mRefreshState = RELEASE_TO_REFRESH;
} else if (mRefreshView.getBottom() < mRefreshViewHeight + 20
&& mRefreshState != PULL_TO_REFRESH) {
mRefreshViewText.setText(R.string.pull_to_refresh_pull_label);
if (mRefreshState != TAP_TO_REFRESH) {
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mReverseFlipAnimation);
}
mRefreshState = PULL_TO_REFRESH;
}
} else {
mRefreshViewImage.setVisibility(View.GONE);
resetHeader();
}
} else if (mCurrentScrollState == SCROLL_STATE_FLING
&& firstVisibleItem == 0
&& mRefreshState != REFRESHING) {
setSelection(1);
mBounceHack = true;
} else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {
setSelection(1);
}
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem,
visibleItemCount, totalItemCount);
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
mCurrentScrollState = scrollState;
if (mCurrentScrollState == SCROLL_STATE_IDLE) {
mBounceHack = false;
}
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
public void prepareForRefresh() {
resetHeaderPadding();
mRefreshViewImage.setVisibility(View.GONE);
// We need this hack, otherwise it will keep the previous drawable.
mRefreshViewImage.setImageDrawable(null);
mRefreshViewProgress.setVisibility(View.VISIBLE);
// Set refresh view text to the refreshing label
mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);
mRefreshState = REFRESHING;
}
public void onRefresh() {
Log.d(TAG, "onRefresh");
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
}
/**
* Resets the list to a normal state after a refresh.
* #param lastUpdated Last updated at.
*/
public void onRefreshComplete(CharSequence lastUpdated) {
setLastUpdated(lastUpdated);
onRefreshComplete();
}
/**
* Resets the list to a normal state after a refresh.
*/
public void onRefreshComplete() {
Log.d(TAG, "onRefreshComplete");
resetHeader();
// If refresh view is visible when loading completes, scroll down to
// the next item.
if (mRefreshView.getBottom() > 0) {
invalidateViews();
setSelection(1);
}
}
/**
* Invoked when the refresh view is clicked on. This is mainly used when
* there's only a few items in the list and it's not possible to drag the
* list.
*/
private class OnClickRefreshListener implements OnClickListener {
#Override
public void onClick(View v) {
if (mRefreshState != REFRESHING) {
prepareForRefresh();
onRefresh();
}
}
}
/**
* Interface definition for a callback to be invoked when list should be
* refreshed.
*/
public interface OnRefreshListener {
/**
* Called when the list should be refreshed.
* <p>
* A call to {#link PullToRefreshListView #onRefreshComplete()} is
* expected to indicate that the refresh has completed.
*/
public void onRefresh();
}
}
Try it
Related
In my Application I added Swipe to dismiss a item along with Undo option in Listview.
Requried:
I want to add the Section Headers from Server in Listview Like Group1,Group2,..etc.
Code for Swipe to dismiss with Undo.Please help me to achieve my Requirement.
Link i referred
ListviewActivity.class
package com.swipe.delete;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.hudomju.swipe.SwipeToDismissTouchListener;
import com.hudomju.swipe.adapter.ListViewAdapter;
import java.util.ArrayList;
import java.util.List;
import static android.widget.Toast.LENGTH_SHORT;
public class ListViewActivity extends Activity {
private static final int TIME_TO_AUTOMATICALLY_DISMISS_ITEM = 3000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_view_activity);
init((ListView) findViewById(R.id.list_view));
}
private void init(ListView listView) {
final MyBaseAdapter adapter = new MyBaseAdapter();
listView.setAdapter(adapter);
final SwipeToDismissTouchListener<ListViewAdapter> touchListener =
new SwipeToDismissTouchListener<>(
new ListViewAdapter(listView),
new SwipeToDismissTouchListener.DismissCallbacks<ListViewAdapter>() {
#Override
public boolean canDismiss(int position) {
return true;
}
#Override
public void onPendingDismiss(ListViewAdapter recyclerView, int position) {
}
#Override
public void onDismiss(ListViewAdapter view, int position) {
adapter.remove(position);
}
});
touchListener.setDismissDelay(TIME_TO_AUTOMATICALLY_DISMISS_ITEM);
listView.setOnTouchListener(touchListener);
// Setting this scroll listener is required to ensure that during ListView scrolling,
// we don't look for swipes.
listView.setOnScrollListener((AbsListView.OnScrollListener) touchListener.makeScrollListener());
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (touchListener.existPendingDismisses()) {
touchListener.undoPendingDismiss();
} else {
Toast.makeText(ListViewActivity.this, "Position " + position, LENGTH_SHORT).show();
}
}
});
}
static class MyBaseAdapter extends BaseAdapter {
private static final int SIZE = 100;
private final List<String> mDataSet = new ArrayList<>();
MyBaseAdapter() {
for (int i = 0; i < SIZE; i++)
mDataSet.add(i, "This is row number " + i);
}
#Override
public int getCount() {
return mDataSet.size();
}
#Override
public String getItem(int position) {
return mDataSet.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public void remove(int position) {
mDataSet.remove(position);
notifyDataSetChanged();
}
static class ViewHolder {
TextView dataTextView;
ViewHolder(View view) {
dataTextView = (TextView) view.findViewById(R.id.txt_data);
view.setTag(this);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = convertView == null
? new ViewHolder(convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false))
: (ViewHolder) convertView.getTag();
viewHolder.dataTextView.setText(mDataSet.get(position));
return convertView;
}
}
}
SwipeToDismissTouchListener.class
package com.swipe.Delete;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Rect;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ListView;
public class SwipeToDismissTouchListener<SomeCollectionView extends ViewAdapter> implements
View.OnTouchListener {
// Cached ViewConfiguration and system-wide constant values
private final int mSlop;
private final int mMinFlingVelocity;
private final int mMaxFlingVelocity;
private final long mAnimationTime;
// Fixed properties
private final SomeCollectionView mRecyclerView;
private final DismissCallbacks<SomeCollectionView> mCallbacks;
private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
// Transient properties
private PendingDismissData mPendingDismiss;
private float mDownX;
private float mDownY;
private boolean mSwiping;
private int mSwipingSlop;
private VelocityTracker mVelocityTracker;
private int mDownPosition;
private RowContainer mRowContainer;
private boolean mPaused;
// Handler to dismiss pending items after a delay
private final Handler mHandler;
private final Runnable mDismissRunnable = new Runnable() {
#Override
public void run() {
processPendingDismisses();
}
};
private long mDismissDelayMillis = -1; // negative to disable automatic dismissing
public class RowContainer {
final View container;
final View dataContainer;
final View undoContainer;
boolean dataContainerHasBeenDismissed;
public RowContainer(ViewGroup container) {
this.container = container;
dataContainer = container.getChildAt(0);
undoContainer = container.getChildAt(1);
dataContainerHasBeenDismissed = false;
}
View getCurrentSwipingView() {
return dataContainerHasBeenDismissed ? undoContainer: dataContainer;
}
}
/**
* The callback interface used by {#link SwipeToDismissTouchListener} to inform its client
* about a successful dismissal of one or more list item positions.
*/
public interface DismissCallbacks<SomeCollectionView extends ViewAdapter> {
/**
* Called to determine whether the given position can be dismissed.
*/
boolean canDismiss(int position);
/**
* Called when an item is swiped away by the user and the undo layout is completely visible.
* Do NOT remove the list item yet, that should be done in { #onDismiss(com.hudomju.swipe.adapter.ViewAdapter, int)}
* This may also be called immediately before and item is completely dismissed.
*
* #param recyclerView The originating {android.support.v7.widget.RecyclerView}.
* #param position The position of the dismissed item.
*/
void onPendingDismiss(SomeCollectionView recyclerView, int position);
/**
* Called when the item is completely dismissed and removed from the list, after the undo layout is hidden.
*
* #param recyclerView The originating { android.support.v7.widget.RecyclerView}.
* #param position The position of the dismissed item.
*/
void onDismiss(SomeCollectionView recyclerView, int position);
}
/**
* Constructs a new swipe-to-dismiss touch listener for the given list view.
*
* #param recyclerView The list view whose items should be dismissable.
* #param callbacks The callback to trigger when the user has indicated that she would like to
* dismiss one or more list items.
*/
public SwipeToDismissTouchListener(SomeCollectionView recyclerView,
DismissCallbacks<SomeCollectionView> callbacks) {
ViewConfiguration vc = ViewConfiguration.get(recyclerView.getContext());
mSlop = vc.getScaledTouchSlop();
mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
mAnimationTime = recyclerView.getContext().getResources().getInteger(
android.R.integer.config_shortAnimTime);
mRecyclerView = recyclerView;
mCallbacks = callbacks;
mHandler = new Handler();
}
/**
* Enables or disables (pauses or resumes) watching for swipe-to-dismiss gestures.
*
* #param enabled Whether or not to watch for gestures.
*/
public void setEnabled(boolean enabled) {
mPaused = !enabled;
}
/**
* Set the delay after which the pending items will be dismissed when there was no user action.
* Set to a negative value to disable automatic dismissing items.
* #param dismissDelayMillis The delay between onPendingDismiss and onDismiss calls, in milliseconds.
*/
public void setDismissDelay(long dismissDelayMillis) {
this.mDismissDelayMillis = dismissDelayMillis;
}
/**
* Returns an {#link AbsListView.OnScrollListener} to be added to the {#link
* ListView} using {#link ListView#setOnScrollListener(AbsListView.OnScrollListener)}.
* If a scroll listener is already assigned, the caller should still pass scroll changes through
* to this listener. This will ensure that this {#link SwipeToDismissTouchListener} is
* paused during list view scrolling.</p>
*
* #see SwipeToDismissTouchListener
*/
public Object makeScrollListener() {
return mRecyclerView.makeScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
processPendingDismisses();
setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
#Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
});
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (mViewWidth < 2) {
mViewWidth = mRecyclerView.getWidth();
}
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
if (mPaused) {
return false;
}
// TODO: ensure this is a finger, and set a flag
// Find the child view that was touched (perform a hit test)
Rect rect = new Rect();
int childCount = mRecyclerView.getChildCount();
int[] listViewCoords = new int[2];
mRecyclerView.getLocationOnScreen(listViewCoords);
int x = (int) motionEvent.getRawX() - listViewCoords[0];
int y = (int) motionEvent.getRawY() - listViewCoords[1];
View child;
for (int i = 0; i < childCount; i++) {
child = mRecyclerView.getChildAt(i);
child.getHitRect(rect);
if (rect.contains(x, y)) {
assert child instanceof ViewGroup &&
((ViewGroup) child).getChildCount() == 2 :
"Each child needs to extend from ViewGroup and have two children";
boolean dataContainerHasBeenDismissed = mPendingDismiss != null &&
mPendingDismiss.position == mRecyclerView.getChildPosition(child) &&
mPendingDismiss.rowContainer.dataContainerHasBeenDismissed;
mRowContainer = new RowContainer((ViewGroup) child);
mRowContainer.dataContainerHasBeenDismissed = dataContainerHasBeenDismissed;
break;
}
}
if (mRowContainer != null) {
mDownX = motionEvent.getRawX();
mDownY = motionEvent.getRawY();
mDownPosition = mRecyclerView.getChildPosition(mRowContainer.container);
if (mCallbacks.canDismiss(mDownPosition)) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(motionEvent);
} else {
mRowContainer = null;
}
}
return false;
}
case MotionEvent.ACTION_CANCEL: {
if (mVelocityTracker == null) {
break;
}
if (mRowContainer != null && mSwiping) {
// cancel
mRowContainer.getCurrentSwipingView()
.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
mDownX = 0;
mDownY = 0;
mRowContainer = null;
mDownPosition = ListView.INVALID_POSITION;
mSwiping = false;
break;
}
case MotionEvent.ACTION_UP: {
if (mVelocityTracker == null) {
break;
}
float deltaX = motionEvent.getRawX() - mDownX;
mVelocityTracker.addMovement(motionEvent);
mVelocityTracker.computeCurrentVelocity(1000);
float velocityX = mVelocityTracker.getXVelocity();
float absVelocityX = Math.abs(velocityX);
float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false;
boolean dismissRight = false;
if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
dismiss = true;
dismissRight = deltaX > 0;
} else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
&& absVelocityY < absVelocityX && mSwiping) {
// dismiss only if flinging in the same direction as dragging
dismiss = (velocityX < 0) == (deltaX < 0);
dismissRight = mVelocityTracker.getXVelocity() > 0;
}
if (dismiss && mDownPosition != ListView.INVALID_POSITION) {
// dismiss
final RowContainer downView = mRowContainer; // mDownView gets null'd before animation ends
final int downPosition = mDownPosition;
mRowContainer.getCurrentSwipingView()
.animate()
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
performDismiss(downView, downPosition);
}
});
} else {
// cancel
mRowContainer.getCurrentSwipingView()
.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
mDownX = 0;
mDownY = 0;
mRowContainer = null;
mDownPosition = ListView.INVALID_POSITION;
mSwiping = false;
break;
}
case MotionEvent.ACTION_MOVE: {
if (mVelocityTracker == null || mPaused) {
break;
}
mVelocityTracker.addMovement(motionEvent);
float deltaX = motionEvent.getRawX() - mDownX;
float deltaY = motionEvent.getRawY() - mDownY;
if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
mSwiping = true;
mSwipingSlop = deltaX > 0 ? mSlop : -mSlop;
mRecyclerView.requestDisallowInterceptTouchEvent(true);
// Cancel ListView's touch (un-highlighting the item)
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
(motionEvent.getActionIndex()
<< MotionEvent.ACTION_POINTER_INDEX_SHIFT));
mRecyclerView.onTouchEvent(cancelEvent);
cancelEvent.recycle();
}
if (mSwiping) {
mRowContainer.getCurrentSwipingView().setTranslationX(deltaX - mSwipingSlop);
mRowContainer.getCurrentSwipingView().setAlpha(Math.max(0f, Math.min(1f,
1f - 2f * Math.abs(deltaX) / mViewWidth)));
return true;
}
break;
}
}
return false;
}
class PendingDismissData implements Comparable<PendingDismissData> {
public int position;
public RowContainer rowContainer;
public PendingDismissData(int position, RowContainer rowContainer) {
this.position = position;
this.rowContainer= rowContainer;
}
#Override
public int compareTo(#NonNull PendingDismissData other) {
// Sort by descending position
return other.position - position;
}
}
private void performDismiss(RowContainer dismissView, int dismissPosition) {
// Animate the dismissed list item to zero-height and fire the dismiss callback when
// all dismissed list item animations have completed. This triggers layout on each animation
// frame; in the future we may want to do something smarter and more performant.
if (mPendingDismiss != null) {
boolean dismissingDifferentRow = mPendingDismiss.position != dismissPosition;
int newPosition = mPendingDismiss.position < dismissPosition ? dismissPosition-1 : dismissPosition;
processPendingDismisses();
if (dismissingDifferentRow) {
addPendingDismiss(dismissView, newPosition);
}
} else {
addPendingDismiss(dismissView, dismissPosition);
}
}
private void addPendingDismiss(RowContainer dismissView, int dismissPosition) {
dismissView.dataContainerHasBeenDismissed = true;
dismissView.undoContainer.setVisibility(View.VISIBLE);
mPendingDismiss = new PendingDismissData(dismissPosition, dismissView);
// Notify the callbacks
mCallbacks.onPendingDismiss(mRecyclerView, dismissPosition);
// Automatically dismiss the item after a certain delay
if(mDismissDelayMillis >= 0)
mHandler.removeCallbacks(mDismissRunnable);
mHandler.postDelayed(mDismissRunnable, mDismissDelayMillis);
}
/**
* If a view was dismissed and the undo container is showing it will proceed with the final
* dismiss of the item.
* #return whether there were any pending rows to be dismissed.
*/
public boolean processPendingDismisses() {
boolean existPendingDismisses = existPendingDismisses();
if (existPendingDismisses) processPendingDismisses(mPendingDismiss);
return existPendingDismisses;
}
/**
* Whether a row has been dismissed and is waiting for confirmation
* #return whether there are any pending rows to be dismissed.
*/
public boolean existPendingDismisses() {
return mPendingDismiss != null && mPendingDismiss.rowContainer.dataContainerHasBeenDismissed;
}
/**
* If a view was dismissed and the undo container is showing it will undo and make the data
* container reappear.
* #return whether there were any pending rows to be dismissed.
*/
public boolean undoPendingDismiss() {
boolean existPendingDismisses = existPendingDismisses();
if (existPendingDismisses) {
mPendingDismiss.rowContainer.undoContainer.setVisibility(View.GONE);
mPendingDismiss.rowContainer.dataContainer
.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
mPendingDismiss = null;
}
return existPendingDismisses;
}
private void processPendingDismisses(final PendingDismissData pendingDismissData) {
mPendingDismiss = null;
final ViewGroup.LayoutParams lp = pendingDismissData.rowContainer.container.getLayoutParams();
final int originalHeight = pendingDismissData.rowContainer.container.getHeight();
ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
if (mCallbacks.canDismiss(pendingDismissData.position))
mCallbacks.onDismiss(mRecyclerView, pendingDismissData.position);
pendingDismissData.rowContainer.dataContainer.post(new Runnable() {
#Override
public void run() {
pendingDismissData.rowContainer.dataContainer.setTranslationX(0);
pendingDismissData.rowContainer.dataContainer.setAlpha(1);
pendingDismissData.rowContainer.undoContainer.setVisibility(View.GONE);
pendingDismissData.rowContainer.undoContainer.setTranslationX(0);
pendingDismissData.rowContainer.undoContainer.setAlpha(1);
lp.height = originalHeight;
pendingDismissData.rowContainer.container.setLayoutParams(lp);
}
});
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
lp.height = (Integer) valueAnimator.getAnimatedValue();
pendingDismissData.rowContainer.container.setLayoutParams(lp);
}
});
animator.start();
}
}
I have updated and commented your code to achieve what you want. Check MyBaseAdapter() Constructor first and then getView() method.
Package com.swipe.delete;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.hudomju.swipe.SwipeToDismissTouchListener;
import com.hudomju.swipe.adapter.ListViewAdapter;
import java.util.ArrayList;
import java.util.List;
import static android.widget.Toast.LENGTH_SHORT;
public class ListViewActivity extends Activity {
private static final int TIME_TO_AUTOMATICALLY_DISMISS_ITEM = 3000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_view_activity);
init((ListView) findViewById(R.id.list_view));
}
private void init(ListView listView) {
final MyBaseAdapter adapter = new MyBaseAdapter();
listView.setAdapter(adapter);
final SwipeToDismissTouchListener<ListViewAdapter> touchListener =
new SwipeToDismissTouchListener<>(
new ListViewAdapter(listView),
new SwipeToDismissTouchListener.DismissCallbacks<ListViewAdapter>() {
#Override
public boolean canDismiss(int position) {
return true;
}
#Override
public void onPendingDismiss(ListViewAdapter recyclerView, int position) {
}
#Override
public void onDismiss(ListViewAdapter view, int position) {
adapter.remove(position);
}
});
touchListener.setDismissDelay(TIME_TO_AUTOMATICALLY_DISMISS_ITEM);
listView.setOnTouchListener(touchListener);
// Setting this scroll listener is required to ensure that during ListView scrolling,
// we don't look for swipes.
listView.setOnScrollListener((AbsListView.OnScrollListener) touchListener.makeScrollListener());
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (touchListener.existPendingDismisses()) {
touchListener.undoPendingDismiss();
} else {
Toast.makeText(ListViewActivity.this, "Position " + position, LENGTH_SHORT).show();
}
}
});
}
static class MyBaseAdapter extends BaseAdapter {
private static final int SIZE = 100;
private final List<String> mDataSet = new ArrayList<>();
MyBaseAdapter() {
for (int i = 0; i < 5; i++){
// You should add an object containing type of view like section or sectionHeader along with your string.
// Here i am just using string search to detect whether it is sectionHeader or section. have a look at getView() Method
mDataSet.add("This is Section Header " + i);
for (int e = 0; e < SIZE; i++){
mDataSet.add(i, "This is section " + e);
}
}
}
#Override
public int getCount() {
return mDataSet.size();
}
#Override
public String getItem(int position) {
return mDataSet.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public void remove(int position) {
mDataSet.remove(position);
notifyDataSetChanged();
}
static class ViewHolder {
TextView dataTextView;
ViewHolder(View view) {
dataTextView = (TextView) view.findViewById(R.id.txt_data);
view.setTag(this);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = convertView == null
? new ViewHolder(convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false))
: (ViewHolder) convertView.getTag();
viewHolder.dataTextView.setText(mDataSet.get(position));
if(mDataSet.get(position).indexof("Section Header") != -1){
// This is your sectionHeader
// Customize you sectionHeader UI here
// Ideally you should use object here so (object.type == 1) can determine whether this is a sectionHeader or header
}else{
// This is your section
// Customize you section UI here
}
return convertView;
}
}
}
I hope it helps.
I am using pull to refresh in my application. Pull to refresh is working fine when the list size is crossing screen. But when the size is one or two there is a gap between the header and the listview saying tap to refresh.
Here is my code
public class PullToRefreshListView extends ListView implements OnScrollListener {
private static final int TAP_TO_REFRESH = 1;
private static final int PULL_TO_REFRESH = 2;
private static final int RELEASE_TO_REFRESH = 3;
private static final int REFRESHING = 4;
private static final String TAG = "PullToRefreshListView";
private OnRefreshListener mOnRefreshListener;
/**
* Listener that will receive notifications every time the list scrolls.
*/
private OnScrollListener mOnScrollListener;
private LayoutInflater mInflater;
private RelativeLayout mRefreshView;
private TextView mRefreshViewText;
private ImageView mRefreshViewImage;
private ProgressBar mRefreshViewProgress;
private TextView mRefreshViewLastUpdated;
private int mCurrentScrollState;
private int mRefreshState;
private RotateAnimation mFlipAnimation;
private RotateAnimation mReverseFlipAnimation;
private int mRefreshViewHeight;
private int mRefreshOriginalTopPadding;
private int mLastMotionY;
private boolean mBounceHack;
public PullToRefreshListView(Context context) {
super(context);
init(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
// Load all of the animations we need in code rather than through XML
mFlipAnimation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(250);
mFlipAnimation.setFillAfter(true);
mReverseFlipAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
mReverseFlipAnimation.setDuration(250);
mReverseFlipAnimation.setFillAfter(true);
mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRefreshView = (RelativeLayout) mInflater.inflate(
R.layout.pull_to_refresh_header, this, false);
mRefreshViewText = (TextView) mRefreshView
.findViewById(R.id.pull_to_refresh_text);
mRefreshViewImage = (ImageView) mRefreshView
.findViewById(R.id.pull_to_refresh_image);
mRefreshViewProgress = (ProgressBar) mRefreshView
.findViewById(R.id.pull_to_refresh_progress);
mRefreshViewLastUpdated = (TextView) mRefreshView
.findViewById(R.id.pull_to_refresh_updated_at);
mRefreshViewImage.setMinimumHeight(50);
mRefreshView.setOnClickListener(new OnClickRefreshListener());
mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();
mRefreshState = TAP_TO_REFRESH;
addHeaderView(mRefreshView);
super.setOnScrollListener(this);
measureView(mRefreshView);
mRefreshViewHeight = mRefreshView.getMeasuredHeight();
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setSelection(1);
}
#Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
setSelection(1);
}
/**
* Set the listener that will receive notifications every time the list
* scrolls.
*
* #param l
* The scroll listener.
*/
#Override
public void setOnScrollListener(AbsListView.OnScrollListener l) {
mOnScrollListener = l;
}
/**
* Register a callback to be invoked when this list should be refreshed.
*
* #param onRefreshListener
* The callback to run.
*/
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
mOnRefreshListener = onRefreshListener;
}
/**
* Set a text to represent when the list was last updated.
*
* #param lastUpdated
* Last updated at.
*/
public void setLastUpdated(CharSequence lastUpdated) {
if (lastUpdated != null) {
mRefreshViewLastUpdated.setVisibility(View.VISIBLE);
mRefreshViewLastUpdated.setText(lastUpdated);
} else {
mRefreshViewLastUpdated.setVisibility(View.GONE);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
final int y = (int) event.getY();
mBounceHack = false;
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (!isVerticalScrollBarEnabled()) {
setVerticalScrollBarEnabled(true);
}
if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
if ((mRefreshView.getBottom() >= mRefreshViewHeight || mRefreshView
.getTop() >= 0) && mRefreshState == RELEASE_TO_REFRESH) {
// Initiate the refresh
mRefreshState = REFRESHING;
prepareForRefresh();
onRefresh();
} else if (mRefreshView.getBottom() < mRefreshViewHeight
|| mRefreshView.getTop() <= 0) {
// Abort refresh and scroll down below the refresh view
resetHeader();
setSelection(1);
}
}
break;
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
applyHeaderPadding(event);
break;
}
return super.onTouchEvent(event);
}
private void applyHeaderPadding(MotionEvent ev) {
// getHistorySize has been available since API 1
int pointerCount = ev.getHistorySize();
for (int p = 0; p < pointerCount; p++) {
if (mRefreshState == RELEASE_TO_REFRESH) {
if (isVerticalFadingEdgeEnabled()) {
setVerticalScrollBarEnabled(false);
}
int historicalY = (int) ev.getHistoricalY(p);
// Calculate the padding to apply, we divide by 1.7 to
// simulate a more resistant effect during pull.
int topPadding = (int) (((historicalY - mLastMotionY) - mRefreshViewHeight) / 1.7);
mRefreshView.setPadding(mRefreshView.getPaddingLeft(),
topPadding, mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
}
}
/**
* Sets the header padding back to original size.
*/
private void resetHeaderPadding() {
mRefreshView.setPadding(mRefreshView.getPaddingLeft(),
mRefreshOriginalTopPadding, mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
/**
* Resets the header to the original state.
*/
private void resetHeader() {
if (mRefreshState != TAP_TO_REFRESH) {
mRefreshState = TAP_TO_REFRESH;
resetHeaderPadding();
// Set refresh view text to the pull label
mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);
// Replace refresh drawable with arrow drawable
mRefreshViewImage
.setImageResource(R.drawable.ic_pulltorefresh_arrow);
// Clear the full rotation animation
mRefreshViewImage.clearAnimation();
// Hide progress bar and arrow.
mRefreshViewImage.setVisibility(View.GONE);
mRefreshViewProgress.setVisibility(View.GONE);
}
}
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// When the refresh view is completely visible, change the text to say
// "Release to refresh..." and flip the arrow drawable.
if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL
&& mRefreshState != REFRESHING) {
if (firstVisibleItem == 0) {
mRefreshViewImage.setVisibility(View.VISIBLE);
if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20 || mRefreshView
.getTop() >= 0) && mRefreshState != RELEASE_TO_REFRESH) {
mRefreshViewText
.setText(R.string.pull_to_refresh_release_label);
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mFlipAnimation);
mRefreshState = RELEASE_TO_REFRESH;
} else if (mRefreshView.getBottom() < mRefreshViewHeight + 20
&& mRefreshState != PULL_TO_REFRESH) {
mRefreshViewText
.setText(R.string.pull_to_refresh_pull_label);
if (mRefreshState != TAP_TO_REFRESH) {
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mReverseFlipAnimation);
}
mRefreshState = PULL_TO_REFRESH;
}
} else {
mRefreshViewImage.setVisibility(View.GONE);
resetHeader();
}
} else if (mCurrentScrollState == SCROLL_STATE_FLING
&& firstVisibleItem == 0 && mRefreshState != REFRESHING) {
setSelection(1);
mBounceHack = true;
} else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {
setSelection(1);
}
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem,
visibleItemCount, totalItemCount);
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
mCurrentScrollState = scrollState;
if (mCurrentScrollState == SCROLL_STATE_IDLE) {
mBounceHack = false;
}
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
public void prepareForRefresh() {
resetHeaderPadding();
mRefreshViewImage.setVisibility(View.GONE);
// We need this hack, otherwise it will keep the previous drawable.
mRefreshViewImage.setImageDrawable(null);
mRefreshViewProgress.setVisibility(View.VISIBLE);
// Set refresh view text to the refreshing label
mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);
mRefreshState = REFRESHING;
}
public void onRefresh() {
Log.d(TAG, "onRefresh");
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
}
/**
* Resets the list to a normal state after a refresh.
*
* #param lastUpdated
* Last updated at.
*/
public void onRefreshComplete(CharSequence lastUpdated) {
setLastUpdated(lastUpdated);
onRefreshComplete();
}
/**
* Resets the list to a normal state after a refresh.
*/
public void onRefreshComplete() {
Log.d(TAG, "onRefreshComplete");
resetHeader();
// If refresh view is visible when loading completes, scroll down to
// the next item.
if (mRefreshView.getBottom() > 0) {
invalidateViews();
setSelection(1);
}
}
/**
* Invoked when the refresh view is clicked on. This is mainly used when
* there's only a few items in the list and it's not possible to drag the
* list.
*/
private class OnClickRefreshListener implements OnClickListener {
#Override
public void onClick(View v) {
if (mRefreshState != REFRESHING) {
prepareForRefresh();
onRefresh();
}
}
}
/**
* Interface definition for a callback to be invoked when list should be
* refreshed.
*/
public interface OnRefreshListener {
/**
* Called when the list should be refreshed.
* <p>
* A call to {#link PullToRefreshListView #onRefreshComplete()} is
* expected to indicate that the refresh has completed.
*/
public void onRefresh();
}
}
Here is my xml code
<com.k2b.kluebook.pulltorefresh.PullToRefreshListView
android:id="#+id/list_pulltorefresh"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#null"
android:dividerHeight="0dp" >
</com.k2b.kluebook.pulltorefresh.PullToRefreshListView>
Here is my class file code
listview.setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh() {
// Do work to refresh the list here.
}
});
How to get rid of the GAP and "Tap to Refresh".
Use this code instead
public class PullToRefreshListView extends ListView implements OnScrollListener {
// private static final int TAP_TO_REFRESH = 1;
private static final int PULL_TO_REFRESH = 2;
private static final int RELEASE_TO_REFRESH = 3;
protected static final int REFRESHING = 4;
protected static final String TAG = "PullToRefreshListView";
private OnRefreshListener mOnRefreshListener;
/**
* Listener that will receive notifications every time the list scrolls.
*/
private OnScrollListener mOnScrollListener;
protected LayoutInflater mInflater;
// header
private RelativeLayout mRefreshView;
private TextView mRefreshViewText;
private ImageView mRefreshViewImage;
private ProgressBar mRefreshViewProgress;
private TextView mRefreshViewLastUpdated;
protected int mCurrentScrollState;
protected int mRefreshState;
private RotateAnimation mFlipAnimation;
private RotateAnimation mReverseFlipAnimation;
private int mRefreshViewHeight;
private int mRefreshOriginalTopPadding;
private int mLastMotionY;
private boolean mBounceHack;
public PullToRefreshListView(Context context) {
super(context);
init(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context);
}
protected void init(Context context) {
// Load all of the animations we need in code rather than through XML
mFlipAnimation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(250);
mFlipAnimation.setFillAfter(true);
mReverseFlipAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
mReverseFlipAnimation.setDuration(250);
mReverseFlipAnimation.setFillAfter(true);
mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// header
mRefreshView = (RelativeLayout) mInflater.inflate(
R.layout.pull_to_refresh_header, this, false);
mRefreshViewText = (TextView) mRefreshView
.findViewById(R.id.pull_to_refresh_text);
mRefreshViewImage = (ImageView) mRefreshView
.findViewById(R.id.pull_to_refresh_image);
mRefreshViewProgress = (ProgressBar) mRefreshView
.findViewById(R.id.pull_to_refresh_progress);
mRefreshViewLastUpdated = (TextView) mRefreshView
.findViewById(R.id.pull_to_refresh_updated_at);
mRefreshViewImage.setMinimumHeight(50);
mRefreshView.setOnClickListener(new OnClickRefreshListener());
mRefreshOriginalTopPadding = mRefreshView.getPaddingTop();
mRefreshState = PULL_TO_REFRESH;
addHeaderView(mRefreshView);
super.setOnScrollListener(this);
measureView(mRefreshView);
mRefreshViewHeight = mRefreshView.getMeasuredHeight();
}
#Override
protected void onAttachedToWindow() {
//have to ask super to attach to window, otherwise it won't scroll in jelly bean.
super.onAttachedToWindow();
setSelection(1);
}
#Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
setSelection(1);
}
/**
* Set the listener that will receive notifications every time the list
* scrolls.
*
* #param l
* The scroll listener.
*/
#Override
public void setOnScrollListener(AbsListView.OnScrollListener l) {
mOnScrollListener = l;
}
/**
* Register a callback to be invoked when this list should be refreshed.
*
* #param onRefreshListener
* The callback to run.
*/
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
mOnRefreshListener = onRefreshListener;
}
/**
* Set a text to represent when the list was last updated.
*
* #param lastUpdated
* Last updated at.
*/
public void setLastUpdated(CharSequence lastUpdated) {
if (lastUpdated != null) {
mRefreshViewLastUpdated.setVisibility(View.VISIBLE);
mRefreshViewLastUpdated.setText(lastUpdated);
} else {
mRefreshViewLastUpdated.setVisibility(View.GONE);
}
}
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent(MotionEvent event) {
final int y = (int) event.getY();
mBounceHack = false;
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (!isVerticalScrollBarEnabled()) {
setVerticalScrollBarEnabled(true);
}
if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
if ((mRefreshView.getBottom() >= mRefreshViewHeight || mRefreshView
.getTop() >= 0) && mRefreshState == RELEASE_TO_REFRESH) {
// Initiate the refresh
mRefreshState = REFRESHING;
prepareForRefresh();
onRefresh();
} else if (mRefreshView.getBottom() < mRefreshViewHeight
|| mRefreshView.getTop() <= 0) {
// Abort refresh and scroll down below the refresh view
resetHeader();
setSelection(1);
}
}
break;
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
applyHeaderPadding(event);
break;
}
return super.onTouchEvent(event);
}
private void applyHeaderPadding(MotionEvent ev) {
// getHistorySize has been available since API 1
int pointerCount = ev.getHistorySize();
for (int p = 0; p < pointerCount; p++) {
// if (mRefreshState == RELEASE_TO_REFRESH) {
if (isVerticalFadingEdgeEnabled()) {
setVerticalScrollBarEnabled(false);
}
int historicalY = (int) ev.getHistoricalY(p);
// Calculate the padding to apply, we divide by 1.7 to
// simulate a more resistant effect during pull.
int topPadding = (int) (((historicalY - mLastMotionY) - mRefreshViewHeight) / 1.7);
mRefreshView.setPadding(mRefreshView.getPaddingLeft(),
topPadding, mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
// }
}
/**
* Sets the header padding back to original size.
*/
private void resetHeaderPadding() {
mLastMotionY = 0;
mRefreshView.setPadding(mRefreshView.getPaddingLeft(),
mRefreshOriginalTopPadding, mRefreshView.getPaddingRight(),
mRefreshView.getPaddingBottom());
}
/**
* Resets the header to the original state.
*/
private void resetHeader() {
// if (mRefreshState != TAP_TO_REFRESH) {
mRefreshState = PULL_TO_REFRESH;
resetHeaderPadding();
// Set refresh view text to the pull label
mRefreshViewText.setText(R.string.pull_to_refresh_tap_label);
// Replace refresh drawable with arrow drawable
mRefreshViewImage
.setImageResource(R.drawable.ic_pulltorefresh_arrow);
// Clear the full rotation animation
mRefreshViewImage.clearAnimation();
// Hide progress bar and arrow.
mRefreshViewImage.setVisibility(View.GONE);
mRefreshViewProgress.setVisibility(View.GONE);
// }
}
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// When the refresh view is completely visible, change the text to say
// "Release to refresh..." and flip the arrow drawable.
if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL
&& mRefreshState != REFRESHING) {
if (firstVisibleItem == 0) {
mRefreshViewImage.setVisibility(View.VISIBLE);
if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20 || mRefreshView
.getTop() >= 0) && mRefreshState != RELEASE_TO_REFRESH) {
mRefreshViewText
.setText(R.string.pull_to_refresh_release_label);
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mFlipAnimation);
mRefreshState = RELEASE_TO_REFRESH;
} else if (mRefreshView.getBottom() < mRefreshViewHeight + 20
&& mRefreshState != PULL_TO_REFRESH) {
mRefreshViewText
.setText(R.string.pull_to_refresh_pull_label);
// if (mRefreshState != TAP_TO_REFRESH) {
mRefreshViewImage.clearAnimation();
mRefreshViewImage.startAnimation(mReverseFlipAnimation);
// }
mRefreshState = PULL_TO_REFRESH;
}
} else {
mRefreshViewImage.setVisibility(View.GONE);
resetHeader();
}
} else if (mCurrentScrollState == SCROLL_STATE_FLING
&& firstVisibleItem == 0 && mRefreshState != REFRESHING) {
setSelection(1);
mBounceHack = true;
} else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {
setSelection(1);
}
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem,
visibleItemCount, totalItemCount);
}
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
mCurrentScrollState = scrollState;
if (mCurrentScrollState == SCROLL_STATE_IDLE) {
mBounceHack = false;
}
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
public void prepareForRefresh() {
resetHeaderPadding();
mRefreshViewImage.setVisibility(View.GONE);
// We need this hack, otherwise it will keep the previous drawable.
mRefreshViewImage.setImageDrawable(null);
mRefreshViewProgress.setVisibility(View.VISIBLE);
// Set refresh view text to the refreshing label
mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label);
mRefreshState = REFRESHING;
}
public void onRefresh() {
Log.d(TAG, "onRefresh");
if (mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
}
/**
* Resets the list to a normal state after a refresh.
*
* #param lastUpdated
* Last updated at.
*/
public void onRefreshComplete(CharSequence lastUpdated) {
setLastUpdated(lastUpdated);
onRefreshComplete();
}
/**
* Resets the list to a normal state after a refresh.
*/
public void onRefreshComplete() {
Log.d(TAG, "onRefreshComplete");
resetHeader();
// If refresh view is visible when loading completes, scroll down to
// the next item.
if (mRefreshView.getBottom() > 0) {
invalidateViews();
setSelection(1);
}
}
/**
* Invoked when the refresh view is clicked on. This is mainly used when
* there's only a few items in the list and it's not possible to drag the
* list.
*/
private class OnClickRefreshListener implements OnClickListener {
public void onClick(View v) {
if (mRefreshState != REFRESHING) {
prepareForRefresh();
onRefresh();
}
}
}
/**
* Interface definition for a callback to be invoked when list should be
* refreshed.
*/
public interface OnRefreshListener {
/**
* Called when the list should be refreshed.
* <p>
* A call to {#link PullToRefreshListView #onRefreshComplete()} is
* expected to indicate that the refresh has completed.
*/
public void onRefresh();
}
}
also set the visibility to gone in the pull_to_refresh_header.xml in your library layout if you have it (android:id="#+id/pull_to_refresh_text")
<TextView
android:id="#+id/pull_to_refresh_text"
android:text="#string/pull_to_refresh_pull_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
android:paddingTop="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:visibility="gone"
/>
enjoy!
I want to implement Swipe in ListView like in Samsung Android Phones calling function
I have a list shown in below image :
Now when I swipe right side at some distance of swipe from left i.e 25% distance it just changed background, like call function in Samsung device or like SwipeListView:
need solution for this.
try this code :
main.xml file
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
raw.xml
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:gravity="left"
android:text="ABC"
android:textSize="22sp" />
<LinearLayout
android:id="#+id/delete_lay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#55ff0000"
android:visibility="gone" >
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:src="#drawable/ic_menu_delete"
android:visibility="visible" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:gravity="left"
android:text="Deleting..."
android:textColor="#ff0000"
android:textSize="22sp"
android:textStyle="bold" />
</LinearLayout>
MainActivity.java
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import de.timroes.swipetodismiss.SwipeDismissList;
import de.timroes.swipetodismiss.SwipeDismissList.SwipeDirection;
import de.timroes.swipetodismiss.SwipeDismissList.UndoMode;
import de.timroes.swipetodismiss.SwipeDismissList.Undoable;
public class MainActivity extends Activity {
ArrayList<String> listData;
ListView listView;
ArrayAdapter<String> adapter;
SwipeListAdapter listAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView1);
listData = new ArrayList<String>();
listData.add("item 1");
listData.add("item 2");
listData.add("item 3");
listData.add("item 4");
listData.add("item 5");
listData.add("item 6");
listData.add("item 7");
listData.add("item 8");
listData.add("item 9");
listData.add("item 10");
listData.add("item 11");
listData.add("item 12");
listData.add("item 13");
listData.add("item 14");
listData.add("item 15");
listData.add("item 16");
listData.add("item 17");
listAdapter = new SwipeListAdapter(MainActivity.this);
listView.setAdapter(listAdapter);
listAdapter.notifyDataSetChanged();
SwipeDismissList.OnDismissCallback callback = new SwipeDismissList.OnDismissCallback() {
#Override
public Undoable onDismiss(AbsListView listView, int position) {
View view = (View) listView.getChildAt(0);
view.animate().alpha(1).setDuration(200).translationX(10);
listAdapter.remove(position);
return null;
}
};
UndoMode mode = SwipeDismissList.UndoMode.SINGLE_UNDO;
SwipeDismissList swipeList = new SwipeDismissList(listView, callback,
mode);
swipeList.setSwipeDirection(SwipeDirection.END);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
class SwipeListAdapter extends BaseAdapter {
Context mContext;
public SwipeListAdapter(Context context) {
this.mContext = context;
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return listData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
private void remove(int pos) {
listData.remove(pos);
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
try {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.raw, null);
}
TextView textView = (TextView) convertView
.findViewById(R.id.name);
textView.setText(listData.get(position));
RelativeLayout layout = (RelativeLayout) convertView
.findViewById(R.id.parentLayout);
LayoutParams params = new LayoutParams(
LayoutParams.MATCH_PARENT, 50);
layout.setLayoutParams(params);
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
}
}
SwipeDismissList.java
import static com.nineoldandroids.view.ViewHelper.setAlpha;
import static com.nineoldandroids.view.ViewHelper.setTranslationX;
import static com.nineoldandroids.view.ViewPropertyAnimator.animate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.animation.ValueAnimator;
public final class SwipeDismissList implements View.OnTouchListener {
// Cached ViewConfiguration and system-wide constant values
private int mSlop;
private int mMinFlingVelocity;
private int mMaxFlingVelocity;
private long mAnimationTime;
// Fixed properties
private AbsListView mListView;
private OnDismissCallback mCallback;
private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
// Transient properties
private SortedSet<PendingDismissData> mPendingDismisses = new TreeSet<PendingDismissData>();
private int mDismissAnimationRefCount = 0;
private float mDownX;
private boolean mSwiping;
private VelocityTracker mVelocityTracker;
private int mDownPosition;
private View mDownView;
private boolean mPaused;
private float mDensity;
private boolean mSwipeDisabled;
private UndoMode mMode;
private List<Undoable> mUndoActions;
private Handler mHandler;
private PopupWindow mUndoPopup;
private TextView mUndoText;
private Button mUndoButton;
private SwipeDirection mSwipeDirection = SwipeDirection.BOTH;
private int mAutoHideDelay = 5000;
private String mDeleteString = "Item deleted";
private String mDeleteMultipleString = "%d items deleted";
private boolean mTouchBeforeAutoHide = true;
private int mDelayedMsgId;
View frontView;
View backView;
RelativeLayout layout ;
public enum UndoMode {
SINGLE_UNDO,
MULTI_UNDO,
COLLAPSED_UNDO
};
public enum SwipeDirection {
BOTH,
START,
END
}
public interface OnDismissCallback {
Undoable onDismiss(AbsListView listView, int position);
}
public abstract static class Undoable {
public String getTitle() {
return null;
}
public abstract void undo();
public void discard() { }
}
public SwipeDismissList(AbsListView listView, OnDismissCallback callback) {
this(listView, callback, UndoMode.SINGLE_UNDO);
}
public SwipeDismissList(AbsListView listView, OnDismissCallback callback, UndoMode mode) {
if(listView == null) {
throw new IllegalArgumentException("listview must not be null.");
}
mHandler = new HideUndoPopupHandler();
mListView = listView;
mCallback = callback;
mMode = mode;
ViewConfiguration vc = ViewConfiguration.get(listView.getContext());
mSlop = vc.getScaledTouchSlop();
mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
mAnimationTime = listView.getContext().getResources().getInteger(
android.R.integer.config_shortAnimTime);
mDensity = mListView.getResources().getDisplayMetrics().density;
// -- Load undo popup --
LayoutInflater inflater = (LayoutInflater) mListView.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.undo_popup, null);
mUndoButton = (Button)v.findViewById(R.id.undo);
mUndoButton.setOnClickListener(new UndoHandler());
mUndoButton.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// If user tabs "undo" button, reset delay time to remove popup
mDelayedMsgId++;
return false;
}
});
mUndoText = (TextView)v.findViewById(R.id.text);
mUndoPopup = new PopupWindow(v);
mUndoPopup.setAnimationStyle(R.style.fade_animation);
// Get scren width in dp and set width respectively
int xdensity = (int)(mListView.getContext().getResources().getDisplayMetrics().widthPixels / mDensity);
if(xdensity < 300) {
mUndoPopup.setWidth((int)(mDensity * 280));
} else if(xdensity < 350) {
mUndoPopup.setWidth((int)(mDensity * 300));
} else if(xdensity < 500) {
mUndoPopup.setWidth((int)(mDensity * 330));
} else {
mUndoPopup.setWidth((int)(mDensity * 450));
}
mUndoPopup.setHeight((int)(mDensity * 56));
// -- END Load undo popu --
listView.setOnTouchListener(this);
listView.setOnScrollListener(this.makeScrollListener());
switch(mode) {
case SINGLE_UNDO:
mUndoActions = new ArrayList<Undoable>(1);
break;
default:
mUndoActions = new ArrayList<Undoable>(10);
break;
}
}
private void setEnabled(boolean enabled) {
mPaused = !enabled;
}
public void setAutoHideDelay(int delay) {
mAutoHideDelay = delay;
}
public void setSwipeDirection(SwipeDirection direction) {
mSwipeDirection = direction;
}
public void setUndoString(String msg) {
mDeleteString = msg;
}
public void setUndoMultipleString(String msg) {
mDeleteMultipleString = msg;
}
public void setRequireTouchBeforeDismiss(boolean require) {
mTouchBeforeAutoHide = require;
}
public void discardUndo() {
for(Undoable undoable : mUndoActions) {
undoable.discard();
}
mUndoActions.clear();
mUndoPopup.dismiss();
}
private AbsListView.OnScrollListener makeScrollListener() {
return new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
#Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
};
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (this.mSwipeDisabled) {
return false;
}
if (mViewWidth < 2) {
mViewWidth = mListView.getWidth();
}
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
if (mPaused) {
return false;
}
// TODO: ensure this is a finger, and set a flag
// Find the child view that was touched (perform a hit test)
Rect rect = new Rect();
int childCount = mListView.getChildCount();
int[] listViewCoords = new int[2];
mListView.getLocationOnScreen(listViewCoords);
int x = (int) motionEvent.getRawX() - listViewCoords[0];
int y = (int) motionEvent.getRawY() - listViewCoords[1];
View child;
for (int i = 0; i < childCount; i++) {
child = mListView.getChildAt(i);
child.getHitRect(rect);
if (rect.contains(x, y)) {
mDownView = child;
break;
}
}
if (mDownView != null) {
mDownX = motionEvent.getRawX();
mDownPosition = mListView.getPositionForView(mDownView);
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(motionEvent);
}
view.onTouchEvent(motionEvent);
return true;
}
case MotionEvent.ACTION_UP: {
if (mVelocityTracker == null) {
break;
}
float deltaX = motionEvent.getRawX() - mDownX;
mVelocityTracker.addMovement(motionEvent);
mVelocityTracker.computeCurrentVelocity(1000);
float velocityX = Math.abs(mVelocityTracker.getXVelocity());
float velocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false;
boolean dismissRight = false;
if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
dismiss = true;
dismissRight = deltaX > 0;
} else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity
&& velocityY < velocityX && mSwiping && isDirectionValid(mVelocityTracker.getXVelocity())
&& deltaX >= mViewWidth * 0.2f) {
dismiss = true;
dismissRight = mVelocityTracker.getXVelocity() > 0;
}
if (dismiss) {
// dismiss
final View downView = frontView; // mDownView gets null'd before animation ends
final int downPosition = mDownPosition;
++mDismissAnimationRefCount;
animate(frontView)
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
performDismiss(downView, downPosition);
}
});
} else {
// cancel
animate(frontView)
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
}
mVelocityTracker = null;
mDownX = 0;
mDownView = null;
mDownPosition = ListView.INVALID_POSITION;
mSwiping = false;
if(backView != null) {
backView.setVisibility(View.GONE);
frontView.setVisibility(View.VISIBLE);
setTranslationX(frontView, 0);
layout = null;
backView = null;
frontView = null;
}
break;
}
case MotionEvent.ACTION_MOVE: {
if(mTouchBeforeAutoHide && mUndoPopup.isShowing()) {
// Send a delayed message to hide popup
mHandler.sendMessageDelayed(mHandler.obtainMessage(mDelayedMsgId),
mAutoHideDelay);
}
if (mVelocityTracker == null || mPaused) {
break;
}
mVelocityTracker.addMovement(motionEvent);
float deltaX = motionEvent.getRawX() - mDownX;
// Only start swipe in correct direction
if(isDirectionValid(deltaX)) {
if (Math.abs(deltaX) > mSlop) {
mSwiping = true;
mListView.requestDisallowInterceptTouchEvent(true);
// Cancel ListView's touch (un-highlighting the item)
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL
| (motionEvent.getActionIndex()
<< MotionEvent.ACTION_POINTER_INDEX_SHIFT));
mListView.onTouchEvent(cancelEvent);
}
} else {
mDownX = motionEvent.getRawX();
deltaX = 0;
}
if(layout == null) {
layout = (RelativeLayout) mDownView;
frontView = layout.getChildAt(0);
backView = layout.getChildAt(1);
}
if(deltaX > 50) {
backView.setVisibility(View.VISIBLE);
}
if (mSwiping) {
setTranslationX(frontView, deltaX);
setAlpha(frontView, Math.max(0f, Math.min(1f,
1f - 2f * Math.abs(deltaX) / mViewWidth)));
return true;
}
break;
}
}
return false;
}
private boolean isDirectionValid(float deltaX) {
int rtlSign = 1;
// On API level 17 and above, check if we are in a Right-To-Left layout
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if(mListView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
rtlSign = -1;
}
}
// Check if swipe has been done in the corret direction
switch(mSwipeDirection) {
default:
case BOTH:
return true;
case START:
return rtlSign * deltaX < 0;
case END:
return rtlSign * deltaX > 0;
}
}
class PendingDismissData implements Comparable<PendingDismissData> {
public int position;
public View view;
public PendingDismissData(int position, View view) {
this.position = position;
this.view = view;
}
#Override
public int compareTo(PendingDismissData other) {
// Sort by descending position
return other.position - position;
}
}
private void performDismiss(final View dismissView, final int dismissPosition) {
// Animate the dismissed list item to zero-height and fire the dismiss callback when
// all dismissed list item animations have completed. This triggers layout on each animation
// frame; in the future we may want to do something smarter and more performant.
final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
final int originalHeight = dismissView.getHeight();
ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
--mDismissAnimationRefCount;
if (mDismissAnimationRefCount == 0) {
// No active animations, process all pending dismisses.
for(PendingDismissData dismiss : mPendingDismisses) {
if(mMode == UndoMode.SINGLE_UNDO) {
for(Undoable undoable : mUndoActions) {
undoable.discard();
}
mUndoActions.clear();
}
Undoable undoable = mCallback.onDismiss(mListView, dismiss.position);
if(undoable != null) {
mUndoActions.add(undoable);
}
mDelayedMsgId++;
}
if(!mUndoActions.isEmpty()) {
changePopupText();
changeButtonLabel();
// Show undo popup
mUndoPopup.showAtLocation(mListView,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
0, (int)(mDensity * 15));
// Queue the dismiss only if required
if(!mTouchBeforeAutoHide) {
// Send a delayed message to hide popup
mHandler.sendMessageDelayed(mHandler.obtainMessage(mDelayedMsgId),
mAutoHideDelay);
}
}
ViewGroup.LayoutParams lp;
for (PendingDismissData pendingDismiss : mPendingDismisses) {
// Reset view presentation
setAlpha(pendingDismiss.view, 1f);
setTranslationX(pendingDismiss.view, 0);
lp = pendingDismiss.view.getLayoutParams();
lp.height = originalHeight;
pendingDismiss.view.setLayoutParams(lp);
}
mPendingDismisses.clear();
}
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
lp.height = (Integer) valueAnimator.getAnimatedValue();
dismissView.setLayoutParams(lp);
}
});
mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView));
animator.start();
}
private void changePopupText() {
String msg = "";
if(mUndoActions.size() > 1 && mDeleteMultipleString != null) {
msg = String.format(mDeleteMultipleString, mUndoActions.size());
} else if(mUndoActions.size() >= 1) {
// Set title from single undoable or when no multiple deletion string
// is given
if(mUndoActions.get(mUndoActions.size() - 1).getTitle() != null) {
msg = mUndoActions.get(mUndoActions.size() - 1).getTitle();
} else {
msg = mDeleteString;
}
}
mUndoText.setText(msg);
}
private void changeButtonLabel() {
String msg;
if(mUndoActions.size() > 1 && mMode == UndoMode.COLLAPSED_UNDO) {
msg = mListView.getResources().getString(R.string.undoall);
} else {
msg = mListView.getResources().getString(R.string.undo);
}
mUndoButton.setText(msg);
}
/**
* Takes care of undoing a dismiss. This will be added as a
* {#link View.OnClickListener} to the undo button in the undo popup.
*/
private class UndoHandler implements View.OnClickListener {
public void onClick(View v) {
if(!mUndoActions.isEmpty()) {
switch(mMode) {
case SINGLE_UNDO:
mUndoActions.get(0).undo();
mUndoActions.clear();
break;
case COLLAPSED_UNDO:
Collections.reverse(mUndoActions);
for(Undoable undo : mUndoActions) {
undo.undo();
}
mUndoActions.clear();
break;
case MULTI_UNDO:
mUndoActions.get(mUndoActions.size() - 1).undo();
mUndoActions.remove(mUndoActions.size() - 1);
break;
}
}
// Dismiss dialog or change text
if(mUndoActions.isEmpty()) {
mUndoPopup.dismiss();
} else {
changePopupText();
changeButtonLabel();
}
mDelayedMsgId++;
}
}
/**
* Handler used to hide the undo popup after a special delay.
*/
private class HideUndoPopupHandler extends Handler {
#Override
public void handleMessage(Message msg) {
if(msg.what == mDelayedMsgId) {
// Call discard on any element
for(Undoable undo : mUndoActions) {
undo.discard();
}
mUndoActions.clear();
mUndoPopup.dismiss();
}
}
}
/**
* Enable/disable swipe.
*/
public void setSwipeDisabled(boolean disabled) {
this.mSwipeDisabled = disabled;
}
}
enjoy!
Use a ListView extension such as android-swipelistview.
You may also need to refer to the demo source. Instructions for setting up the demo can be found here.
To make a phone call when the user swipes left, add the below code to the instance of SwipeListView:
src > activities > SwipeListViewExampleActivity.java > onCreate()
swipeListView.setSwipeListViewListener(new BaseSwipeListViewListener() {
#Override
public void onOpened(int position, boolean toRight) {
if(!toRight) {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:0123456789"));
startActivity(intent);
}
}
});
For swipe right you can set it to dismiss which should be sufficient for what you are trying to achieve.
res > layout > swipe-list-view-activity.xml > SwipeListView
swipe:swipeActionRight="dismiss"
you can use this library https://github.com/timroes/EnhancedListView An Android ListView with enhanced functionality (e.g. Swipe To Dismiss or Undo).
I am using pulltorefresh in my application.In onRefresh(), I tried to remove all the items by keeping listView.setAdapter(null);
But still my listView.getCount() is returning 1.
listView.setOnRefreshListener(new OnRefreshListener() {
// #Override
public void onRefresh() {
// Your code to refresh the list contents goes here
scroll=true;
pic.clear();
id.clear();
name.clear();
msg.clear();
img.clear();
profimg.clear();
objid.clear();
comment.clear();
weburl.clear();
adapter.clear();
likes.clear();
like_or_unlike.clear();
previousTotal = 0;
adapter.clear();
j=0;
loading = true;
webserv="https://graph.facebook.com/me/home?access_token="+accesstoken;
// listView.setAdapter(null);
System.out.println(listView.getCount());
// doInBack dob=new doInBack();
// dob.execute();
System.out.println(listView.getCount());
doback(webserv);
Log.e("hi","doback called");
}
});
My pulltorefresh class is
package com.beerbro.utils;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.*;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.*;
import android.view.animation.Animation.AnimationListener;
import android.widget.*;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* A generic, customizable Android ListView implementation that has 'Pull to Refresh' functionality.
* <p/>
* This ListView can be used in place of the normal Android android.widget.ListView class.
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* 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 boolean scrollbarEnabled;
private boolean bounceBackHeader;
private boolean lockScrollWhileRefreshing;
private boolean showLastUpdatedText;
private String pullToRefreshText;
private String releaseToRefreshText;
private String refreshingText;
private String lastUpdatedText;
private SimpleDateFormat lastUpdatedDateFormat = new SimpleDateFormat("dd/MM HH:mm");
private float previousY;
private int headerPadding;
private boolean hasResetHeader;
private long lastUpdated = -1;
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 TextView lastUpdatedTextView;
private OnItemClickListener onItemClickListener;
private OnItemLongClickListener onItemLongClickListener;
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;
}
#Override
public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener){
this.onItemLongClickListener = onItemLongClickListener;
}
/**
* 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;
}
/**
* Default is false. Show the last-updated date/time in the 'Pull ro Refresh'
* header. See 'setLastUpdatedDateFormat' to set the date/time formatting.
*
* #param showLastUpdatedText
*/
public void setShowLastUpdatedText(boolean showLastUpdatedText){
this.showLastUpdatedText = showLastUpdatedText;
if(!showLastUpdatedText) lastUpdatedTextView.setVisibility(View.GONE);
}
/**
* Default: "dd/MM HH:mm". Set the format in which the last-updated
* date/time is shown. Meaningless if 'showLastUpdatedText == false (default)'.
* See 'setShowLastUpdatedText'.
*
* #param lastUpdatedDateFormat
*/
public void setLastUpdatedDateFormat(SimpleDateFormat lastUpdatedDateFormat){
this.lastUpdatedDateFormat = lastUpdatedDateFormat;
}
/**
* 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();
lastUpdated = System.currentTimeMillis();
}
/**
* 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.ptr_header, null);
header = (RelativeLayout) headerContainer.findViewById(R.id.ptr_id_header);
text = (TextView) header.findViewById(R.id.ptr_id_text);
lastUpdatedTextView = (TextView) header.findViewById(R.id.ptr_id_last_updated);
image = (ImageView) header.findViewById(R.id.ptr_id_image);
spinner = (ProgressBar) header.findViewById(R.id.ptr_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);
lastUpdatedText = getContext().getString(R.string.ptr_last_updated);
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());
super.setOnItemLongClickListener(new PTROnItemLongClickListener());
}
private void setHeaderPadding(int padding){
headerPadding = padding;
MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) header.getLayoutParams();
mlp.setMargins(0, Math.round(padding), 0, 0);
header.setLayoutParams(mlp);
}
#Override
public boolean onTouchEvent(MotionEvent event){
if(lockScrollWhileRefreshing
&& (state == State.REFRESHING || getAnimation() != null && !getAnimation().hasEnded())){
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(Math.round(headerPadding + diff), -header.getHeight());
if(newHeaderPadding != headerPadding && state != State.REFRESHING){
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);
}
return true;
}
}
break;
}
return super.onTouchEvent(event);
}
private void bounceBackHeader(){
int yTranslate = state == State.REFRESHING ?
header.getHeight() - headerContainer.getHeight() :
-headerContainer.getHeight() - headerContainer.getTop();
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(yTranslate));
startAnimation(bounceAnimation);
}
private void resetHeader(){
if(getFirstVisiblePosition() > 0){
setHeaderPadding(-header.getHeight());
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);
if(showLastUpdatedText && lastUpdated != -1){
lastUpdatedTextView.setVisibility(View.VISIBLE);
lastUpdatedTextView.setText(String.format(lastUpdatedText, lastUpdatedDateFormat.format(new Date(lastUpdated))));
}
break;
case RELEASE_TO_REFRESH:
spinner.setVisibility(View.INVISIBLE);
image.setVisibility(View.VISIBLE);
text.setText(releaseToRefreshText);
break;
case REFRESHING:
setUiRefreshing();
lastUpdated = System.currentTimeMillis();
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, translation;
private State stateAtAnimationStart;
public HeaderAnimationListener(int translation){
this.translation = translation;
}
public void onAnimationStart(Animation animation){
stateAtAnimationStart = state;
android.view.ViewGroup.LayoutParams lp = getLayoutParams();
height = lp.height;
lp.height = getHeight() - translation;
setLayoutParams(lp);
if(scrollbarEnabled){
setVerticalScrollBarEnabled(false);
}
}
// #Override
public void onAnimationEnd(Animation animation){
setHeaderPadding(stateAtAnimationStart == State.REFRESHING ? 0 : -measuredHeaderHeight - headerContainer.getTop());
setSelection(0);
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(){
resetHeader();
}
}, 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 && state == State.PULL_TO_REFRESH){
// Passing up onItemClick. Correct position with the number of header views
onItemClickListener.onItemClick(adapterView, view, position - getHeaderViewsCount(), id);
}
}
}
private class PTROnItemLongClickListener implements OnItemLongClickListener{
// #Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id){
hasResetHeader = false;
if(onItemLongClickListener != null && state == State.PULL_TO_REFRESH){
// Passing up onItemLongClick. Correct position with the number of header views
return onItemLongClickListener.onItemLongClick(adapterView, view, position - getHeaderViewsCount(), id);
}
return false;
}
}
}
I really didnt understand why it is returning 1 instead of 0.
Have you tried to clear the list and the notify the adapter?
I mean, If I use an String array to make the list:
ArrayList<String> names=new ArrayList<String>();
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, names);
ListView listView = (ListView) findViewById(android.R.id.list);
listView.setAdapter(adapter);
If I want to clear it, I make:
names.clear();
adapter.notifyDataSetChanged();
I need to load only new items on pull to refresh, remaining loaded items should move down after the new items are loaded. I am loading 10,10 items in load more once again if I do pull to refresh I want all loaded items on top with newly updated item.
How to do that?
((PullAndLoadListView)getListView()).setOnRefreshListener(new OnRefreshListener(){public void onRefresh(){}}
I would definitely take a look at Chris Banes' implementation of pull-to-refresh. His code does not only include this interaction style for ListView, but also GridView and WebView.
Especially the latter will be of interest in your case, since it's an example implementation of pull-to-refresh for a view that does not use an adapter for its content. If you look at the source code, you'll see that every concrete pull-to-refreh view in Banes' project extends from a generic PullToRefreshBase, which contains most of the logic for animation and refreshing. The benefit of having that base class is that doing the same thing for any other type of view, e.g. a TextView, should be pretty straightforward.
The only drawback of this approach is that the implementation is a wrapper for other views, meaning you'll have write a couple of extra lines to get the actual view. So it's not a full drop-in replacement. However, its functionality and features far exceed that little inconvenience.
EDITED :
Look at the Below Code i have implemented
in your Main JAVA File :
PullToRefreshListView listview;
listview = (PullToRefreshListView) findViewById(R.id.airpost_listView);
listview.setOnRefreshListener(new OnRefreshListener() {
public void onRefresh() {
// TODO Auto-generated method stub
new GetPost().execute(); // AsyncTask where you can put your logic when to call the listview for getting new data or let it be same as before
}
});
Listview Defined in xml File:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/bhavesh"
android:padding="5dp" >
<com.FlightMate.AirpostTab.PullToRefreshListView
android:id="#+id/airpost_listView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff"
android:cacheColorHint="#android:color/transparent"
android:divider="#00000000" />
</LinearLayout>
Here is PullToRefreshListView :
package com.FlightMate.AirpostTab;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
public class PullToRefreshListView extends PullToRefreshBase<ListView> {
public PullToRefreshListView(Context context) {
super(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected final ListView createAdapterView(Context context,
AttributeSet attrs) {
ListView lv = new ListView(context, attrs);
// Set it to this so it can be used in ListActivity/ListFragment
lv.setId(android.R.id.list);
return lv;
}
}
here is PullToRefreshBase :
package com.FlightMate.AirpostTab;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;
import com.FlightMate.R;
public abstract class PullToRefreshBase<T extends AbsListView> extends
LinearLayout implements OnTouchListener, OnScrollListener {
private final class SmoothScrollRunnable implements Runnable {
static final int ANIMATION_DURATION_MS = 190;
static final int ANIMATION_FPS = 1000 / 60;
private final Interpolator interpolator;
private final int scrollToY;
private final int scrollFromY;
private final Handler handler;
private boolean continueRunning = true;
private long startTime = -1;
private int currentY = -1;
public SmoothScrollRunnable(Handler handler, int fromY, int toY) {
this.handler = handler;
this.scrollFromY = fromY;
this.scrollToY = toY;
this.interpolator = new AccelerateDecelerateInterpolator();
}
// #Override
public void run() {
/**
* Only set startTime if this is the first time we're starting, else
* actually calculate the Y delta
*/
if (startTime == -1) {
startTime = System.currentTimeMillis();
} else {
/**
* We do do all calculations in long to reduce software float
* calculations. We use 1000 as it gives us good accuracy and
* small rounding errors
*/
long normalizedTime = (1000 * (System.currentTimeMillis() - startTime))
/ ANIMATION_DURATION_MS;
normalizedTime = Math.max(Math.min(normalizedTime, 1000), 0);
final int deltaY = Math
.round((scrollFromY - scrollToY)
* interpolator
.getInterpolation(normalizedTime / 1000f));
this.currentY = scrollFromY - deltaY;
setHeaderScroll(currentY);
}
// If we're not at the target Y, keep going...
if (continueRunning && scrollToY != currentY) {
handler.postDelayed(this, ANIMATION_FPS);
}
}
public void stop() {
this.continueRunning = false;
this.handler.removeCallbacks(this);
}
};
// ===========================================================
// Constants
// ===========================================================
static final int PULL_TO_REFRESH = 0;
static final int RELEASE_TO_REFRESH = PULL_TO_REFRESH + 1;
static final int REFRESHING = RELEASE_TO_REFRESH + 1;
static final int EVENT_COUNT = 3;
public static final int MODE_PULL_DOWN_TO_REFRESH = 0x1;
public static final int MODE_PULL_UP_TO_REFRESH = 0x2;
public static final int MODE_BOTH = 0x3;
// ===========================================================
// Fields
// ===========================================================
private int state = PULL_TO_REFRESH;
private int mode = MODE_PULL_DOWN_TO_REFRESH;
private int currentMode;
private boolean disableScrollingWhileRefreshing = true;
private T adapterView;
private boolean isPullToRefreshEnabled = true;
private LoadingLayout headerLayout;
private LoadingLayout footerLayout;
private int headerHeight;
private final Handler handler = new Handler();
private OnTouchListener onTouchListener;
private OnRefreshListener onRefreshListener;
private OnScrollListener onScrollListener;
private OnLastItemVisibleListener onLastItemVisibleListener;
private int lastSavedFirstVisibleItem = -1;
private SmoothScrollRunnable currentSmoothScrollRunnable;
private float startY = -1;
private final float[] lastYs = new float[EVENT_COUNT];
// ===========================================================
// Constructors
// ===========================================================
public PullToRefreshBase(Context context) {
this(context, null);
}
public PullToRefreshBase(Context context, int mode) {
this(context);
this.mode = mode;
}
public PullToRefreshBase(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
// ===========================================================
// Getter & Setter
// ===========================================================
/**
* Get the Wrapped AdapterView. Anything returned here has already been
* added to the content view.
*
* #return The AdapterView which is currently wrapped
*/
public final T getAdapterView() {
return adapterView;
}
/**
* Whether Pull-to-Refresh is enabled
*
* #return enabled
*/
public final boolean isPullToRefreshEnabled() {
return isPullToRefreshEnabled;
}
public void setDisableScrollingWhileRefreshing(
boolean disableScrollingWhileRefreshing) {
this.disableScrollingWhileRefreshing = disableScrollingWhileRefreshing;
}
/**
* Mark the current Refresh as complete. Will Reset the UI and hide the
* Refreshing View
*/
public final void onRefreshComplete() {
resetHeader();
}
public final void setOnLastItemVisibleListener(
OnLastItemVisibleListener listener) {
onLastItemVisibleListener = listener;
}
public final void setOnRefreshListener(OnRefreshListener listener) {
onRefreshListener = listener;
}
/**
* A mutator to enable/disable Pull-to-Refresh for the current AdapterView
*
* #param enable
* Whether Pull-To-Refresh should be used
*/
public final void setPullToRefreshEnabled(boolean enabled) {
this.isPullToRefreshEnabled = enabled;
}
public final void setReleaseLabel(String releaseLabel) {
if (null != headerLayout) {
headerLayout.setReleaseLabel(releaseLabel);
}
if (null != footerLayout) {
footerLayout.setReleaseLabel(releaseLabel);
}
}
public final void setPullLabel(String pullLabel) {
if (null != headerLayout) {
headerLayout.setPullLabel(pullLabel);
}
if (null != footerLayout) {
footerLayout.setPullLabel(pullLabel);
}
}
public final void setRefreshingLabel(String refreshingLabel) {
if (null != headerLayout) {
headerLayout.setRefreshingLabel(refreshingLabel);
}
if (null != footerLayout) {
footerLayout.setRefreshingLabel(refreshingLabel);
}
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
public final void setOnScrollListener(OnScrollListener listener) {
onScrollListener = listener;
}
#Override
public final void setOnTouchListener(OnTouchListener listener) {
onTouchListener = listener;
}
public final void onScroll(final AbsListView view,
final int firstVisibleItem, final int visibleItemCount,
final int totalItemCount) {
if (null != onLastItemVisibleListener) {
// detect if last item is visible
if (visibleItemCount > 0 && visibleItemCount < totalItemCount
&& (firstVisibleItem + visibleItemCount == totalItemCount)) {
// only process first event
if (firstVisibleItem != lastSavedFirstVisibleItem) {
lastSavedFirstVisibleItem = firstVisibleItem;
onLastItemVisibleListener.onLastItemVisible();
}
}
}
if (null != onScrollListener) {
onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
totalItemCount);
}
}
public final void onScrollStateChanged(final AbsListView view,
final int scrollState) {
if (null != onScrollListener) {
onScrollListener.onScrollStateChanged(view, scrollState);
}
}
// #Override
public final boolean onTouch(View view, MotionEvent ev) {
if (isPullToRefreshEnabled) {
// Returning true here stops the ListView being scrollable while we
// refresh
if (state == REFRESHING && disableScrollingWhileRefreshing) {
return true;
} else if (onAdapterViewTouch(view, ev)) {
return true;
}
}
if (null != onTouchListener) {
return onTouchListener.onTouch(view, ev);
}
return false;
}
/**
* This is implemented by derived classes to return the created AdapterView.
* If you need to use a custom AdapterView (such as a custom ListView),
* override this method and return an instance of your custom class.
*
* Be sure to set the ID of the view in this method, especially if you're
* using a ListActivity or ListFragment.
*
* #param context
* #param attrs
* AttributeSet from wrapped class. Means that anything you
* include in the XML layout declaration will be routed to the
* AdapterView
* #return New instance of the AdapterView
*/
protected abstract T createAdapterView(Context context, AttributeSet attrs);
// ===========================================================
// Methods
// ===========================================================
protected final void resetHeader() {
state = PULL_TO_REFRESH;
initializeYsHistory();
startY = -1;
if (null != headerLayout) {
headerLayout.reset();
}
if (null != footerLayout) {
footerLayout.reset();
}
smoothScrollTo(0);
}
private void init(Context context, AttributeSet attrs) {
setOrientation(LinearLayout.VERTICAL);
// Styleables from XML
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.PullToRefresh);
mode = a.getInteger(R.styleable.PullToRefresh_mode,
MODE_PULL_DOWN_TO_REFRESH);
// AdapterView
// By passing the attrs, we can add ListView/GridView params via XML
adapterView = this.createAdapterView(context, attrs);
adapterView.setOnTouchListener(this);
adapterView.setOnScrollListener(this);
addView(adapterView, new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, 0, 1.0f));
// Loading View Strings
String pullLabel = context
.getString(R.string.pull_to_refresh_pull_label);
String refreshingLabel = context
.getString(R.string.pull_to_refresh_refreshing_label);
String releaseLabel = context
.getString(R.string.pull_to_refresh_release_label);
// Add Loading Views
if (mode == MODE_PULL_DOWN_TO_REFRESH || mode == MODE_BOTH) {
headerLayout = new LoadingLayout(context,
MODE_PULL_DOWN_TO_REFRESH, releaseLabel, pullLabel,
refreshingLabel);
addView(headerLayout, 0, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
measureView(headerLayout);
headerHeight = headerLayout.getMeasuredHeight();
}
if (mode == MODE_PULL_UP_TO_REFRESH || mode == MODE_BOTH) {
footerLayout = new LoadingLayout(context, MODE_PULL_UP_TO_REFRESH,
releaseLabel, pullLabel, refreshingLabel);
addView(footerLayout, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
measureView(footerLayout);
headerHeight = footerLayout.getMeasuredHeight();
}
// Styleables from XML
if (a.hasValue(R.styleable.PullToRefresh_headerTextColor)) {
final int color = a.getColor(
R.styleable.PullToRefresh_headerTextColor, Color.BLACK);
if (null != headerLayout) {
headerLayout.setTextColor(color);
}
if (null != footerLayout) {
footerLayout.setTextColor(color);
}
}
if (a.hasValue(R.styleable.PullToRefresh_headerBackground)) {
this.setBackgroundResource(a.getResourceId(
R.styleable.PullToRefresh_headerBackground, Color.WHITE));
}
if (a.hasValue(R.styleable.PullToRefresh_adapterViewBackground)) {
adapterView.setBackgroundResource(a.getResourceId(
R.styleable.PullToRefresh_adapterViewBackground,
Color.WHITE));
}
a.recycle();
// Hide Loading Views
switch (mode) {
case MODE_BOTH:
setPadding(getPaddingLeft(), -headerHeight, getPaddingRight(),
-headerHeight);
break;
case MODE_PULL_UP_TO_REFRESH:
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
-headerHeight);
break;
case MODE_PULL_DOWN_TO_REFRESH:
default:
setPadding(getPaddingLeft(), -headerHeight, getPaddingRight(),
getPaddingBottom());
break;
}
// If we're not using MODE_BOTH, then just set currentMode to current
// mode
if (mode != MODE_BOTH) {
currentMode = mode;
}
}
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
private boolean onAdapterViewTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
updateEventStates(event);
if (isPullingToRefresh() && startY == -1) {
startY = event.getY();
// Need to set current Mode if we're using both
if (mode == MODE_BOTH) {
if (isUserDraggingDownwards()) {
currentMode = MODE_PULL_DOWN_TO_REFRESH;
} else if (isUserDraggingUpwards()) {
currentMode = MODE_PULL_UP_TO_REFRESH;
}
}
return false;
}
if (startY != -1 && !adapterView.isPressed()) {
pullEvent(event, startY);
return true;
}
break;
case MotionEvent.ACTION_UP:
initializeYsHistory();
startY = -1;
if (state == RELEASE_TO_REFRESH) {
setRefreshing();
if (onRefreshListener != null) {
onRefreshListener.onRefresh();
}
} else {
smoothScrollTo(0);
}
break;
}
return false;
}
private void pullEvent(MotionEvent event, float firstY) {
float averageY = average(lastYs);
final int height;
switch (currentMode) {
case MODE_PULL_UP_TO_REFRESH:
height = (int) Math.max(firstY - averageY, 0);
setHeaderScroll(height);
break;
case MODE_PULL_DOWN_TO_REFRESH:
default:
height = (int) Math.max(averageY - firstY, 0);
setHeaderScroll(-height);
break;
}
if (state == PULL_TO_REFRESH && headerHeight < height) {
state = RELEASE_TO_REFRESH;
if (null != headerLayout) {
headerLayout.releaseToRefresh();
}
if (null != footerLayout) {
footerLayout.releaseToRefresh();
}
} else if (state == RELEASE_TO_REFRESH && headerHeight >= height) {
state = PULL_TO_REFRESH;
if (null != headerLayout) {
headerLayout.pullToRefresh();
}
if (null != footerLayout) {
footerLayout.pullToRefresh();
}
}
}
private void setHeaderScroll(int y) {
scrollTo(0, y);
}
private void setRefreshing() {
state = REFRESHING;
if (null != headerLayout) {
headerLayout.refreshing();
}
if (null != footerLayout) {
footerLayout.refreshing();
}
switch (currentMode) {
case MODE_PULL_DOWN_TO_REFRESH:
smoothScrollTo(-headerHeight);
break;
case MODE_PULL_UP_TO_REFRESH:
smoothScrollTo(headerHeight);
break;
}
}
private float average(float[] ysArray) {
float avg = 0;
for (int i = 0; i < EVENT_COUNT; i++) {
avg += ysArray[i];
}
return avg / EVENT_COUNT;
}
private void initializeYsHistory() {
for (int i = 0; i < EVENT_COUNT; i++) {
lastYs[i] = 0;
}
}
private void updateEventStates(MotionEvent event) {
for (int i = 0, z = event.getHistorySize(); i < z; i++) {
this.updateEventStates(event.getHistoricalY(i));
}
this.updateEventStates(event.getY());
}
private void updateEventStates(float y) {
for (int i = 0; i < EVENT_COUNT - 1; i++) {
lastYs[i] = lastYs[i + 1];
}
lastYs[EVENT_COUNT - 1] = y;
}
private boolean isPullingToRefresh() {
if (isPullToRefreshEnabled && state != REFRESHING) {
switch (mode) {
case MODE_PULL_DOWN_TO_REFRESH:
return isFirstItemVisible() && isUserDraggingDownwards();
case MODE_PULL_UP_TO_REFRESH:
return isLastItemVisible() && isUserDraggingUpwards();
case MODE_BOTH:
return (isFirstItemVisible() && isUserDraggingDownwards())
|| (isLastItemVisible() && isUserDraggingUpwards());
}
}
return false;
}
private boolean isFirstItemVisible() {
if (this.adapterView.getCount() == 0) {
return true;
} else if (adapterView.getFirstVisiblePosition() == 0) {
return adapterView.getChildAt(0).getTop() >= adapterView.getTop();
} else {
return false;
}
}
private boolean isLastItemVisible() {
final int count = this.adapterView.getCount();
if (count == 0) {
return true;
} else if (adapterView.getLastVisiblePosition() == count - 1) {
return true;
} else {
return false;
}
}
private boolean isUserDraggingDownwards() {
return this.isUserDraggingDownwards(0, EVENT_COUNT - 1);
}
private boolean isUserDraggingDownwards(int from, int to) {
return lastYs[from] != 0 && lastYs[to] != 0
&& Math.abs(lastYs[from] - lastYs[to]) > 10
&& lastYs[from] < lastYs[to];
}
private boolean isUserDraggingUpwards() {
return this.isUserDraggingUpwards(0, EVENT_COUNT - 1);
}
private boolean isUserDraggingUpwards(int from, int to) {
return lastYs[from] != 0 && lastYs[to] != 0
&& Math.abs(lastYs[to] - lastYs[from]) > 10
&& lastYs[to] < lastYs[from];
}
private void smoothScrollTo(int y) {
if (null != currentSmoothScrollRunnable) {
currentSmoothScrollRunnable.stop();
}
this.currentSmoothScrollRunnable = new SmoothScrollRunnable(handler,
getScrollY(), y);
handler.post(currentSmoothScrollRunnable);
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public static interface OnRefreshListener {
public void onRefresh();
}
public static interface OnLastItemVisibleListener {
public void onLastItemVisible();
}
}
Hope it will Help you out from your Problem. let me know if you are still finding any difficulties.