true
to enable list
- * item sorting.
- */
- public void setSortEnabled(boolean enabled) {
- mSortEnabled = enabled;
- }
-
- public boolean isSortEnabled() {
- return mSortEnabled;
- }
-
- /**
- * One of {@link CLICK_REMOVE}, {@link FLING_RIGHT_REMOVE},
- * {@link FLING_LEFT_REMOVE},
- * {@link SLIDE_RIGHT_REMOVE}, or {@link SLIDE_LEFT_REMOVE}.
- */
- public void setRemoveMode(int mode) {
- mRemoveMode = mode;
- }
-
- public int getRemoveMode() {
- return mRemoveMode;
- }
-
- /**
- * Enable/Disable item removal without affecting remove mode.
- */
- public void setRemoveEnabled(boolean enabled) {
- mRemoveEnabled = enabled;
- }
-
- public boolean isRemoveEnabled() {
- return mRemoveEnabled;
- }
-
- /**
- * Set the resource id for the View that represents the drag
- * handle in a list item.
- *
- * @param id An android resource id.
- */
- public void setDragHandleId(int id) {
- mDragHandleId = id;
- }
-
- /**
- * Set the resource id for the View that represents the fling
- * handle in a list item.
- *
- * @param id An android resource id.
- */
- public void setFlingHandleId(int id) {
- mFlingHandleId = id;
- }
-
- /**
- * Set the resource id for the View that represents click
- * removal button.
- *
- * @param id An android resource id.
- */
- public void setClickRemoveId(int id) {
- mClickRemoveId = id;
- }
-
- /**
- * Sets flags to restrict certain motions of the floating View
- * based on DragSortController settings (such as remove mode).
- * Starts the drag on the DragSortListView.
- *
- * @param position The list item position (includes headers).
- * @param deltaX Touch x-coord minus left edge of floating View.
- * @param deltaY Touch y-coord minus top edge of floating View.
- *
- * @return True if drag started, false otherwise.
- */
- public boolean startDrag(int position, int deltaX, int deltaY) {
-
- int dragFlags = 0;
- if (mSortEnabled && !mIsRemoving) {
- dragFlags |= DragSortListView.DRAG_POS_Y | DragSortListView.DRAG_NEG_Y;
- }
- if (mRemoveEnabled && mIsRemoving) {
- dragFlags |= DragSortListView.DRAG_POS_X;
- dragFlags |= DragSortListView.DRAG_NEG_X;
- }
-
- mDragging = mDslv.startDrag(position - mDslv.getHeaderViewsCount(), dragFlags, deltaX,
- deltaY);
- return mDragging;
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- if (!mDslv.isDragEnabled() || mDslv.listViewIntercepted()) {
- return false;
- }
-
- mDetector.onTouchEvent(ev);
- if (mRemoveEnabled && mDragging && mRemoveMode == FLING_REMOVE) {
- mFlingRemoveDetector.onTouchEvent(ev);
- }
-
- int action = ev.getAction() & MotionEvent.ACTION_MASK;
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mCurrX = (int) ev.getX();
- mCurrY = (int) ev.getY();
- break;
- case MotionEvent.ACTION_UP:
- if (mRemoveEnabled && mIsRemoving) {
- int x = mPositionX >= 0 ? mPositionX : -mPositionX;
- int removePoint = mDslv.getWidth() / 2;
- if (x > removePoint) {
- mDslv.stopDragWithVelocity(true, 0);
- }
- }
- case MotionEvent.ACTION_CANCEL:
- mIsRemoving = false;
- mDragging = false;
- break;
- }
-
- return false;
- }
-
- /**
- * Overrides to provide fading when slide removal is enabled.
- */
- @Override
- public void onDragFloatView(View floatView, Point position, Point touch) {
-
- if (mRemoveEnabled && mIsRemoving) {
- mPositionX = position.x;
- }
- }
-
- /**
- * Get the position to start dragging based on the ACTION_DOWN
- * MotionEvent. This function simply calls
- * {@link #dragHandleHitPosition(MotionEvent)}. Override
- * to change drag handle behavior;
- * this function is called internally when an ACTION_DOWN
- * event is detected.
- *
- * @param ev The ACTION_DOWN MotionEvent.
- *
- * @return The list position to drag if a drag-init gesture is
- * detected; MISS if unsuccessful.
- */
- public int startDragPosition(MotionEvent ev) {
- return dragHandleHitPosition(ev);
- }
-
- public int startFlingPosition(MotionEvent ev) {
- return mRemoveMode == FLING_REMOVE ? flingHandleHitPosition(ev) : MISS;
- }
-
- /**
- * Checks for the touch of an item's drag handle (specified by
- * {@link #setDragHandleId(int)}), and returns that item's position
- * if a drag handle touch was detected.
- *
- * @param ev The ACTION_DOWN MotionEvent.
-
- * @return The list position of the item whose drag handle was
- * touched; MISS if unsuccessful.
- */
- public int dragHandleHitPosition(MotionEvent ev) {
- return viewIdHitPosition(ev, mDragHandleId);
- }
-
- public int flingHandleHitPosition(MotionEvent ev) {
- return viewIdHitPosition(ev, mFlingHandleId);
- }
-
- public int viewIdHitPosition(MotionEvent ev, int id) {
- final int x = (int) ev.getX();
- final int y = (int) ev.getY();
-
- int touchPos = mDslv.pointToPosition(x, y); // includes headers/footers
-
- final int numHeaders = mDslv.getHeaderViewsCount();
- final int numFooters = mDslv.getFooterViewsCount();
- final int count = mDslv.getCount();
-
- // We're only interested if the touch was on an
- // item that's not a header or footer.
- if (touchPos != AdapterView.INVALID_POSITION && touchPos >= numHeaders
- && touchPos < (count - numFooters)) {
- final View item = mDslv.getChildAt(touchPos - mDslv.getFirstVisiblePosition());
- final int rawX = (int) ev.getRawX();
- final int rawY = (int) ev.getRawY();
-
- View dragBox = id == 0 ? item : (View) item.findViewById(id);
- if (dragBox != null) {
- dragBox.getLocationOnScreen(mTempLoc);
-
- if (rawX > mTempLoc[0] && rawY > mTempLoc[1] &&
- rawX < mTempLoc[0] + dragBox.getWidth() &&
- rawY < mTempLoc[1] + dragBox.getHeight()) {
-
- mItemX = item.getLeft();
- mItemY = item.getTop();
-
- return touchPos;
- }
- }
- }
-
- return MISS;
- }
-
- @Override
- public boolean onDown(MotionEvent ev) {
- if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) {
- mClickRemoveHitPos = viewIdHitPosition(ev, mClickRemoveId);
- }
-
- mHitPos = startDragPosition(ev);
- if (mHitPos != MISS && mDragInitMode == ON_DOWN) {
- startDrag(mHitPos, (int) ev.getX() - mItemX, (int) ev.getY() - mItemY);
- }
-
- mIsRemoving = false;
- mCanDrag = true;
- mPositionX = 0;
- mFlingHitPos = startFlingPosition(ev);
-
- return true;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
-
- final int x1 = (int) e1.getX();
- final int y1 = (int) e1.getY();
- final int x2 = (int) e2.getX();
- final int y2 = (int) e2.getY();
- final int deltaX = x2 - mItemX;
- final int deltaY = y2 - mItemY;
-
- if (mCanDrag && !mDragging && (mHitPos != MISS || mFlingHitPos != MISS)) {
- if (mHitPos != MISS) {
- if (mDragInitMode == ON_DRAG && Math.abs(y2 - y1) > mTouchSlop && mSortEnabled) {
- startDrag(mHitPos, deltaX, deltaY);
- }
- else if (mDragInitMode != ON_DOWN && Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled)
- {
- mIsRemoving = true;
- startDrag(mFlingHitPos, deltaX, deltaY);
- }
- } else if (mFlingHitPos != MISS) {
- if (Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) {
- mIsRemoving = true;
- startDrag(mFlingHitPos, deltaX, deltaY);
- } else if (Math.abs(y2 - y1) > mTouchSlop) {
- mCanDrag = false; // if started to scroll the list then
- // don't allow sorting nor fling-removing
- }
- }
- }
- // return whatever
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- if (mHitPos != MISS && mDragInitMode == ON_LONG_PRESS) {
- mDslv.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- startDrag(mHitPos, mCurrX - mItemX, mCurrY - mItemY);
- }
- }
-
- // complete the OnGestureListener interface
- @Override
- public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- return false;
- }
-
- // complete the OnGestureListener interface
- @Override
- public boolean onSingleTapUp(MotionEvent ev) {
- if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) {
- if (mClickRemoveHitPos != MISS) {
- mDslv.removeItem(mClickRemoveHitPos - mDslv.getHeaderViewsCount());
- }
- }
- return true;
- }
-
- // complete the OnGestureListener interface
- @Override
- public void onShowPress(MotionEvent ev) {
- // do nothing
- }
-
- private GestureDetector.OnGestureListener mFlingRemoveListener =
- new GestureDetector.SimpleOnGestureListener() {
- @Override
- public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- if (mRemoveEnabled && mIsRemoving) {
- int w = mDslv.getWidth();
- int minPos = w / 5;
- if (velocityX > mFlingSpeed) {
- if (mPositionX > -minPos) {
- mDslv.stopDragWithVelocity(true, velocityX);
- }
- } else if (velocityX < -mFlingSpeed) {
- if (mPositionX < minPos) {
- mDslv.stopDragWithVelocity(true, velocityX);
- }
- }
- mIsRemoving = false;
- }
- return false;
- }
- };
-
-}
diff --git a/core/library/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java b/core/library/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java
deleted file mode 100644
index 9e14059b..00000000
--- a/core/library/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package com.mobeta.android.dslv;
-
-import java.util.ArrayList;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.util.SparseIntArray;
-import android.view.View;
-import android.view.ViewGroup;
-import androidx.cursoradapter.widget.CursorAdapter;
-
-
-/**
- * A subclass of {@link android.widget.CursorAdapter} that provides
- * reordering of the elements in the Cursor based on completed
- * drag-sort operations. The reordering is a simple mapping of
- * list positions into Cursor positions (the Cursor is unchanged).
- * To persist changes made by drag-sorts, one can retrieve the
- * mapping with the {@link #getCursorPositions()} method, which
- * returns the reordered list of Cursor positions.
- *
- * An instance of this class is passed
- * to {@link DragSortListView#setAdapter(ListAdapter)} and, since
- * this class implements the {@link DragSortListView.DragSortListener}
- * interface, it is automatically set as the DragSortListener for
- * the DragSortListView instance.
- */
-public abstract class DragSortCursorAdapter extends CursorAdapter implements DragSortListView.DragSortListener {
-
- public static final int REMOVED = -1;
-
- /**
- * Key is ListView position, value is Cursor position
- */
- private SparseIntArray mListMapping = new SparseIntArray();
-
- private ArrayListadapter
, this method calls the appropriate
- * set*Listener method with adapter
as the argument.
- *
- * @param adapter The ListAdapter providing data to back
- * DragSortListView.
- *
- * @see android.widget.ListView#setAdapter(android.widget.ListAdapter)
- */
- @Override
- public void setAdapter(ListAdapter adapter) {
- if (adapter != null) {
- mAdapterWrapper = new AdapterWrapper(adapter);
- adapter.registerDataSetObserver(mObserver);
-
- if (adapter instanceof DropListener) {
- setDropListener((DropListener) adapter);
- }
- if (adapter instanceof DragListener) {
- setDragListener((DragListener) adapter);
- }
- if (adapter instanceof RemoveListener) {
- setRemoveListener((RemoveListener) adapter);
- }
- } else {
- mAdapterWrapper = null;
- }
-
- super.setAdapter(mAdapterWrapper);
- }
-
- /**
- * As opposed to {@link ListView#getAdapter()}, which returns
- * a heavily wrapped ListAdapter (DragSortListView wraps the
- * input ListAdapter {\emph and} ListView wraps the wrapped one).
- *
- * @return The ListAdapter set as the argument of {@link setAdapter()}
- */
- public ListAdapter getInputAdapter() {
- if (mAdapterWrapper == null) {
- return null;
- } else {
- return mAdapterWrapper.getAdapter();
- }
- }
-
- private class AdapterWrapper extends BaseAdapter {
- private ListAdapter mAdapter;
-
- public AdapterWrapper(ListAdapter adapter) {
- super();
- mAdapter = adapter;
-
- mAdapter.registerDataSetObserver(new DataSetObserver() {
- public void onChanged() {
- notifyDataSetChanged();
- }
-
- public void onInvalidated() {
- notifyDataSetInvalidated();
- }
- });
- }
-
- public ListAdapter getAdapter() {
- return mAdapter;
- }
-
- @Override
- public long getItemId(int position) {
- return mAdapter.getItemId(position);
- }
-
- @Override
- public Object getItem(int position) {
- return mAdapter.getItem(position);
- }
-
- @Override
- public int getCount() {
- return mAdapter.getCount();
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return mAdapter.areAllItemsEnabled();
- }
-
- @Override
- public boolean isEnabled(int position) {
- return mAdapter.isEnabled(position);
- }
-
- @Override
- public int getItemViewType(int position) {
- return mAdapter.getItemViewType(position);
- }
-
- @Override
- public int getViewTypeCount() {
- return mAdapter.getViewTypeCount();
- }
-
- @Override
- public boolean hasStableIds() {
- return mAdapter.hasStableIds();
- }
-
- @Override
- public boolean isEmpty() {
- return mAdapter.isEmpty();
- }
-
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- DragSortItemView v;
- View child;
- if (convertView != null) {
- v = (DragSortItemView) convertView;
- View oldChild = v.getChildAt(0);
-
- child = mAdapter.getView(position, oldChild, DragSortListView.this);
- if (child != oldChild) {
- // shouldn't get here if user is reusing convertViews
- // properly
- if (oldChild != null) {
- v.removeViewAt(0);
- }
- v.addView(child);
- }
- } else {
- child = mAdapter.getView(position, null, DragSortListView.this);
- if (child instanceof Checkable) {
- v = new DragSortItemViewCheckable(getContext());
- } else {
- v = new DragSortItemView(getContext());
- }
- v.setLayoutParams(new AbsListView.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- v.addView(child);
- }
-
- // Set the correct item height given drag state; passed
- // View needs to be measured if measurement is required.
- adjustItem(position + getHeaderViewsCount(), v, true);
-
- return v;
- }
- }
-
- private void drawDivider(int expPosition, Canvas canvas) {
-
- final Drawable divider = getDivider();
- final int dividerHeight = getDividerHeight();
-
- if (divider != null && dividerHeight != 0) {
- final ViewGroup expItem = (ViewGroup) getChildAt(expPosition
- - getFirstVisiblePosition());
- if (expItem != null) {
- final int l = getPaddingLeft();
- final int r = getWidth() - getPaddingRight();
- final int t;
- final int b;
-
- final int childHeight = expItem.getChildAt(0).getHeight();
-
- if (expPosition > mSrcPos) {
- t = expItem.getTop() + childHeight;
- b = t + dividerHeight;
- } else {
- b = expItem.getBottom() - childHeight;
- t = b - dividerHeight;
- }
- // Have to clip to support ColorDrawable on <= Gingerbread
- canvas.save();
- canvas.clipRect(l, t, r, b);
- divider.setBounds(l, t, r, b);
- divider.draw(canvas);
- canvas.restore();
- }
- }
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
-
- if (mDragState != IDLE) {
- // draw the divider over the expanded item
- if (mFirstExpPos != mSrcPos) {
- drawDivider(mFirstExpPos, canvas);
- }
- if (mSecondExpPos != mFirstExpPos && mSecondExpPos != mSrcPos) {
- drawDivider(mSecondExpPos, canvas);
- }
- }
-
- if (mFloatView != null) {
- // draw the float view over everything
- final int w = mFloatView.getWidth();
- final int h = mFloatView.getHeight();
-
- int x = mFloatLoc.x;
-
- int width = getWidth();
- if (x < 0)
- x = -x;
- float alphaMod;
- if (x < width) {
- alphaMod = ((float) (width - x)) / ((float) width);
- alphaMod *= alphaMod;
- } else {
- alphaMod = 0;
- }
-
- final int alpha = (int) (255f * mCurrFloatAlpha * alphaMod);
-
- canvas.save();
- canvas.translate(mFloatLoc.x, mFloatLoc.y);
- canvas.clipRect(0, 0, w, h);
-
- canvas.saveLayerAlpha(0, 0, w, h, alpha, Canvas.ALL_SAVE_FLAG);
- mFloatView.draw(canvas);
- canvas.restore();
- canvas.restore();
- }
- }
-
- private int getItemHeight(int position) {
- View v = getChildAt(position - getFirstVisiblePosition());
-
- if (v != null) {
- // item is onscreen, just get the height of the View
- return v.getHeight();
- } else {
- // item is offscreen. get child height and calculate
- // item height based on current shuffle state
- return calcItemHeight(position, getChildHeight(position));
- }
- }
-
- private void printPosData() {
- Timber.d("mSrcPos=%i mFirstExpPos=%i mSecondExpPos=%i", mSrcPos, mFirstExpPos, mSecondExpPos);
- }
-
- private class HeightCache {
-
- private SparseIntArray mMap;
- private ArrayListtrue
as the first argument.
- */
- public void cancelDrag() {
- if (mDragState == DRAGGING) {
- mDragScroller.stopScrolling(true);
- destroyFloatView();
- clearPositions();
- adjustAllItems();
-
- if (mInTouchEvent) {
- mDragState = STOPPED;
- } else {
- mDragState = IDLE;
- }
- }
- }
-
- private void clearPositions() {
- mSrcPos = -1;
- mFirstExpPos = -1;
- mSecondExpPos = -1;
- mFloatPos = -1;
- }
-
- private void dropFloatView() {
- // must set to avoid cancelDrag being called from the
- // DataSetObserver
- mDragState = DROPPING;
-
- if (mDropListener != null && mFloatPos >= 0 && mFloatPos < getCount()) {
- final int numHeaders = getHeaderViewsCount();
- mDropListener.drop(mSrcPos - numHeaders, mFloatPos - numHeaders);
- }
-
- destroyFloatView();
-
- adjustOnReorder();
- clearPositions();
- adjustAllItems();
-
- // now the drag is done
- if (mInTouchEvent) {
- mDragState = STOPPED;
- } else {
- mDragState = IDLE;
- }
- }
-
- private void doRemoveItem() {
- doRemoveItem(mSrcPos - getHeaderViewsCount());
- }
-
- /**
- * Removes dragged item from the list. Calls RemoveListener.
- */
- private void doRemoveItem(int which) {
- // must set to avoid cancelDrag being called from the
- // DataSetObserver
- mDragState = REMOVING;
-
- // end it
- if (mRemoveListener != null) {
- mRemoveListener.remove(which);
- }
-
- destroyFloatView();
-
- adjustOnReorder();
- clearPositions();
-
- // now the drag is done
- if (mInTouchEvent) {
- mDragState = STOPPED;
- } else {
- mDragState = IDLE;
- }
- }
-
- private void adjustOnReorder() {
- final int firstPos = getFirstVisiblePosition();
- if (mSrcPos < firstPos) {
- // collapsed src item is off screen;
- // adjust the scroll after item heights have been fixed
- View v = getChildAt(0);
- int top = 0;
- if (v != null) {
- top = v.getTop();
- }
- setSelectionFromTop(firstPos - 1, top - getPaddingTop());
- }
- }
-
- /**
- * Stop a drag in progress. Pass true
if you would
- * like to remove the dragged item from the list.
- *
- * @param remove Remove the dragged item from the list. Calls
- * a registered RemoveListener, if one exists. Otherwise, calls
- * the DropListener, if one exists.
- *
- * @return True if the stop was successful. False if there is
- * no floating View.
- */
- public boolean stopDrag(boolean remove) {
- mUseRemoveVelocity = false;
- return stopDrag(remove, 0);
- }
-
- public boolean stopDragWithVelocity(boolean remove, float velocityX) {
-
- mUseRemoveVelocity = true;
- return stopDrag(remove, velocityX);
- }
-
- public boolean stopDrag(boolean remove, float velocityX) {
- if (mFloatView != null) {
- mDragScroller.stopScrolling(true);
-
- if (remove) {
- removeItem(mSrcPos - getHeaderViewsCount(), velocityX);
- } else {
- if (mDropAnimator != null) {
- mDropAnimator.start();
- } else {
- dropFloatView();
- }
- }
-
- if (mTrackDragSort) {
- mDragSortTracker.stopTracking();
- }
-
- return true;
- } else {
- // stop failed
- return false;
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (mIgnoreTouchEvent) {
- mIgnoreTouchEvent = false;
- return false;
- }
-
- if (!mDragEnabled) {
- return super.onTouchEvent(ev);
- }
-
- boolean more = false;
-
- boolean lastCallWasIntercept = mLastCallWasIntercept;
- mLastCallWasIntercept = false;
-
- if (!lastCallWasIntercept) {
- saveTouchCoords(ev);
- }
-
- // if (mFloatView != null) {
- if (mDragState == DRAGGING) {
- onDragTouchEvent(ev);
- more = true; // give us more!
- } else {
- // what if float view is null b/c we dropped in middle
- // of drag touch event?
-
- // if (mDragState != STOPPED) {
- if (mDragState == IDLE) {
- if (super.onTouchEvent(ev)) {
- more = true;
- }
- }
-
- int action = ev.getAction() & MotionEvent.ACTION_MASK;
-
- switch (action) {
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- doActionUpOrCancel();
- break;
- default:
- if (more) {
- mCancelMethod = ON_TOUCH_EVENT;
- }
- }
- }
-
- return more;
- }
-
- private void doActionUpOrCancel() {
- mCancelMethod = NO_CANCEL;
- mInTouchEvent = false;
- if (mDragState == STOPPED) {
- mDragState = IDLE;
- }
- mCurrFloatAlpha = mFloatAlpha;
- mListViewIntercepted = false;
- mChildHeightCache.clear();
- }
-
- private void saveTouchCoords(MotionEvent ev) {
- int action = ev.getAction() & MotionEvent.ACTION_MASK;
- if (action != MotionEvent.ACTION_DOWN) {
- mLastX = mX;
- mLastY = mY;
- }
- mX = (int) ev.getX();
- mY = (int) ev.getY();
- if (action == MotionEvent.ACTION_DOWN) {
- mLastX = mX;
- mLastY = mY;
- }
- mOffsetX = (int) ev.getRawX() - mX;
- mOffsetY = (int) ev.getRawY() - mY;
- }
-
- public boolean listViewIntercepted() {
- return mListViewIntercepted;
- }
-
- private boolean mListViewIntercepted = false;
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (!mDragEnabled) {
- return super.onInterceptTouchEvent(ev);
- }
-
- saveTouchCoords(ev);
- mLastCallWasIntercept = true;
-
- int action = ev.getAction() & MotionEvent.ACTION_MASK;
-
- if (action == MotionEvent.ACTION_DOWN) {
- if (mDragState != IDLE) {
- // intercept and ignore
- mIgnoreTouchEvent = true;
- return true;
- }
- mInTouchEvent = true;
- }
-
- boolean intercept = false;
-
- // the following deals with calls to super.onInterceptTouchEvent
- if (mFloatView != null) {
- // super's touch event canceled in startDrag
- intercept = true;
- } else {
- if (super.onInterceptTouchEvent(ev)) {
- mListViewIntercepted = true;
- intercept = true;
- }
-
- switch (action) {
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- doActionUpOrCancel();
- break;
- default:
- if (intercept) {
- mCancelMethod = ON_TOUCH_EVENT;
- } else {
- mCancelMethod = ON_INTERCEPT_TOUCH_EVENT;
- }
- }
- }
-
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- mInTouchEvent = false;
- }
-
- return intercept;
- }
-
- /**
- * Set the width of each drag scroll region by specifying
- * a fraction of the ListView height.
- *
- * @param heightFraction Fraction of ListView height. Capped at
- * 0.5f.
- *
- */
- public void setDragScrollStart(float heightFraction) {
- setDragScrollStarts(heightFraction, heightFraction);
- }
-
- /**
- * Set the width of each drag scroll region by specifying
- * a fraction of the ListView height.
- *
- * @param upperFrac Fraction of ListView height for up-scroll bound.
- * Capped at 0.5f.
- * @param lowerFrac Fraction of ListView height for down-scroll bound.
- * Capped at 0.5f.
- *
- */
- public void setDragScrollStarts(float upperFrac, float lowerFrac) {
- if (lowerFrac > 0.5f) {
- mDragDownScrollStartFrac = 0.5f;
- } else {
- mDragDownScrollStartFrac = lowerFrac;
- }
-
- if (upperFrac > 0.5f) {
- mDragUpScrollStartFrac = 0.5f;
- } else {
- mDragUpScrollStartFrac = upperFrac;
- }
-
- if (getHeight() != 0) {
- updateScrollStarts();
- }
- }
-
- private void continueDrag(int x, int y) {
-
- // proposed position
- mFloatLoc.x = x - mDragDeltaX;
- mFloatLoc.y = y - mDragDeltaY;
-
- doDragFloatView(true);
-
- int minY = Math.min(y, mFloatViewMid + mFloatViewHeightHalf);
- int maxY = Math.max(y, mFloatViewMid - mFloatViewHeightHalf);
-
- // get the current scroll direction
- int currentScrollDir = mDragScroller.getScrollDir();
-
- if (minY > mLastY && minY > mDownScrollStartY && currentScrollDir != DragScroller.DOWN) {
- // dragged down, it is below the down scroll start and it is not
- // scrolling up
-
- if (currentScrollDir != DragScroller.STOP) {
- // moved directly from up scroll to down scroll
- mDragScroller.stopScrolling(true);
- }
-
- // start scrolling down
- mDragScroller.startScrolling(DragScroller.DOWN);
- } else if (maxY < mLastY && maxY < mUpScrollStartY && currentScrollDir != DragScroller.UP) {
- // dragged up, it is above the up scroll start and it is not
- // scrolling up
-
- if (currentScrollDir != DragScroller.STOP) {
- // moved directly from down scroll to up scroll
- mDragScroller.stopScrolling(true);
- }
-
- // start scrolling up
- mDragScroller.startScrolling(DragScroller.UP);
- }
- else if (maxY >= mUpScrollStartY && minY <= mDownScrollStartY
- && mDragScroller.isScrolling()) {
- // not in the upper nor in the lower drag-scroll regions but it is
- // still scrolling
-
- mDragScroller.stopScrolling(true);
- }
- }
-
- private void updateScrollStarts() {
- final int padTop = getPaddingTop();
- final int listHeight = getHeight() - padTop - getPaddingBottom();
- float heightF = (float) listHeight;
-
- mUpScrollStartYF = padTop + mDragUpScrollStartFrac * heightF;
- mDownScrollStartYF = padTop + (1.0f - mDragDownScrollStartFrac) * heightF;
-
- mUpScrollStartY = (int) mUpScrollStartYF;
- mDownScrollStartY = (int) mDownScrollStartYF;
-
- mDragUpScrollHeight = mUpScrollStartYF - padTop;
- mDragDownScrollHeight = padTop + listHeight - mDownScrollStartYF;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- updateScrollStarts();
- }
-
- private void adjustAllItems() {
- final int first = getFirstVisiblePosition();
- final int last = getLastVisiblePosition();
-
- int begin = Math.max(0, getHeaderViewsCount() - first);
- int end = Math.min(last - first, getCount() - 1 - getFooterViewsCount() - first);
-
- for (int i = begin; i <= end; ++i) {
- View v = getChildAt(i);
- if (v != null) {
- adjustItem(first + i, v, false);
- }
- }
- }
-
- private void adjustItem(int position) {
- View v = getChildAt(position - getFirstVisiblePosition());
-
- if (v != null) {
- adjustItem(position, v, false);
- }
- }
-
- /**
- * Sets layout param height, gravity, and visibility on
- * wrapped item.
- */
- private void adjustItem(int position, View v, boolean invalidChildHeight) {
-
- // Adjust item height
- ViewGroup.LayoutParams lp = v.getLayoutParams();
- int height;
- if (position != mSrcPos && position != mFirstExpPos && position != mSecondExpPos) {
- height = ViewGroup.LayoutParams.WRAP_CONTENT;
- } else {
- height = calcItemHeight(position, v, invalidChildHeight);
- }
-
- if (height != lp.height) {
- lp.height = height;
- v.setLayoutParams(lp);
- }
-
- // Adjust item gravity
- if (position == mFirstExpPos || position == mSecondExpPos) {
- if (position < mSrcPos) {
- ((DragSortItemView) v).setGravity(Gravity.BOTTOM);
- } else if (position > mSrcPos) {
- ((DragSortItemView) v).setGravity(Gravity.TOP);
- }
- }
-
- // Finally adjust item visibility
-
- int oldVis = v.getVisibility();
- int vis = View.VISIBLE;
-
- if (position == mSrcPos && mFloatView != null) {
- vis = View.INVISIBLE;
- }
-
- if (vis != oldVis) {
- v.setVisibility(vis);
- }
- }
-
- private int getChildHeight(int position) {
- if (position == mSrcPos) {
- return 0;
- }
-
- View v = getChildAt(position - getFirstVisiblePosition());
-
- if (v != null) {
- // item is onscreen, therefore child height is valid,
- // hence the "true"
- return getChildHeight(position, v, false);
- } else {
- // item is offscreen
- // first check cache for child height at this position
- int childHeight = mChildHeightCache.get(position);
- if (childHeight != -1) {
- return childHeight;
- }
-
- final ListAdapter adapter = getAdapter();
- int type = adapter.getItemViewType(position);
-
- // There might be a better place for checking for the following
- final int typeCount = adapter.getViewTypeCount();
- if (typeCount != mSampleViewTypes.length) {
- mSampleViewTypes = new View[typeCount];
- }
-
- if (type >= 0) {
- if (mSampleViewTypes[type] == null) {
- v = adapter.getView(position, null, this);
- mSampleViewTypes[type] = v;
- } else {
- v = adapter.getView(position, mSampleViewTypes[type], this);
- }
- } else {
- // type is HEADER_OR_FOOTER or IGNORE
- v = adapter.getView(position, null, this);
- }
-
- // current child height is invalid, hence "true" below
- childHeight = getChildHeight(position, v, true);
-
- // cache it because this could have been expensive
- mChildHeightCache.add(position, childHeight);
-
- return childHeight;
- }
- }
-
- private int getChildHeight(int position, View item, boolean invalidChildHeight) {
- if (position == mSrcPos) {
- return 0;
- }
-
- View child;
- if (position < getHeaderViewsCount() || position >= getCount() - getFooterViewsCount()) {
- child = item;
- } else {
- child = ((ViewGroup) item).getChildAt(0);
- }
-
- ViewGroup.LayoutParams lp = child.getLayoutParams();
-
- if (lp != null) {
- if (lp.height > 0) {
- return lp.height;
- }
- }
-
- int childHeight = child.getHeight();
-
- if (childHeight == 0 || invalidChildHeight) {
- measureItem(child);
- childHeight = child.getMeasuredHeight();
- }
-
- return childHeight;
- }
-
- private int calcItemHeight(int position, View item, boolean invalidChildHeight) {
- return calcItemHeight(position, getChildHeight(position, item, invalidChildHeight));
- }
-
- private int calcItemHeight(int position, int childHeight) {
-
- int divHeight = getDividerHeight();
-
- boolean isSliding = mAnimate && mFirstExpPos != mSecondExpPos;
- int maxNonSrcBlankHeight = mFloatViewHeight - mItemHeightCollapsed;
- int slideHeight = (int) (mSlideFrac * maxNonSrcBlankHeight);
-
- int height;
-
- if (position == mSrcPos) {
- if (mSrcPos == mFirstExpPos) {
- if (isSliding) {
- height = slideHeight + mItemHeightCollapsed;
- } else {
- height = mFloatViewHeight;
- }
- } else if (mSrcPos == mSecondExpPos) {
- // if gets here, we know an item is sliding
- height = mFloatViewHeight - slideHeight;
- } else {
- height = mItemHeightCollapsed;
- }
- } else if (position == mFirstExpPos) {
- if (isSliding) {
- height = childHeight + slideHeight;
- } else {
- height = childHeight + maxNonSrcBlankHeight;
- }
- } else if (position == mSecondExpPos) {
- // we know an item is sliding (b/c 2ndPos != 1stPos)
- height = childHeight + maxNonSrcBlankHeight - slideHeight;
- } else {
- height = childHeight;
- }
-
- return height;
- }
-
- @Override
- public void requestLayout() {
- if (!mBlockLayoutRequests) {
- super.requestLayout();
- }
- }
-
- private int adjustScroll(int movePos, View moveItem, int oldFirstExpPos, int oldSecondExpPos) {
- int adjust = 0;
-
- final int childHeight = getChildHeight(movePos);
-
- int moveHeightBefore = moveItem.getHeight();
- int moveHeightAfter = calcItemHeight(movePos, childHeight);
-
- int moveBlankBefore = moveHeightBefore;
- int moveBlankAfter = moveHeightAfter;
- if (movePos != mSrcPos) {
- moveBlankBefore -= childHeight;
- moveBlankAfter -= childHeight;
- }
-
- int maxBlank = mFloatViewHeight;
- if (mSrcPos != mFirstExpPos && mSrcPos != mSecondExpPos) {
- maxBlank -= mItemHeightCollapsed;
- }
-
- if (movePos <= oldFirstExpPos) {
- if (movePos > mFirstExpPos) {
- adjust += maxBlank - moveBlankAfter;
- }
- } else if (movePos == oldSecondExpPos) {
- if (movePos <= mFirstExpPos) {
- adjust += moveBlankBefore - maxBlank;
- } else if (movePos == mSecondExpPos) {
- adjust += moveHeightBefore - moveHeightAfter;
- } else {
- adjust += moveBlankBefore;
- }
- } else {
- if (movePos <= mFirstExpPos) {
- adjust -= maxBlank;
- } else if (movePos == mSecondExpPos) {
- adjust -= moveBlankAfter;
- }
- }
-
- return adjust;
- }
-
- private void measureItem(View item) {
- ViewGroup.LayoutParams lp = item.getLayoutParams();
- if (lp == null) {
- lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- item.setLayoutParams(lp);
- }
- int wspec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getListPaddingLeft()
- + getListPaddingRight(), lp.width);
- int hspec;
- if (lp.height > 0) {
- hspec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
- } else {
- hspec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- }
- item.measure(wspec, hspec);
- }
-
- private void measureFloatView() {
- if (mFloatView != null) {
- measureItem(mFloatView);
- mFloatViewHeight = mFloatView.getMeasuredHeight();
- mFloatViewHeightHalf = mFloatViewHeight / 2;
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mFloatView != null) {
- if (mFloatView.isLayoutRequested()) {
- measureFloatView();
- }
- mFloatViewOnMeasured = true; // set to false after layout
- }
- mWidthMeasureSpec = widthMeasureSpec;
- }
-
- @Override
- protected void layoutChildren() {
- super.layoutChildren();
-
- if (mFloatView != null) {
- if (mFloatView.isLayoutRequested() && !mFloatViewOnMeasured) {
- // Have to measure here when usual android measure
- // pass is skipped. This happens during a drag-sort
- // when layoutChildren is called directly.
- measureFloatView();
- }
- mFloatView.layout(0, 0, mFloatView.getMeasuredWidth(), mFloatView.getMeasuredHeight());
- mFloatViewOnMeasured = false;
- }
- }
-
- protected boolean onDragTouchEvent(MotionEvent ev) {
- // we are in a drag
- int action = ev.getAction() & MotionEvent.ACTION_MASK;
-
- switch (ev.getAction() & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_CANCEL:
- if (mDragState == DRAGGING) {
- cancelDrag();
- }
- doActionUpOrCancel();
- break;
- case MotionEvent.ACTION_UP:
- if (mDragState == DRAGGING) {
- stopDrag(false);
- }
- doActionUpOrCancel();
- break;
- case MotionEvent.ACTION_MOVE:
- continueDrag((int) ev.getX(), (int) ev.getY());
- break;
- }
-
- return true;
- }
-
- private boolean mFloatViewInvalidated = false;
-
- private void invalidateFloatView() {
- mFloatViewInvalidated = true;
- }
-
- /**
- * Start a drag of item at position
using the
- * registered FloatViewManager. Calls through
- * to {@link #startDrag(int,View,int,int,int)} after obtaining
- * the floating View from the FloatViewManager.
- *
- * @param position Item to drag.
- * @param dragFlags Flags that restrict some movements of the
- * floating View. For example, set dragFlags |=
- * ~{@link #DRAG_NEG_X}
to allow dragging the floating
- * View in all directions except off the screen to the left.
- * @param deltaX Offset in x of the touch coordinate from the
- * left edge of the floating View (i.e. touch-x minus float View
- * left).
- * @param deltaY Offset in y of the touch coordinate from the
- * top edge of the floating View (i.e. touch-y minus float View
- * top).
- *
- * @return True if the drag was started, false otherwise. This
- * startDrag
will fail if we are not currently in
- * a touch event, there is no registered FloatViewManager,
- * or the FloatViewManager returns a null View.
- */
- public boolean startDrag(int position, int dragFlags, int deltaX, int deltaY) {
- if (!mInTouchEvent || mFloatViewManager == null) {
- return false;
- }
-
- View v = mFloatViewManager.onCreateFloatView(position);
-
- if (v == null) {
- return false;
- } else {
- return startDrag(position, v, dragFlags, deltaX, deltaY);
- }
-
- }
-
- /**
- * Start a drag of item at position
without using
- * a FloatViewManager.
- *
- * @param position Item to drag.
- * @param floatView Floating View.
- * @param dragFlags Flags that restrict some movements of the
- * floating View. For example, set dragFlags |=
- * ~{@link #DRAG_NEG_X}
to allow dragging the floating
- * View in all directions except off the screen to the left.
- * @param deltaX Offset in x of the touch coordinate from the
- * left edge of the floating View (i.e. touch-x minus float View
- * left).
- * @param deltaY Offset in y of the touch coordinate from the
- * top edge of the floating View (i.e. touch-y minus float View
- * top).
- *
- * @return True if the drag was started, false otherwise. This
- * startDrag
will fail if we are not currently in
- * a touch event, floatView
is null, or there is
- * a drag in progress.
- */
- public boolean startDrag(int position, View floatView, int dragFlags, int deltaX, int deltaY) {
- if (mDragState != IDLE || !mInTouchEvent || mFloatView != null || floatView == null
- || !mDragEnabled) {
- return false;
- }
-
- if (getParent() != null) {
- getParent().requestDisallowInterceptTouchEvent(true);
- }
-
- int pos = position + getHeaderViewsCount();
- mFirstExpPos = pos;
- mSecondExpPos = pos;
- mSrcPos = pos;
- mFloatPos = pos;
-
- // mDragState = dragType;
- mDragState = DRAGGING;
- mDragFlags = 0;
- mDragFlags |= dragFlags;
-
- mFloatView = floatView;
- measureFloatView(); // sets mFloatViewHeight
-
- mDragDeltaX = deltaX;
- mDragDeltaY = deltaY;
- mDragStartY = mY;
-
- // updateFloatView(mX - mDragDeltaX, mY - mDragDeltaY);
- mFloatLoc.x = mX - mDragDeltaX;
- mFloatLoc.y = mY - mDragDeltaY;
-
- // set src item invisible
- final View srcItem = getChildAt(mSrcPos - getFirstVisiblePosition());
-
- if (srcItem != null) {
- srcItem.setVisibility(View.INVISIBLE);
- }
-
- if (mTrackDragSort) {
- mDragSortTracker.startTracking();
- }
-
- // once float view is created, events are no longer passed
- // to ListView
- switch (mCancelMethod) {
- case ON_TOUCH_EVENT:
- super.onTouchEvent(mCancelEvent);
- break;
- case ON_INTERCEPT_TOUCH_EVENT:
- super.onInterceptTouchEvent(mCancelEvent);
- break;
- }
-
- requestLayout();
-
- if (mLiftAnimator != null) {
- mLiftAnimator.start();
- }
-
- return true;
- }
-
- private void doDragFloatView(boolean forceInvalidate) {
- int movePos = getFirstVisiblePosition() + getChildCount() / 2;
- View moveItem = getChildAt(getChildCount() / 2);
-
- if (moveItem == null) {
- return;
- }
-
- doDragFloatView(movePos, moveItem, forceInvalidate);
- }
-
- private void doDragFloatView(int movePos, View moveItem, boolean forceInvalidate) {
- mBlockLayoutRequests = true;
-
- updateFloatView();
-
- int oldFirstExpPos = mFirstExpPos;
- int oldSecondExpPos = mSecondExpPos;
-
- boolean updated = updatePositions();
-
- if (updated) {
- adjustAllItems();
- int scroll = adjustScroll(movePos, moveItem, oldFirstExpPos, oldSecondExpPos);
-
- setSelectionFromTop(movePos, moveItem.getTop() + scroll - getPaddingTop());
- layoutChildren();
- }
-
- if (updated || forceInvalidate) {
- invalidate();
- }
-
- mBlockLayoutRequests = false;
- }
-
- /**
- * Sets float View location based on suggested values and
- * constraints set in mDragFlags.
- */
- private void updateFloatView() {
-
- if (mFloatViewManager != null) {
- mTouchLoc.set(mX, mY);
- mFloatViewManager.onDragFloatView(mFloatView, mFloatLoc, mTouchLoc);
- }
-
- final int floatX = mFloatLoc.x;
- final int floatY = mFloatLoc.y;
-
- // restrict x motion
- int padLeft = getPaddingLeft();
- if ((mDragFlags & DRAG_POS_X) == 0 && floatX > padLeft) {
- mFloatLoc.x = padLeft;
- } else if ((mDragFlags & DRAG_NEG_X) == 0 && floatX < padLeft) {
- mFloatLoc.x = padLeft;
- }
-
- // keep floating view from going past bottom of last header view
- final int numHeaders = getHeaderViewsCount();
- final int numFooters = getFooterViewsCount();
- final int firstPos = getFirstVisiblePosition();
- final int lastPos = getLastVisiblePosition();
-
- // "nHead="+numHeaders+" nFoot="+numFooters+" first="+firstPos+" last="+lastPos);
- int topLimit = getPaddingTop();
- if (firstPos < numHeaders) {
- topLimit = getChildAt(numHeaders - firstPos - 1).getBottom();
- }
- if ((mDragFlags & DRAG_NEG_Y) == 0) {
- if (firstPos <= mSrcPos) {
- topLimit = Math.max(getChildAt(mSrcPos - firstPos).getTop(), topLimit);
- }
- }
- // bottom limit is top of first footer View or
- // bottom of last item in list
- int bottomLimit = getHeight() - getPaddingBottom();
- if (lastPos >= getCount() - numFooters - 1) {
- bottomLimit = getChildAt(getCount() - numFooters - 1 - firstPos).getBottom();
- }
- if ((mDragFlags & DRAG_POS_Y) == 0) {
- if (lastPos >= mSrcPos) {
- bottomLimit = Math.min(getChildAt(mSrcPos - firstPos).getBottom(), bottomLimit);
- }
- }
-
- if (floatY < topLimit) {
- mFloatLoc.y = topLimit;
- } else if (floatY + mFloatViewHeight > bottomLimit) {
- mFloatLoc.y = bottomLimit - mFloatViewHeight;
- }
-
- // get y-midpoint of floating view (constrained to ListView bounds)
- mFloatViewMid = mFloatLoc.y + mFloatViewHeightHalf;
- }
-
- private void destroyFloatView() {
- if (mFloatView != null) {
- mFloatView.setVisibility(GONE);
- if (mFloatViewManager != null) {
- mFloatViewManager.onDestroyFloatView(mFloatView);
- }
- mFloatView = null;
- invalidate();
- }
- }
-
- /**
- * Interface for customization of the floating View appearance
- * and dragging behavior. Implement
- * your own and pass it to {@link #setFloatViewManager}. If
- * your own is not passed, the default {@link SimpleFloatViewManager}
- * implementation is used.
- */
- public interface FloatViewManager {
- /**
- * Return the floating View for item at position
.
- * DragSortListView will measure and layout this View for you,
- * so feel free to just inflate it. You can help DSLV by
- * setting some {@link ViewGroup.LayoutParams} on this View;
- * otherwise it will set some for you (with a width of FILL_PARENT
- * and a height of WRAP_CONTENT).
- *
- * @param position Position of item to drag (NOTE:
- * position
excludes header Views; thus, if you
- * want to call {@link ListView#getChildAt(int)}, you will need
- * to add {@link ListView#getHeaderViewsCount()} to the index).
- *
- * @return The View you wish to display as the floating View.
- */
- public View onCreateFloatView(int position);
-
- /**
- * Called whenever the floating View is dragged. Float View
- * properties can be changed here. Also, the upcoming location
- * of the float View can be altered by setting
- * location.x
and location.y
.
- *
- * @param floatView The floating View.
- * @param location The location (top-left; relative to DSLV
- * top-left) at which the float
- * View would like to appear, given the current touch location
- * and the offset provided in {@link DragSortListView#startDrag}.
- * @param touch The current touch location (relative to DSLV
- * top-left).
- * @param pendingScroll
- */
- public void onDragFloatView(View floatView, Point location, Point touch);
-
- /**
- * Called when the float View is dropped; lets you perform
- * any necessary cleanup. The internal DSLV floating View
- * reference is set to null immediately after this is called.
- *
- * @param floatView The floating View passed to
- * {@link #onCreateFloatView(int)}.
- */
- public void onDestroyFloatView(View floatView);
- }
-
- public void setFloatViewManager(FloatViewManager manager) {
- mFloatViewManager = manager;
- }
-
- public void setDragListener(DragListener l) {
- mDragListener = l;
- }
-
- /**
- * Allows for easy toggling between a DragSortListView
- * and a regular old ListView. If enabled, items are
- * draggable, where the drag init mode determines how
- * items are lifted (see {@link setDragInitMode(int)}).
- * If disabled, items cannot be dragged.
- *
- * @param enabled Set true
to enable list
- * item dragging
- */
- public void setDragEnabled(boolean enabled) {
- mDragEnabled = enabled;
- }
-
- public boolean isDragEnabled() {
- return mDragEnabled;
- }
-
- /**
- * This better reorder your ListAdapter! DragSortListView does not do this
- * for you; doesn't make sense to. Make sure
- * {@link BaseAdapter#notifyDataSetChanged()} or something like it is called
- * in your implementation. Furthermore, if you have a choiceMode other than
- * none and the ListAdapter does not return true for
- * {@link ListAdapter#hasStableIds()}, you will need to call
- * {@link #moveCheckState(int, int)} to move the check boxes along with the
- * list items.
- *
- * @param l
- */
- public void setDropListener(DropListener l) {
- mDropListener = l;
- }
-
- /**
- * Probably a no-brainer, but make sure that your remove listener
- * calls {@link BaseAdapter#notifyDataSetChanged()} or something like it.
- * When an item removal occurs, DragSortListView
- * relies on a redraw of all the items to recover invisible views
- * and such. Strictly speaking, if you remove something, your dataset
- * has changed...
- *
- * @param l
- */
- public void setRemoveListener(RemoveListener l) {
- mRemoveListener = l;
- }
-
- public interface DragListener {
- public void drag(int from, int to);
- }
-
- /**
- * Your implementation of this has to reorder your ListAdapter!
- * Make sure to call
- * {@link BaseAdapter#notifyDataSetChanged()} or something like it
- * in your implementation.
- *
- * @author heycosmo
- *
- */
- public interface DropListener {
- public void drop(int from, int to);
- }
-
- /**
- * Make sure to call
- * {@link BaseAdapter#notifyDataSetChanged()} or something like it
- * in your implementation.
- *
- * @author heycosmo
- *
- */
- public interface RemoveListener {
- public void remove(int which);
- }
-
- public interface DragSortListener extends DropListener, DragListener, RemoveListener {
- }
-
- public void setDragSortListener(DragSortListener l) {
- setDropListener(l);
- setDragListener(l);
- setRemoveListener(l);
- }
-
- /**
- * Completely custom scroll speed profile. Default increases linearly
- * with position and is constant in time. Create your own by implementing
- * {@link DragSortListView.DragScrollProfile}.
- *
- * @param ssp
- */
- public void setDragScrollProfile(DragScrollProfile ssp) {
- if (ssp != null) {
- mScrollProfile = ssp;
- }
- }
-
- /**
- * Use this to move the check state of an item from one position to another
- * in a drop operation. If you have a choiceMode which is not none, this
- * method must be called when the order of items changes in an underlying
- * adapter which does not have stable IDs (see
- * {@link ListAdapter#hasStableIds()}). This is because without IDs, the
- * ListView has no way of knowing which items have moved where, and cannot
- * update the check state accordingly.
- *
- * A word of warning about a "feature" in Android that you may run into when
- * dealing with movable list items: for an adapter that does have
- * stable IDs, ListView will attempt to locate each item based on its ID and
- * move the check state from the item's old position to the new position —
- * which is all fine and good (and removes the need for calling this
- * function), except for the half-baked approach. Apparently to save time in
- * the naive algorithm used, ListView will only search for an ID in the
- * close neighborhood of the old position. If the user moves an item too far
- * (specifically, more than 20 rows away), ListView will give up and just
- * force the item to be unchecked. So if there is a reasonable chance that
- * the user will move items more than 20 rows away from the original
- * position, you may wish to use an adapter with unstable IDs and call this
- * method manually instead.
- *
- * @param from
- * @param to
- */
- public void moveCheckState(int from, int to) {
- // This method runs in O(n log n) time (n being the number of list
- // items). The bottleneck is the call to AbsListView.setItemChecked,
- // which is O(log n) because of the binary search involved in calling
- // SparseBooleanArray.put().
- //
- // To improve on the average time, we minimize the number of calls to
- // setItemChecked by only calling it for items that actually have a
- // changed state. This is achieved by building a list containing the
- // start and end of the "runs" of checked items, and then moving the
- // runs. Note that moving an item from A to B is essentially a rotation
- // of the range of items in [A, B]. Let's say we have
- // . . U V X Y Z . .
- // and move U after Z. This is equivalent to a rotation one step to the
- // left within the range you are moving across:
- // . . V X Y Z U . .
- //
- // So, to perform the move we enumerate all the runs within the move
- // range, then rotate each run one step to the left or right (depending
- // on move direction). For example, in the list:
- // X X . X X X . X
- // we have two runs. One begins at the last item of the list and wraps
- // around to the beginning, ending at position 1. The second begins at
- // position 3 and ends at position 5. To rotate a run, regardless of
- // length, we only need to set a check mark at one end of the run, and
- // clear a check mark at the other end:
- // X . X X X . X X
- SparseBooleanArray cip = getCheckedItemPositions();
- int rangeStart = from;
- int rangeEnd = to;
- if (to < from) {
- rangeStart = to;
- rangeEnd = from;
- }
- rangeEnd += 1;
-
- int[] runStart = new int[cip.size()];
- int[] runEnd = new int[cip.size()];
- int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd);
- if (runCount == 1 && (runStart[0] == runEnd[0])) {
- // Special case where all items are checked, we can never set any
- // item to false like we do below.
- return;
- }
-
- if (from < to) {
- for (int i = 0; i != runCount; i++) {
- setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true);
- setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false);
- }
-
- } else {
- for (int i = 0; i != runCount; i++) {
- setItemChecked(runStart[i], false);
- setItemChecked(runEnd[i], true);
- }
- }
- }
-
- /**
- * Use this when an item has been deleted, to move the check state of all
- * following items up one step. If you have a choiceMode which is not none,
- * this method must be called when the order of items changes in an
- * underlying adapter which does not have stable IDs (see
- * {@link ListAdapter#hasStableIds()}). This is because without IDs, the
- * ListView has no way of knowing which items have moved where, and cannot
- * update the check state accordingly.
- *
- * See also further comments on {@link #moveCheckState(int, int)}.
- *
- * @param position
- */
- public void removeCheckState(int position) {
- SparseBooleanArray cip = getCheckedItemPositions();
-
- if (cip.size() == 0)
- return;
- int[] runStart = new int[cip.size()];
- int[] runEnd = new int[cip.size()];
- int rangeStart = position;
- int rangeEnd = cip.keyAt(cip.size() - 1) + 1;
- int runCount = buildRunList(cip, rangeStart, rangeEnd, runStart, runEnd);
- for (int i = 0; i != runCount; i++) {
- if (!(runStart[i] == position || (runEnd[i] < runStart[i] && runEnd[i] > position))) {
- // Only set a new check mark in front of this run if it does
- // not contain the deleted position. If it does, we only need
- // to make it one check mark shorter at the end.
- setItemChecked(rotate(runStart[i], -1, rangeStart, rangeEnd), true);
- }
- setItemChecked(rotate(runEnd[i], -1, rangeStart, rangeEnd), false);
- }
- }
-
- private static int buildRunList(SparseBooleanArray cip, int rangeStart,
- int rangeEnd, int[] runStart, int[] runEnd) {
- int runCount = 0;
-
- int i = findFirstSetIndex(cip, rangeStart, rangeEnd);
- if (i == -1)
- return 0;
-
- int position = cip.keyAt(i);
- int currentRunStart = position;
- int currentRunEnd = currentRunStart + 1;
- for (i++; i < cip.size() && (position = cip.keyAt(i)) < rangeEnd; i++) {
- if (!cip.valueAt(i)) // not checked => not interesting
- continue;
- if (position == currentRunEnd) {
- currentRunEnd++;
- } else {
- runStart[runCount] = currentRunStart;
- runEnd[runCount] = currentRunEnd;
- runCount++;
- currentRunStart = position;
- currentRunEnd = position + 1;
- }
- }
-
- if (currentRunEnd == rangeEnd) {
- // rangeStart and rangeEnd are equivalent positions so to be
- // consistent we translate them to the same integer value. That way
- // we can check whether a run covers the entire range by just
- // checking if the start equals the end position.
- currentRunEnd = rangeStart;
- }
- runStart[runCount] = currentRunStart;
- runEnd[runCount] = currentRunEnd;
- runCount++;
-
- if (runCount > 1) {
- if (runStart[0] == rangeStart && runEnd[runCount - 1] == rangeStart) {
- // The last run ends at the end of the range, and the first run
- // starts at the beginning of the range. So they are actually
- // part of the same run, except they wrap around the end of the
- // range. To avoid adjacent runs, we need to merge them.
- runStart[0] = runStart[runCount - 1];
- runCount--;
- }
- }
- return runCount;
- }
-
- private static int rotate(int value, int offset, int lowerBound, int upperBound) {
- int windowSize = upperBound - lowerBound;
-
- value += offset;
- if (value < lowerBound) {
- value += windowSize;
- } else if (value >= upperBound) {
- value -= windowSize;
- }
- return value;
- }
-
- private static int findFirstSetIndex(SparseBooleanArray sba, int rangeStart, int rangeEnd) {
- int size = sba.size();
- int i = insertionIndexForKey(sba, rangeStart);
- while (i < size && sba.keyAt(i) < rangeEnd && !sba.valueAt(i))
- i++;
- if (i == size || sba.keyAt(i) >= rangeEnd)
- return -1;
- return i;
- }
-
- private static int insertionIndexForKey(SparseBooleanArray sba, int key) {
- int low = 0;
- int high = sba.size();
- while (high - low > 0) {
- int middle = (low + high) >> 1;
- if (sba.keyAt(middle) < key)
- low = middle + 1;
- else
- high = middle;
- }
- return low;
- }
-
- /**
- * Interface for controlling
- * scroll speed as a function of touch position and time. Use
- * {@link DragSortListView#setDragScrollProfile(DragScrollProfile)} to
- * set custom profile.
- *
- * @author heycosmo
- *
- */
- public interface DragScrollProfile {
- /**
- * Return a scroll speed in pixels/millisecond. Always return a
- * positive number.
- *
- * @param w Normalized position in scroll region (i.e. w \in [0,1]).
- * Small w typically means slow scrolling.
- * @param t Time (in milliseconds) since start of scroll (handy if you
- * want scroll acceleration).
- * @return Scroll speed at position w and time t in pixels/ms.
- */
- float getSpeed(float w, long t);
- }
-
- private class DragScroller implements Runnable {
-
- private boolean mAbort;
-
- private long mPrevTime;
- private long mCurrTime;
-
- private int dy;
- private float dt;
- private long tStart;
- private int scrollDir;
-
- public final static int STOP = -1;
- public final static int UP = 0;
- public final static int DOWN = 1;
-
- private float mScrollSpeed; // pixels per ms
-
- private boolean mScrolling = false;
-
- private int mLastHeader;
- private int mFirstFooter;
-
- public boolean isScrolling() {
- return mScrolling;
- }
-
- public int getScrollDir() {
- return mScrolling ? scrollDir : STOP;
- }
-
- public DragScroller() {
- }
-
- public void startScrolling(int dir) {
- if (!mScrolling) {
- // Debug.startMethodTracing("dslv-scroll");
- mAbort = false;
- mScrolling = true;
- tStart = SystemClock.uptimeMillis();
- mPrevTime = tStart;
- scrollDir = dir;
- post(this);
- }
- }
-
- public void stopScrolling(boolean now) {
- if (now) {
- DragSortListView.this.removeCallbacks(this);
- mScrolling = false;
- } else {
- mAbort = true;
- }
-
- // Debug.stopMethodTracing();
- }
-
- @Override
- public void run() {
- if (mAbort) {
- mScrolling = false;
- return;
- }
-
-
- final int first = getFirstVisiblePosition();
- final int last = getLastVisiblePosition();
- final int count = getCount();
- final int padTop = getPaddingTop();
- final int listHeight = getHeight() - padTop - getPaddingBottom();
-
- int minY = Math.min(mY, mFloatViewMid + mFloatViewHeightHalf);
- int maxY = Math.max(mY, mFloatViewMid - mFloatViewHeightHalf);
-
- if (scrollDir == UP) {
- View v = getChildAt(0);
- if (v == null) {
- mScrolling = false;
- return;
- } else {
- if (first == 0 && v.getTop() == padTop) {
- mScrolling = false;
- return;
- }
- }
- mScrollSpeed = mScrollProfile.getSpeed((mUpScrollStartYF - maxY)
- / mDragUpScrollHeight, mPrevTime);
- } else {
- View v = getChildAt(last - first);
- if (v == null) {
- mScrolling = false;
- return;
- } else {
- if (last == count - 1 && v.getBottom() <= listHeight + padTop) {
- mScrolling = false;
- return;
- }
- }
- mScrollSpeed = -mScrollProfile.getSpeed((minY - mDownScrollStartYF)
- / mDragDownScrollHeight, mPrevTime);
- }
-
- mCurrTime = SystemClock.uptimeMillis();
- dt = (float) (mCurrTime - mPrevTime);
-
- // dy is change in View position of a list item; i.e. positive dy
- // means user is scrolling up (list item moves down the screen,
- // remember
- // y=0 is at top of View).
- dy = (int) Math.round(mScrollSpeed * dt);
-
- int movePos;
- if (dy >= 0) {
- dy = Math.min(listHeight, dy);
- movePos = first;
- } else {
- dy = Math.max(-listHeight, dy);
- movePos = last;
- }
-
- final View moveItem = getChildAt(movePos - first);
- int top = moveItem.getTop() + dy;
-
- if (movePos == 0 && top > padTop) {
- top = padTop;
- }
-
- // always do scroll
- mBlockLayoutRequests = true;
-
- // This cast is a workaround of an API bug, see https://issuetracker.google.com/issues/37045361
- ((ListView)DragSortListView.this).setSelectionFromTop(movePos, top - padTop);
-
- DragSortListView.this.layoutChildren();
- invalidate();
-
- mBlockLayoutRequests = false;
-
- // scroll means relative float View movement
- doDragFloatView(movePos, moveItem, false);
-
- mPrevTime = mCurrTime;
- post(this);
- }
- }
-
- private class DragSortTracker {
- StringBuilder mBuilder = new StringBuilder();
-
- File mFile;
-
- private int mNumInBuffer = 0;
- private int mNumFlushes = 0;
-
- private boolean mTracking = false;
-
- public DragSortTracker() {
- File root = Environment.getExternalStorageDirectory();
- mFile = new File(root, "dslv_state.txt");
-
- if (!mFile.exists()) {
- try {
- mFile.createNewFile();
- Timber.d("file created");
- } catch (IOException e) {
- Timber.w("Could not create dslv_state.txt");
- Timber.d(e.getMessage());
- }
- }
-
- }
-
- public void startTracking() {
- mBuilder.append("
Sets the layout resource of the item views.
- * - * @param layout the layout resources used to create item views - */ - public void setViewResource(int layout) { - mLayout = layout; - } - - /** - *Sets the layout resource of the drop down views.
- * - * @param dropDownLayout the layout resources used to create drop down views - */ - public void setDropDownViewResource(int dropDownLayout) { - mDropDownLayout = dropDownLayout; - } -} diff --git a/core/library/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java b/core/library/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java deleted file mode 100644 index 7a76ea9d..00000000 --- a/core/library/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.mobeta.android.dslv; - -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.view.View; -import android.widget.TextView; -import android.widget.ImageView; - -// taken from sdk/sources/android-16/android/widget/SimpleCursorAdapter.java - -/** - * An easy adapter to map columns from a cursor to TextViews or ImageViews - * defined in an XML file. You can specify which columns you want, which - * views you want to display the columns, and the XML file that defines - * the appearance of these views. - * - * Binding occurs in two phases. First, if a - * {@link android.widget.SimpleCursorAdapter.ViewBinder} is available, - * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)} - * is invoked. If the returned value is true, binding has occured. If the - * returned value is false and the view to bind is a TextView, - * {@link #setViewText(TextView, String)} is invoked. If the returned value - * is false and the view to bind is an ImageView, - * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate - * binding can be found, an {@link IllegalStateException} is thrown. - * - * If this adapter is used with filtering, for instance in an - * {@link android.widget.AutoCompleteTextView}, you can use the - * {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} and the - * {@link android.widget.FilterQueryProvider} interfaces - * to get control over the filtering process. You can refer to - * {@link #convertToString(android.database.Cursor)} and - * {@link #runQueryOnBackgroundThread(CharSequence)} for more information. - */ -public class SimpleDragSortCursorAdapter extends ResourceDragSortCursorAdapter { - /** - * A list of columns containing the data to bind to the UI. - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected int[] mFrom; - /** - * A list of View ids representing the views to which the data must be bound. - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected int[] mTo; - - private int mStringConversionColumn = -1; - private CursorToStringConverter mCursorToStringConverter; - private ViewBinder mViewBinder; - - String[] mOriginalFrom; - - /** - * Constructor the enables auto-requery. - * - * @deprecated This option is discouraged, as it results in Cursor queries - * being performed on the application's UI thread and thus can cause poor - * responsiveness or even Application Not Responding errors. As an alternative, - * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}. - */ - @Deprecated - public SimpleDragSortCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { - super(context, layout, c); - mTo = to; - mOriginalFrom = from; - findColumns(c, from); - } - - /** - * Standard constructor. - * - * @param context The context where the ListView associated with this - * SimpleListItemFactory is running - * @param layout resource identifier of a layout file that defines the views - * for this list item. The layout file should include at least - * those named views defined in "to" - * @param c The database cursor. Can be null if the cursor is not available yet. - * @param from A list of column names representing the data to bind to the UI. Can be null - * if the cursor is not available yet. - * @param to The views that should display column in the "from" parameter. - * These should all be TextViews. The first N views in this list - * are given the values of the first N columns in the from - * parameter. Can be null if the cursor is not available yet. - * @param flags Flags used to determine the behavior of the adapter, - * as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}. - */ - public SimpleDragSortCursorAdapter(Context context, int layout, - Cursor c, String[] from, int[] to, int flags) { - super(context, layout, c, flags); - mTo = to; - mOriginalFrom = from; - findColumns(c, from); - } - - /** - * Binds all of the field names passed into the "to" parameter of the - * constructor with their corresponding cursor columns as specified in the - * "from" parameter. - * - * Binding occurs in two phases. First, if a - * {@link android.widget.SimpleCursorAdapter.ViewBinder} is available, - * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)} - * is invoked. If the returned value is true, binding has occured. If the - * returned value is false and the view to bind is a TextView, - * {@link #setViewText(TextView, String)} is invoked. If the returned value is - * false and the view to bind is an ImageView, - * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate - * binding can be found, an {@link IllegalStateException} is thrown. - * - * @throws IllegalStateException if binding cannot occur - * - * @see android.widget.CursorAdapter#bindView(android.view.View, - * android.content.Context, android.database.Cursor) - * @see #getViewBinder() - * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) - * @see #setViewImage(ImageView, String) - * @see #setViewText(TextView, String) - */ - @Override - public void bindView(View view, Context context, Cursor cursor) { - final ViewBinder binder = mViewBinder; - final int count = mTo.length; - final int[] from = mFrom; - final int[] to = mTo; - - for (int i = 0; i < count; i++) { - final View v = view.findViewById(to[i]); - if (v != null) { - boolean bound = false; - if (binder != null) { - bound = binder.setViewValue(v, cursor, from[i]); - } - - if (!bound) { - String text = cursor.getString(from[i]); - if (text == null) { - text = ""; - } - - if (v instanceof TextView) { - setViewText((TextView) v, text); - } else if (v instanceof ImageView) { - setViewImage((ImageView) v, text); - } else { - throw new IllegalStateException(v.getClass().getName() + " is not a " + - " view that can be bounds by this SimpleCursorAdapter"); - } - } - } - } - } - - /** - * Returns the {@link ViewBinder} used to bind data to views. - * - * @return a ViewBinder or null if the binder does not exist - * - * @see #bindView(android.view.View, android.content.Context, android.database.Cursor) - * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) - */ - public ViewBinder getViewBinder() { - return mViewBinder; - } - - /** - * Sets the binder used to bind data to views. - * - * @param viewBinder the binder used to bind data to views, can be null to - * remove the existing binder - * - * @see #bindView(android.view.View, android.content.Context, android.database.Cursor) - * @see #getViewBinder() - */ - public void setViewBinder(ViewBinder viewBinder) { - mViewBinder = viewBinder; - } - - /** - * Called by bindView() to set the image for an ImageView but only if - * there is no existing ViewBinder or if the existing ViewBinder cannot - * handle binding to an ImageView. - * - * By default, the value will be treated as an image resource. If the - * value cannot be used as an image resource, the value is used as an - * image Uri. - * - * Intended to be overridden by Adapters that need to filter strings - * retrieved from the database. - * - * @param v ImageView to receive an image - * @param value the value retrieved from the cursor - */ - public void setViewImage(ImageView v, String value) { - try { - v.setImageResource(Integer.parseInt(value)); - } catch (NumberFormatException nfe) { - v.setImageURI(Uri.parse(value)); - } - } - - /** - * Called by bindView() to set the text for a TextView but only if - * there is no existing ViewBinder or if the existing ViewBinder cannot - * handle binding to a TextView. - * - * Intended to be overridden by Adapters that need to filter strings - * retrieved from the database. - * - * @param v TextView to receive text - * @param text the text to be set for the TextView - */ - public void setViewText(TextView v, String text) { - v.setText(text); - } - - /** - * Return the index of the column used to get a String representation - * of the Cursor. - * - * @return a valid index in the current Cursor or -1 - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - * @see #setStringConversionColumn(int) - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getCursorToStringConverter() - */ - public int getStringConversionColumn() { - return mStringConversionColumn; - } - - /** - * Defines the index of the column in the Cursor used to get a String - * representation of that Cursor. The column is used to convert the - * Cursor to a String only when the current CursorToStringConverter - * is null. - * - * @param stringConversionColumn a valid index in the current Cursor or -1 to use the default - * conversion mechanism - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - * @see #getStringConversionColumn() - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getCursorToStringConverter() - */ - public void setStringConversionColumn(int stringConversionColumn) { - mStringConversionColumn = stringConversionColumn; - } - - /** - * Returns the converter used to convert the filtering Cursor - * into a String. - * - * @return null if the converter does not exist or an instance of - * {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} - * - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getStringConversionColumn() - * @see #setStringConversionColumn(int) - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public CursorToStringConverter getCursorToStringConverter() { - return mCursorToStringConverter; - } - - /** - * Sets the converter used to convert the filtering Cursor - * into a String. - * - * @param cursorToStringConverter the Cursor to String converter, or - * null to remove the converter - * - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getStringConversionColumn() - * @see #setStringConversionColumn(int) - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public void setCursorToStringConverter(CursorToStringConverter cursorToStringConverter) { - mCursorToStringConverter = cursorToStringConverter; - } - - /** - * Returns a CharSequence representation of the specified Cursor as defined - * by the current CursorToStringConverter. If no CursorToStringConverter - * has been set, the String conversion column is used instead. If the - * conversion column is -1, the returned String is empty if the cursor - * is null or Cursor.toString(). - * - * @param cursor the Cursor to convert to a CharSequence - * - * @return a non-null CharSequence representing the cursor - */ - @Override - public CharSequence convertToString(Cursor cursor) { - if (mCursorToStringConverter != null) { - return mCursorToStringConverter.convertToString(cursor); - } else if (mStringConversionColumn > -1) { - return cursor.getString(mStringConversionColumn); - } - - return super.convertToString(cursor); - } - - /** - * Create a map from an array of strings to an array of column-id integers in cursor c. - * If c is null, the array will be discarded. - * - * @param c the cursor to find the columns from - * @param from the Strings naming the columns of interest - */ - private void findColumns(Cursor c, String[] from) { - if (c != null) { - int i; - int count = from.length; - if (mFrom == null || mFrom.length != count) { - mFrom = new int[count]; - } - for (i = 0; i < count; i++) { - mFrom[i] = c.getColumnIndexOrThrow(from[i]); - } - } else { - mFrom = null; - } - } - - @Override - public Cursor swapCursor(Cursor c) { - // super.swapCursor() will notify observers before we have - // a valid mapping, make sure we have a mapping before this - // happens - findColumns(c, mOriginalFrom); - return super.swapCursor(c); - } - - /** - * Change the cursor and change the column-to-view mappings at the same time. - * - * @param c The database cursor. Can be null if the cursor is not available yet. - * @param from A list of column names representing the data to bind to the UI. Can be null - * if the cursor is not available yet. - * @param to The views that should display column in the "from" parameter. - * These should all be TextViews. The first N views in this list - * are given the values of the first N columns in the from - * parameter. Can be null if the cursor is not available yet. - */ - public void changeCursorAndColumns(Cursor c, String[] from, int[] to) { - mOriginalFrom = from; - mTo = to; - // super.changeCursor() will notify observers before we have - // a valid mapping, make sure we have a mapping before this - // happens - findColumns(c, mOriginalFrom); - super.changeCursor(c); - } - - /** - * This class can be used by external clients of SimpleCursorAdapter - * to bind values fom the Cursor to views. - * - * You should use this class to bind values from the Cursor to views - * that are not directly supported by SimpleCursorAdapter or to - * change the way binding occurs for views supported by - * SimpleCursorAdapter. - * - * @see SimpleCursorAdapter#bindView(android.view.View, android.content.Context, android.database.Cursor) - * @see SimpleCursorAdapter#setViewImage(ImageView, String) - * @see SimpleCursorAdapter#setViewText(TextView, String) - */ - public static interface ViewBinder { - /** - * Binds the Cursor column defined by the specified index to the specified view. - * - * When binding is handled by this ViewBinder, this method must return true. - * If this method returns false, SimpleCursorAdapter will attempts to handle - * the binding on its own. - * - * @param view the view to bind the data to - * @param cursor the cursor to get the data from - * @param columnIndex the column at which the data can be found in the cursor - * - * @return true if the data was bound to the view, false otherwise - */ - boolean setViewValue(View view, Cursor cursor, int columnIndex); - } - - /** - * This class can be used by external clients of SimpleCursorAdapter - * to define how the Cursor should be converted to a String. - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public static interface CursorToStringConverter { - /** - * Returns a CharSequence representing the specified Cursor. - * - * @param cursor the cursor for which a CharSequence representation - * is requested - * - * @return a non-null CharSequence representing the cursor - */ - CharSequence convertToString(Cursor cursor); - } - -} diff --git a/core/library/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java b/core/library/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java deleted file mode 100644 index 43505a4d..00000000 --- a/core/library/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.mobeta.android.dslv; - -import android.graphics.Bitmap; -import android.graphics.Point; -import android.graphics.Color; -import android.widget.ListView; -import android.widget.ImageView; -import android.view.View; -import android.view.ViewGroup; -import timber.log.Timber; - -/** - * Simple implementation of the FloatViewManager class. Uses list - * items as they appear in the ListView to create the floating View. - */ -public class SimpleFloatViewManager implements DragSortListView.FloatViewManager { - - private Bitmap mFloatBitmap; - - private ImageView mImageView; - - private int mFloatBGColor = Color.BLACK; - - private ListView mListView; - - public SimpleFloatViewManager(ListView lv) { - mListView = lv; - } - - public void setBackgroundColor(int color) { - mFloatBGColor = color; - } - - /** - * This simple implementation creates a Bitmap copy of the - * list item currently shown at ListViewposition
.
- */
- @Override
- public View onCreateFloatView(int position) {
- // Guaranteed that this will not be null? I think so. Nope, got
- // a NullPointerException once...
- View v = mListView.getChildAt(position + mListView.getHeaderViewsCount() - mListView.getFirstVisiblePosition());
-
- if (v == null) {
- return null;
- }
-
- v.setPressed(false);
-
- // Create a copy of the drawing cache so that it does not get
- // recycled by the framework when the list tries to clean up memory
- //v.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
- v.setDrawingCacheEnabled(true);
- mFloatBitmap = Bitmap.createBitmap(v.getDrawingCache());
- v.setDrawingCacheEnabled(false);
-
- if (mImageView == null) {
- mImageView = new ImageView(mListView.getContext());
- }
- mImageView.setBackgroundColor(mFloatBGColor);
- mImageView.setPadding(0, 0, 0, 0);
- mImageView.setImageBitmap(mFloatBitmap);
- mImageView.setLayoutParams(new ViewGroup.LayoutParams(v.getWidth(), v.getHeight()));
-
- return mImageView;
- }
-
- /**
- * This does nothing
- */
- @Override
- public void onDragFloatView(View floatView, Point position, Point touch) {
- // do nothing
- }
-
- /**
- * Removes the Bitmap from the ImageView created in
- * onCreateFloatView() and tells the system to recycle it.
- */
- @Override
- public void onDestroyFloatView(View floatView) {
- ((ImageView) floatView).setImageDrawable(null);
-
- mFloatBitmap.recycle();
- mFloatBitmap = null;
- }
-
-}
-
diff --git a/core/library/src/main/res/values/dslv_attrs.xml b/core/library/src/main/res/values/dslv_attrs.xml
deleted file mode 100644
index 6c4d5d79..00000000
--- a/core/library/src/main/res/values/dslv_attrs.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-