Back to project page AndroidTouchEditableListView.
The source code is released under:
Copyright (c) 2014 Serge Desmedt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Soft...
If you think the Android project AndroidTouchEditableListView listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package be.trojkasoftware.android.toucheditablelistview; // w w w . j a v a 2 s .co m import be.trojkasoftware.android.touch.TouchDataStore; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; public class TouchEditableStateManager { private static final String TAG = "TouchEditableStateManager"; public TouchEditableStateManager(TouchEditableListView listView, TouchEditableActionView actionHeader, TouchEditableActionView actionFooter) { mListView = listView; mActionHeader = actionHeader; mActionFooter = actionFooter; } public int getPublishedY() { return mPublishedY; } public boolean onTouchEvent(MotionEvent event) { mTouchDataStore.add(event); int action = event.getActionMasked(); int pointerIndex = event.getActionIndex(); int pointerId = event.getPointerId(pointerIndex); //Log.i(TAG, "onTouchEvent Action[" + action + "][PointerIndex:" + pointerIndex + "][PointerId:" + pointerId + "]X["+(int)event.getX(pointerIndex)+"]Y["+(int)event.getY(pointerIndex)+"]"); switch (action) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: // Log.i(TAG, "onTouchEvent ACTION_DOWN[PointerIndex:" + pointerIndex + "][PointerId:" + pointerId + "]X["+(int)event.getX(pointerIndex)+"]Y["+(int)event.getY(pointerIndex)+"]"); //Log.i(TAG, "onTouchEvent: Action[ACTION_DOWN]FirstVisiblePosition[" + mListView.getFirstVisiblePosition() + "]ChildAtIndexTag[" + mListView.getChildAt(0).getTag() + "]ChildAtIndexTop[" + mListView.getChildAt(0).getTop() + "]"); //Log.i(TAG, "onTouchEvent: Action[ACTION_DOWN]LastVisiblePosition[" + mListView.getLastVisiblePosition() + "]ChildAtEndTag[" + mListView.getChildAt(mListView.getChildCount()-1).getTag() + "]ChildAtEndBottom[" + mListView.getChildAt(mListView.getChildCount()-1).getBottom() + "]Height[" + mListView.getHeight() + "]"); //mNumberOfPointersDown++; int currentTouchPosition = mListView.pointToPosition((int)event.getX(pointerIndex), (int)event.getY(pointerIndex)); // Log.i(TAG, "onTouchEvent: Action[ACTION_DOWN]CurrentTouchPosition[" + currentTouchPosition + "]TopItemPosition[" + mTopItemPosition + "]BottomItemPosition[" + mBottomItemPosition + "]"); boolean testing = false; if(testing) { //TestSingleTouchIsOnBottom(currentTouchPosition, (int)event.getY()); //TestSingleTouchIsOnTop(currentTouchPosition, (int)event.getY()); } else { if(pointerIndex == 0) { mTopItemPosition = currentTouchPosition; //mTopDownYOnSecondTouch = (int)event.getY(pointerIndex); mPointerIdTop = pointerId; //mFirstPointerId = pointerId; //mFirstPointerDownX = (int)event.getX(pointerIndex); //mFirstPointerDownY = (int)event.getY(pointerIndex); } if(pointerIndex == 1 && mState == STATE_NORMAL) { if(Math.abs(currentTouchPosition - mTopItemPosition) != 1) { } else if(currentTouchPosition > mTopItemPosition) { mBottomItemPosition = currentTouchPosition; //mBottomDownYOnSecondTouch = (int)event.getY(pointerIndex); mPointerIdBottom = pointerId; // only when the second touch occurs do we start monitoring the first //mTopDownYOnSecondTouch = mLastTopMoveY; mState = STATE_INSERT_INBETWEEN; } else { mBottomItemPosition = mTopItemPosition; //mBottomDownYOnSecondTouch = mLastTopMoveY; //mTopDownY; mPointerIdBottom = mPointerIdTop; mTopItemPosition = currentTouchPosition; //mTopDownYOnSecondTouch = (int)event.getY(pointerIndex); mPointerIdTop = pointerId; mState = STATE_INSERT_INBETWEEN; } } } // Log.i(TAG, "onTouchEvent: Action[ACTION_DOWN]TopItemPosition[" + mTopItemPosition + "]BottomItemPosition[" + mBottomItemPosition + "]"); View v = mListView.getChildAt(mTopItemPosition - mListView.getFirstVisiblePosition()); mOriginalTopItemY = v.getTop(); mOriginalTopItemHeight = v.getMeasuredHeight(); mInsertAtYStart = Integer.MAX_VALUE; break; case MotionEvent.ACTION_MOVE: int pointerCount = event.getPointerCount(); // we only start doing something if at least one pointer moved 20 pixels from its touchdown position int topPointerDeviation = 0; int bottomPointerDeviation = 0; for(int i = 0; i < pointerCount; i++) { // if (mFirstPointerId == event.getPointerId(i)) { // //mFirstPointerMoveX = (int)event.getX(pointerIndex); // //mFirstPointerMoveY = (int)event.getY(pointerIndex); // } if (mPointerIdTop == event.getPointerId(i)) { //mPreviousTopMoveY = mLastTopMoveY; //mLastTopMoveY = (int) event.getY(i); topPointerDeviation = Math.abs(mTouchDataStore.get(mPointerIdTop).posYOnPointerDown.get(mTouchDataStore.getPointerId(mTouchDataStore.size() - 1)) /*mTopDownYOnSecondTouch*/ - (int) event.getY(i)); } if (mPointerIdBottom == event.getPointerId(i)) { //mLastBottomMoveY = (int) event.getY(i); bottomPointerDeviation = Math.abs(mTouchDataStore.get(mPointerIdBottom).posYOnPointerDown.get(mTouchDataStore.getPointerId(mTouchDataStore.size() - 1)) /*mBottomDownYOnSecondTouch*/ - (int) event.getY(i)); } } // if(topPointerDeviation < mMinimalDirectionalMovement // && bottomPointerDeviation < mMinimalDirectionalMovement) { // return false; // } if (mInitialMainDirection == DIRECTION_NONE && getMainDirection(mTouchDataStore.getPointerId(0)) == DIRECTION_NONE) { return false; } else if (mInitialMainDirection == DIRECTION_NONE) { mInitialMainDirection = getMainDirection(mTouchDataStore.getPointerId(0)); } if(mState == STATE_INSERT_AT_BOTTOM) { if(mInsertAtYStart > mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/) { int stretch = Math.min((int)(mElasticity * Math.abs(mInsertAtYStart - mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/)), mMaxStretchHeight); // the header will stretch downward, so will have to scroll upward to compensate int newFooterTop = mInitialFooterTop - stretch; mListView.setSelectionFromTop(mListView.getCount()-1, newFooterTop); // start stretching the header // Log.i(TAG, "onTouchEvent: Action[ACTION_MOVE:UP:STRETCH]InsertAtYStart[" + mInsertAtYStart + "]LastTopMoveY[" + mLastTopMoveY + "]NewFooterTop[" + newFooterTop + "]Stretch[" + stretch + "]"); if(!mActionFooter.isSet()) { View insertView = mInsertViewFactory.getInsertView(mListView.getCount() - 1 - (mListView.getFooterViewsCount() + mListView.getHeaderViewsCount()), -1); mActionFooter.setInsertView(insertView, mInsertStretchFactor); } mActionFooter.setStretch(stretch); mActionFooter.requestLayout(); mIsInserting = mActionHeader.isInserting(); return false; } // we've moved passed our startpoint, so we're back to normal mIsInserting = false; mActionFooter.setStretch(0); mActionFooter.requestLayout(); mState = STATE_NORMAL; } else if(mState == STATE_INSERT_AT_TOP) { if(mInsertAtYStart < mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/) { // start stretching the header int stretch = Math.min((int)(mElasticity * Math.abs(mInsertAtYStart - mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/)), mMaxStretchHeight); // Log.i(TAG, "onTouchEvent: Action[ACTION_MOVE:DOWN:STRETCH]InsertAtYStart[" + mInsertAtYStart + "]LastTopMoveY[" + mLastTopMoveY + "]Stretch[" + stretch + "]"); if(!mActionHeader.isSet()) { View insertView = mInsertViewFactory.getInsertView(-1, 0); mActionHeader.setInsertView(insertView, mInsertStretchFactor); } mActionHeader.setStretch(stretch); mActionHeader.requestLayout(); mIsInserting = mActionHeader.isInserting(); return false; } // we've moved passed our startpoint, so we're back to normal mIsInserting = false; mActionHeader.setStretch(0); mActionHeader.requestLayout(); mState = STATE_NORMAL; } else if(mState == STATE_INSERT_INBETWEEN) { mCurrentTopItemY = mOriginalTopItemY; // if we can show all the items in the arrayadapter at once // and the last item is not beyond the bottom of the listview // then there is no need to scroll if(isScrollable()) { mCurrentTopItemY = mOriginalTopItemY + Math.min((int)(mElasticity * (mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/ - mTouchDataStore.get(mPointerIdTop).posYOnPointerDown.get(mTouchDataStore.getPointerId(mTouchDataStore.size() - 1)) /*mTopDownYOnSecondTouch*/)), mMaxStretchHeight / 2); } mListView.setSelectionFromTop(mTopItemPosition, mCurrentTopItemY); // Log.i(TAG, "onTouchEvent.ACTION_MOVE.SetSelectionFromTop V0TopY["+mOriginalTopItemY+"]LastTopMoveY["+mLastTopMoveY+"]TopDownY["+mTopDownYOnSecondTouch+"][CurrentTopItemY:"+mCurrentTopItemY+"]"); TouchEditableItemView topItemView = (TouchEditableItemView)mListView.getChildAt(mTopItemPosition - mListView.getFirstVisiblePosition()); if(topItemView != null) { if(!topItemView.isSet()) { View insertView = mInsertViewFactory.getInsertView(mTopItemPosition - mListView.getFooterViewsCount(), mBottomItemPosition - mListView.getFooterViewsCount()); topItemView.setActionView(insertView, mInsertStretchFactor, Gravity.CENTER); } mIsInserting = topItemView.isShowingInsertView(); // Log.i(TAG, "onTouchEvent.ACTION_MOVE.AdjustItem[TopItemPosition:" + mTopItemPosition + "]"); // We calculate the stretch size here and store it // A layoutrequest can cause the childviews of the listviews (thus the items in the list) to be destroyed // and recreated. In that case we lose our information to be able to calculate the stretch-size mCurrentTopItemStretch = calculateCurrentTopItemStretch(mTopItemPosition, topItemView); adjustItem(mTopItemPosition, topItemView, true); mListView.requestLayout(); } else { // Log.i(TAG, "onTouchEvent.ACTION_MOVE.GetChildAt[TopItemPosition:"+mTopItemPosition+"] is NULL"); } } if(mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/ <= mTouchDataStore.get(mPointerIdTop).posYDown /*mPreviousTopMoveY*/ && getMainDirection(mPointerIdTop) == DIRECTION_VERTICAL && mState == STATE_NORMAL) { // Log.i(TAG, "onTouchEvent: Action[ACTION_MOVE:UP]LastVisiblePosition[" + mListView.getLastVisiblePosition() + "]ChildAtEndTag[" + mListView.getChildAt(mListView.getChildCount()-1).getTag() + "]ChildAtEndBottom[" + mListView.getChildAt(mListView.getChildCount()-1).getBottom() + "]Height[" + mListView.getHeight() + "]"); // we are moving up, // are we at the bottom of the control? if not, let standard handle this // we are not yet at the bottom // if the last visible position is not the footer (mind that the size of the adapter actually accounts for the header and footer !!! if((mListView.getLastVisiblePosition() < mListView.getCount()-1) ) { // Log.i(TAG, "onTouchEvent: Action[ACTION_MOVE:UP:NOT_AT_BOTTOM]Count[" + mListView.getCount() + "]LastVisiblePosition[" + mListView.getLastVisiblePosition() + "]ChildAtEndTag[" + mListView.getChildAt(mListView.getChildCount()-1).getTag() + "]ChildAtEndBottom[" + mListView.getChildAt(mListView.getChildCount()-1).getBottom() + "]"); return true; } // if so start insertion mState = STATE_INSERT_AT_BOTTOM; // initialize our startposition mInsertAtYStart = mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/; mInitialFooterTop = mListView.getChildAt(mListView.getChildCount()-1).getTop(); // Log.i(TAG, "onTouchEvent: Action[ACTION_MOVE:UP:INIT_STARTY]InsertAtYStart[" + mInsertAtYStart + "]LastVisiblePosition[" + mListView.getLastVisiblePosition() + "]ChildAtEndTag[" + mListView.getChildAt(mListView.getChildCount()-1).getTag() + "]AbsChildAtEndBottom[" + Math.abs(mListView.getChildAt(mListView.getChildCount()-1).getBottom()) + "]"); } if(mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/ >= mTouchDataStore.get(mPointerIdTop).posYDown /*mPreviousTopMoveY*/ && getMainDirection(mPointerIdTop) == DIRECTION_VERTICAL && mState == STATE_NORMAL) { // Log.i(TAG, "onTouchEvent: Action[ACTION_MOVE:DOWN]FirstVisiblePosition[" + mListView.getFirstVisiblePosition() + "]ChildAtStartTag[" + mListView.getChildAt(0).getTag() + "]ChildAtStartTop[" + mListView.getChildAt(0).getTop() + "]"); // we are moving down, // are we at the top of the control? if not, let standard handle this // we are not yet at the top // if the first visible position is not the header if((mListView.getFirstVisiblePosition() != 0) ) { // Log.i(TAG, "onTouchEvent: Action[ACTION_MOVE:DOWN:NOT_AT_TOP]FirstVisiblePosition[" + mListView.getFirstVisiblePosition() + "]ChildAtStartTag[" + mListView.getChildAt(0).getTag() + "]ChildAtStartTop[" + mListView.getChildAt(0).getTop() + "]"); return true; } // if so start insertion mState = STATE_INSERT_AT_TOP; // initialize our startposition mInsertAtYStart = mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/; // Log.i(TAG, "onTouchEvent: Action[ACTION_MOVE:DOWN:INIT_STARTY]InsertAtYStart[" + mInsertAtYStart + "]FirstVisiblePosition[" + mListView.getFirstVisiblePosition() + "]ChildAtStartTag[" + mListView.getChildAt(0).getTag() + "]AbsChildAtStartTop[" + Math.abs(mListView.getChildAt(0).getTop()) + "]"); } if((mTouchDataStore.get(mPointerIdTop).posXDown - mTouchDataStore.get(mPointerIdTop).getMoveX(0)) > (mListView.getWidth() / 2) && getMainDirection(mPointerIdTop) == DIRECTION_HORIZONTAL && mState == STATE_NORMAL) { // TouchEditableItemView topItemView = (TouchEditableItemView)mListView.getChildAt(mTopItemPosition - mListView.getFirstVisiblePosition()); // if(topItemView != null) // { // if(!topItemView.isSet()) { // View deleteView = mDeleteViewFactory.getDeleteView(mTopItemPosition - mListView.getFooterViewsCount()); // topItemView.setActionView(deleteView, 0, Gravity.RIGHT); // } // // mListView.requestLayout(); // } mState = STATE_DELETE; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: //mNumberOfPointersDown--; if(mState == STATE_INSERT_AT_BOTTOM) { if(mIsInserting && mInsertListener != null) { mInsertListener.insert(mListView.getCount() - 1 - (mListView.getFooterViewsCount() + mListView.getHeaderViewsCount()), -1); mListView.invalidate(); } mActionFooter.reset(); mActionFooter.requestLayout(); mState = STATE_NORMAL; } else if (mState == STATE_INSERT_AT_TOP) { if(mIsInserting && mInsertListener != null) { mInsertListener.insert(-1, 0); mListView.invalidate(); } mActionHeader.reset(); mActionHeader.requestLayout(); mState = STATE_NORMAL; } else if (mState == STATE_INSERT_INBETWEEN) { if(mIsInserting && mInsertListener != null) { mInsertListener.insert(mTopItemPosition - mListView.getFooterViewsCount(), mBottomItemPosition - mListView.getFooterViewsCount()); mListView.invalidate(); } TouchEditableItemView topItemView = (TouchEditableItemView)mListView.getChildAt(mTopItemPosition - mListView.getFirstVisiblePosition()); if(topItemView != null) { topItemView.reset(); } mListView.invalidateViews(); mListView.setSelectionFromTop(mTopItemPosition, mOriginalTopItemY); mState = STATE_NORMAL; } else if (mState == STATE_DELETE) { mDeleteListener.delete(mTopItemPosition - mListView.getFooterViewsCount()); mListView.invalidate(); mState = STATE_NORMAL; } mTouchDataStore.clean(); // VOLGENDE SECTIENOG EENS BEKIJKEN !!! // SWITCHEN VAN TOP EN BOTTOM HIER KAN GEVOLGEN HEBBEN VOOR ANDERE VARIABELEN ZOALS mOriginalTopItemY if (mTouchDataStore.size() == 1) { mTopItemPosition = INVALID_POINTERID; } else if (mTouchDataStore.size() == 1) { mTopItemPosition = INVALID_POINTERID; mBottomItemPosition = INVALID_POINTERID; } // Log.i(TAG, "onTouchEvent ACTION_UP[PointerIndex:" + pointerIndex + "][PointerId:" + pointerId + "]"); break; case MotionEvent.ACTION_OUTSIDE: // Log.i(TAG, "onTouchEvent ACTION_OUTSIDE[PointerIndex:" + pointerIndex + "][PointerId:" + pointerId + "]"); break; } return true; } public boolean onInterceptTouchEvent(MotionEvent event) { return false; } public int getState() { return mState; } public int getMainDirection(int pointerId) { Log.i(TAG, "getMainDirection" + "[FirstPointerDownX:" + mTouchDataStore.get(pointerId /*mFirstPointerId*/).posXDown //mFirstPointerDownX + "][FirstPointerMoveX:" + mTouchDataStore.get(pointerId /*mFirstPointerId*/).getMoveX(pointerId) //mFirstPointerMoveX + "][FirstPointerDownY:" + mTouchDataStore.get(pointerId /*mFirstPointerId*/).posYDown //mFirstPointerDownY + "][FirstPointerMoveY:" + mTouchDataStore.get(pointerId /*mFirstPointerId*/).getMoveY(pointerId) //mFirstPointerMoveY + "]"); if (Math.abs(mTouchDataStore.get(pointerId /*mFirstPointerId*/).posXDown /*mFirstPointerDownX*/ - mTouchDataStore.get(pointerId /*mFirstPointerId*/).getMoveX(pointerId) /*mFirstPointerMoveX*/) /*> mMinimalDirectionalMovement &&*/ > Math.abs(mTouchDataStore.get(pointerId /*mFirstPointerId*/).posYDown /*mFirstPointerDownY*/ - mTouchDataStore.get(pointerId /*mFirstPointerId*/).getMoveY(pointerId) /*mFirstPointerMoveY*/) /*< mMaximalPerpendicularMovement*/) { Log.i(TAG, "getMainDirection: DIRECTION_HORIZONTAL"); return DIRECTION_HORIZONTAL; } if (Math.abs(mTouchDataStore.get(pointerId /*mFirstPointerId*/).posYDown/*mFirstPointerDownY*/ - mTouchDataStore.get(pointerId /*mFirstPointerId*/).getMoveY(pointerId) /*mFirstPointerMoveY*/) /*> mMinimalDirectionalMovement &&*/ > Math.abs(mTouchDataStore.get(pointerId /*mFirstPointerId*/).posXDown /*mFirstPointerDownX*/ - mTouchDataStore.get(pointerId /*mFirstPointerId*/).getMoveX(pointerId) /*mFirstPointerMoveX*/) /*< mMaximalPerpendicularMovement*/) { Log.i(TAG, "getMainDirection: DIRECTION_VERTICAL"); return DIRECTION_VERTICAL; } Log.i(TAG, "getMainDirection: DIRECTION_NONE"); return DIRECTION_NONE; } public int getCurrentTopItemY() { return mCurrentTopItemY; } public int calculateCurrentTopItemStretch(int position, View v) { //int topItemHeightPortion = 0; int newHeight = ViewGroup.LayoutParams.WRAP_CONTENT; int stretchHeight = 0; if(isScrollable()) { stretchHeight = Math.abs(mTouchDataStore.get(mPointerIdBottom).getMoveY(0) /*mLastBottomMoveY*/ - mTouchDataStore.get(mPointerIdTop).getMoveY(0) /*mLastTopMoveY*/); } else { stretchHeight = Math.abs(mTouchDataStore.get(mPointerIdBottom).posYOnPointerDown.get(mTouchDataStore.getPointerId(mTouchDataStore.size() - 1)) /*/*mBottomDownYOnSecondTouch*/ - mTouchDataStore.get(mPointerIdBottom).getMoveY(0) /*mLastBottomMoveY*/); } // Log.i(TAG, "getCurrentTopItemStretch[Indx:" + position + "][OriginalTopItemHeight:" + mOriginalTopItemHeight + "][TopItemHeightPortion:" + topItemHeightPortion + "][BottomItemHeightPortion" + bottomItemHeightPortion + "]"); if(position == mTopItemPosition && (stretchHeight > mOriginalTopItemHeight)) { // the touched item will stretch newHeight = mOriginalTopItemHeight + Math.min((int)(mElasticity * (stretchHeight - mOriginalTopItemHeight)), mMaxStretchHeight); // Log.i(TAG, "getCurrentTopItemStretch[Indx:" + position + "][StretchHeight:" + newHeight + "][MeasuredHeight" + v.getMeasuredHeight() + "]"); } else { // everything else remains as is newHeight = ViewGroup.LayoutParams.WRAP_CONTENT; // Log.i(TAG, "getCurrentTopItemStretch[Indx:" + position + "][SetHeight:WRAP_CONTENT]"); } return newHeight; } public int getOriginalTopItemHeight() { return mOriginalTopItemHeight; } public int getCurrentTopItemStretch() { return mCurrentTopItemStretch; } public void adjustItem(int position, View v, boolean withLogging) { ViewGroup.LayoutParams lp = v.getLayoutParams(); if(mState != STATE_INSERT_INBETWEEN) { // we have no offset, draw everything as normal // if(withLogging) // Log.i(TAG, "adjustItem[Indx:" + position + "][State.NOT:STATE_INSERT_INBETWEEN][SetHeight:WRAP_CONTENT]"); lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; return; } if(position == mTopItemPosition) { // the touched item will stretch lp.height = mCurrentTopItemStretch; } else { // everything else remains as is lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; } v.setLayoutParams(lp); } public boolean canLayout() { return mCanLayout; } public void setInsertViewFactory(TouchEditableListView.InsertViewFactory factory) { mInsertViewFactory = factory; } public void setOnInsertListener(TouchEditableListView.OnInsertListener insertListener) { mInsertListener = insertListener; } public void setDeleteViewFactory(TouchEditableListView.DeleteViewFactory factory) { mDeleteViewFactory = factory; } public void setOnDeleteListener(TouchEditableListView.OnDeleteListener deleteListener) { mDeleteListener = deleteListener; } private boolean isScrollable() { // if we cannot show all the items in the arrayadapter at once // or the last item is beyond the bottom of the listview mCanLayout = false; // Log.i(TAG, "MustCompensateForTop[NormalizedCount:" + (mListView.getCount() - (mListView.getHeaderViewsCount() + mListView.getFooterViewsCount())) + "]" // + "[ChildCount:" + mListView.getChildCount() + "]" // + "[Bottom:" + mListView.getChildAt(mListView.getChildCount()-1).getBottom() + "]" // + "[Height:" + mListView.getHeight() + "]" // ); boolean result = (mListView.getCount() - (mListView.getHeaderViewsCount() + mListView.getFooterViewsCount()) > mListView.getChildCount() || (mListView.getChildCount() > 0 && Math.abs(mListView.getChildAt(mListView.getChildCount()-1).getBottom() - mListView.getHeight()) > 5 )); mCanLayout = true; return result; } // private void TestSingleTouchIsOnTop(int currentTouchPosition, int eventY) { // // mTopItemPosition = currentTouchPosition; // mTopDownY = eventY; // mBottomItemPosition = mTopItemPosition + 1; // mBottomDownY = mTopDownY + 30; // // mLastTopMoveY = mTopDownY; // mLastBottomMoveY = mBottomDownY; // // mState = STATE_INSERT_INBETWEEN; // // } // // private void TestSingleTouchIsOnBottom(int currentTouchPosition, int eventY) { // // mBottomItemPosition = currentTouchPosition; // mBottomDownY = eventY; // mTopItemPosition = mBottomItemPosition - 1; // mTopDownY = mBottomDownY - 30; // // mLastTopMoveY = mTopDownY; // mLastBottomMoveY = mBottomDownY; // // mState = STATE_INSERT_INBETWEEN; // // } private TouchEditableListView mListView; public static int STATE_NORMAL = 0; public static int STATE_UNSUPPORTED = 1; public static int STATE_INSERT_AT_TOP = 2; public static int STATE_INSERT_AT_BOTTOM = 3; public static int STATE_INSERT_INBETWEEN = 4; public static int STATE_DELETE = 5; private int mState = STATE_NORMAL; public static int DIRECTION_NONE = 0; public static int DIRECTION_HORIZONTAL = 1; public static int DIRECTION_VERTICAL = 2; private int mInitialMainDirection = DIRECTION_NONE; // private int mMinimalDirectionalMovement = 20; // private int mMaximalPerpendicularMovement = 10; private TouchDataStore mTouchDataStore = new TouchDataStore(); //private int mNumberOfPointersDown = 0; //private int mFirstPointerId = -1; //private int mFirstPointerDownX; //private int mFirstPointerDownY; //private int mFirstPointerMoveX; //private int mFirstPointerMoveY; private boolean mIsInserting = false; //private int mTopDownYOnSecondTouch; //private int mBottomDownYOnSecondTouch; //private int mLastTopMoveY; //private int mCurrentTopMoveY = Integer.MAX_VALUE; //private int mPreviousTopMoveY = Integer.MAX_VALUE; //private int mLastBottomMoveY; private int mPointerIdTop = -1; private int mPointerIdBottom = -1; private int mInsertAtYStart = 0; private int mOriginalTopItemY = 0; private int mCurrentTopItemY = 0; private int mOriginalTopItemHeight; private int mCurrentTopItemStretch = ViewGroup.LayoutParams.WRAP_CONTENT; private static int INVALID_POINTERID = -1; private int mTopItemPosition = INVALID_POINTERID; private int mBottomItemPosition = INVALID_POINTERID; private TouchEditableActionView mActionHeader; private TouchEditableActionView mActionFooter; private int mInitialFooterTop = 0; private int mPublishedY = 0; private boolean mCanLayout = true; private double mElasticity = 0.5; // must be less than 1.0 private double mInsertStretchFactor = 1.25; private double mMaxStretchFactor = 1.5; private int mMaxStretchHeight = 180; private TouchEditableListView.InsertViewFactory mInsertViewFactory; private TouchEditableListView.OnInsertListener mInsertListener; private TouchEditableListView.DeleteViewFactory mDeleteViewFactory; private TouchEditableListView.OnDeleteListener mDeleteListener; }