Skip to content

Commit

Permalink
Merge pull request #98 from DougSimonton/master
Browse files Browse the repository at this point in the history
Support for long click and pressed state
  • Loading branch information
denizmveli committed Jul 1, 2014
2 parents fa002aa + 733bfb5 commit d8ca7e6
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 12 deletions.
162 changes: 151 additions & 11 deletions library/src/main/java/com/etsy/android/grid/ExtendableListView.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.util.SparseArrayCompat;
Expand Down Expand Up @@ -138,6 +139,33 @@ public abstract class ExtendableListView extends AbsListView {

protected boolean mClipToPadding;
private PerformClick mPerformClick;

private Runnable mPendingCheckForTap;
private CheckForLongPress mPendingCheckForLongPress;

private class CheckForLongPress extends WindowRunnnable implements Runnable {
public void run() {
final int motionPosition = mMotionPosition;
final View child = getChildAt(motionPosition);
if (child != null) {
final int longPressPosition = mMotionPosition;
final long longPressId = mAdapter.getItemId(mMotionPosition + mFirstPosition);

boolean handled = false;
if (sameWindow() && !mDataChanged) {
handled = performLongPress(child, longPressPosition + mFirstPosition, longPressId);
}
if (handled) {
mTouchMode = TOUCH_MODE_IDLE;
setPressed(false);
child.setPressed(false);
} else {
mTouchMode = TOUCH_MODE_DONE_WAITING;
}

}
}
}

/**
* A class that represents a fixed view in a list, for example a header at the top
Expand Down Expand Up @@ -812,6 +840,39 @@ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}

final class CheckForTap implements Runnable {
public void run() {
if (mTouchMode == TOUCH_MODE_DOWN) {
mTouchMode = TOUCH_MODE_TAP;
final View child = getChildAt(mMotionPosition);
if (child != null && !child.hasFocusable()) {
mLayoutMode = LAYOUT_NORMAL;

if (!mDataChanged) {
layoutChildren();
child.setPressed(true);
setPressed(true);

final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
final boolean longClickable = isLongClickable();

if (longClickable) {
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
}
mPendingCheckForLongPress.rememberWindowAttachCount();
postDelayed(mPendingCheckForLongPress, longPressTimeout);
} else {
mTouchMode = TOUCH_MODE_DONE_WAITING;
}
} else {
mTouchMode = TOUCH_MODE_DONE_WAITING;
}
}
}
}
}

private boolean onTouchDown(final MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
Expand All @@ -831,7 +892,10 @@ private boolean onTouchDown(final MotionEvent event) {
// is it a tap or a scroll .. we don't know yet!
mTouchMode = TOUCH_MODE_DOWN;

// TODO : add handling for a click removed from here
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());

if (event.getEdgeFlags() != 0 && motionPosition < 0) {
// If we couldn't find a view to click on, but the down event was touching
Expand Down Expand Up @@ -891,6 +955,12 @@ private boolean onTouchCancel(final MotionEvent event) {
mTouchMode = TOUCH_MODE_IDLE;
setPressed(false);
invalidate(); // redraw selector
final Handler handler = getHandler();

if (handler != null) {
handler.removeCallbacks(mPendingCheckForLongPress);
}

recycleVelocityTracker();
mActivePointerId = INVALID_POINTER;
return true;
Expand All @@ -909,7 +979,14 @@ private boolean onTouchUp(final MotionEvent event) {

setPressed(false);
invalidate(); // redraw selector

final Handler handler = getHandler();
if (handler != null) {
handler.removeCallbacks(mPendingCheckForLongPress);
}

recycleVelocityTracker();

mActivePointerId = INVALID_POINTER;
return true;
}
Expand Down Expand Up @@ -945,17 +1022,58 @@ private boolean onTouchUpScrolling(final MotionEvent event) {
}

private boolean onTouchUpTap(final MotionEvent event) {
if (mPerformClick == null) {
invalidate();
mPerformClick = new PerformClick();
}
final int motionPosition = mMotionPosition;
if (!mDataChanged && motionPosition >= 0 && mAdapter.isEnabled(motionPosition)) {
final PerformClick performClick = mPerformClick;
performClick.mClickMotionPosition = motionPosition;
performClick.rememberWindowAttachCount();
performClick.run();
if (motionPosition >= 0) {
final View child = getChildAt(motionPosition);
if (child != null && !child.hasFocusable()) {
if (mTouchMode != TOUCH_MODE_DOWN) {
child.setPressed(false);
}

if (mPerformClick == null) {
invalidate();
mPerformClick = new PerformClick();
}

final PerformClick performClick = mPerformClick;
performClick.mClickMotionPosition = motionPosition;
performClick.rememberWindowAttachCount();

// mResurrectToPosition = motionPosition;

if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP) {
final Handler handler = getHandler();
if (handler != null) {
handler.removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ?
mPendingCheckForTap : mPendingCheckForLongPress);
}
mLayoutMode = LAYOUT_NORMAL;
if (!mDataChanged && motionPosition >= 0 && mAdapter.isEnabled(motionPosition)) {
mTouchMode = TOUCH_MODE_TAP;
layoutChildren();
child.setPressed(true);
setPressed(true);
postDelayed(new Runnable() {
public void run() {
child.setPressed(false);
setPressed(false);
if (!mDataChanged) {
post(performClick);
}
mTouchMode = TOUCH_MODE_IDLE;
}
}, ViewConfiguration.getPressedStateDuration());
} else {
mTouchMode = TOUCH_MODE_IDLE;
}
return true;
} else if (!mDataChanged && motionPosition >= 0 && mAdapter.isEnabled(motionPosition)) {
post(performClick);
}
}
}
mTouchMode = TOUCH_MODE_IDLE;

return true;
}

Expand Down Expand Up @@ -1011,7 +1129,10 @@ private boolean startScrollIfNeeded(final int y) {
mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop;
}

// TODO : LONG PRESS
final Handler handler = getHandler();
if (handler != null) {
handler.removeCallbacks(mPendingCheckForLongPress);
}
setPressed(false);
View motionView = getChildAt(mMotionPosition - mFirstPosition);
if (motionView != null) {
Expand Down Expand Up @@ -2754,6 +2875,25 @@ public void run() {
}
}
}

private boolean performLongPress(final View child,
final int longPressPosition, final long longPressId) {
boolean handled = false;

OnItemLongClickListener onItemLongClickListener = getOnItemLongClickListener();
if (onItemLongClickListener != null) {
handled = onItemLongClickListener.onItemLongClick(ExtendableListView.this, child,
longPressPosition, longPressId);
}
// if (!handled) {
// mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
// handled = super.showContextMenuForChild(AbsListView.this);
// }
if (handled) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
}
return handled;
}

/**
* A base class for Runnables that will check that their view is still attached to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import com.etsy.android.grid.StaggeredGridView;

public class StaggeredGridActivity extends Activity implements AbsListView.OnScrollListener, AbsListView.OnItemClickListener {
public class StaggeredGridActivity extends Activity implements AbsListView.OnScrollListener, AbsListView.OnItemClickListener, AdapterView.OnItemLongClickListener {

private static final String TAG = "StaggeredGridActivity";
public static final String SAVED_DATA_KEY = "SAVED_DATA";
Expand Down Expand Up @@ -64,6 +64,7 @@ protected void onCreate(Bundle savedInstanceState) {
mGridView.setAdapter(mAdapter);
mGridView.setOnScrollListener(this);
mGridView.setOnItemClickListener(this);
mGridView.setOnItemLongClickListener(this);
}

@Override
Expand Down Expand Up @@ -131,4 +132,11 @@ private void onLoadMoreItems() {
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Toast.makeText(this, "Item Clicked: " + position, Toast.LENGTH_SHORT).show();
}

@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
{
Toast.makeText(this, "Item Long Clicked: " + position, Toast.LENGTH_SHORT).show();
return true;
}
}

0 comments on commit d8ca7e6

Please sign in to comment.