Android 用于视图列表视图的拖放操作

Android 用于视图列表视图的拖放操作,android,listview,android-listview,drag-and-drop,Android,Listview,Android Listview,Drag And Drop,您好,我有一个Listview,其中每个项目都有不同的布局。我想在这个Listview上执行拖放操作。我搜索了许多示例并尝试过,但所有这些都适用于字符串的Listview或类似的内容,没有一个适用于视图的Listview。最后我决定使用 DevBytes:ListView单元格拖动并重新排列此单元格。我实现了dynaliclistview,但它正在崩溃,因为这也在ListView中使用字符串。以下是我的ListView适配器 public class ListViewPagerAdapter e

您好,我有一个Listview,其中每个项目都有不同的布局。我想在这个Listview上执行拖放操作。我搜索了许多示例并尝试过,但所有这些都适用于字符串的Listview或类似的内容,没有一个适用于视图的Listview。最后我决定使用 DevBytes:ListView单元格拖动并重新排列此单元格。我实现了dynaliclistview,但它正在崩溃,因为这也在ListView中使用字符串。以下是我的ListView适配器

public class ListViewPagerAdapter extends BaseAdapter {

ViewPagerAdapter mViewPagerAdapter;
private Context context;
private int selectedIndex;
  FragmentManager mFragmentManager;
  static ViewPager vp;
  LayoutInflater inflater;
  private ArrayList<Integer> mContent;
public ListViewPagerAdapter(Context context,FragmentManager fg) 
{
    super();
    this.context = context;
    mFragmentManager = fg;
}

@Override
public int getCount() {

    return 4;
}

public void setSelectedIndex(int position) {
    selectedIndex = position;
    notifyDataSetChanged();
}



@Override
public long getItemId(int position) {

    return position;
}



@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    if (convertView == null) {

         inflater = (LayoutInflater) context
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        if(position==0)
        {
            convertView = inflater.inflate(R.layout.titlebar, null);
        }

    }
     if(position==0)
     {
        convertView = inflater.inflate(R.layout.titlebar, null);
     }
    if(position==1)
    {LayoutInflater inflater1 = (LayoutInflater) context
    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        convertView = inflater1.inflate(R.layout.calendarwidget_layout, null);

    }
     if(position==2)
     {
         LayoutInflater inflater2 = (LayoutInflater) context
                    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
     convertView = inflater2.inflate(R.layout.view_pager_list_view, null);
     vp = (ViewPager) convertView.findViewById(R.id.list_pager);  


     mViewPagerAdapter = new ViewPagerAdapter(mFragmentManager);
     vp.setAdapter(mViewPagerAdapter);

     }
     if(position==3)
     {
         LayoutInflater inflater2 = (LayoutInflater) context
                    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
     convertView = inflater2.inflate(R.layout.view_pager_list_view, null);
     vp = (ViewPager) convertView.findViewById(R.id.list_pager);  


     mViewPagerAdapter = new ViewPagerAdapter(mFragmentManager);
     vp.setAdapter(mViewPagerAdapter);
     mViewPagerAdapter.notifyDataSetChanged();


     }


    return convertView;
}

@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    return null;
}
}
公共类ListViewPagerAdapter扩展BaseAdapter{
ViewPagerAdapter mViewPagerAdapter;
私人语境;
私有int-selectedIndex;
碎片管理器;
静态可视寻呼机;
充气机;
私有ArrayList mContent;
public ListViewPagerAdapter(上下文,FragmentManager fg)
{
超级();
this.context=上下文;
MFFragmentManager=fg;
}
@凌驾
public int getCount(){
返回4;
}
公共无效集合SelectedIndex(内部位置){
selectedIndex=位置;
notifyDataSetChanged();
}
@凌驾
公共长getItemId(int位置){
返回位置;
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
//TODO自动生成的方法存根
if(convertView==null){
充气器=(充气器)上下文
.getSystemService(活动.布局\充气机\服务);
如果(位置==0)
{
convertView=充气机。充气(右布局标题栏,空);
}
}
如果(位置==0)
{
convertView=充气机。充气(右布局标题栏,空);
}
如果(位置==1)
{LayoutInflater充气器1=(LayoutInflater)上下文
.getSystemService(活动.布局\充气机\服务);
convertView=inflater1.充气(R.layout.calendarwidget\u布局,null);
}
如果(位置==2)
{
LayoutFlater充气器2=(LayoutFlater)上下文
.getSystemService(活动.布局\充气机\服务);
convertView=充气机2.充气(R.layout.view\u pager\u list\u view,空);
vp=(ViewPager)convertView.findViewById(R.id.list\u pager);
mViewPagerAdapter=新的ViewPagerAdapter(MFFragmentManager);
vp.setAdapter(mViewPagerAdapter);
}
如果(位置==3)
{
LayoutFlater充气器2=(LayoutFlater)上下文
.getSystemService(活动.布局\充气机\服务);
convertView=充气机2.充气(R.layout.view\u pager\u list\u view,空);
vp=(ViewPager)convertView.findViewById(R.id.list\u pager);
mViewPagerAdapter=新的ViewPagerAdapter(MFFragmentManager);
vp.setAdapter(mViewPagerAdapter);
mViewPagerAdapter.notifyDataSetChanged();
}
返回视图;
}
@凌驾
公共对象getItem(int位置){
//TODO自动生成的方法存根
返回null;
}
}
下面是dynamiclisview的代码(与前面提到的示例相同)

公共类DynamicListView扩展了ListView{
私有最终整型平滑\u滚动\u数量\u边缘=15;
私人最终整数移动持续时间=150;
私有最终内部线厚度=15;
公共ArrayList mCheeseList;
private int mLastEventY=-1;
private int mDownY=-1;
private int mDownX=-1;
私有int mTotalOffset=0;
私有布尔值mCellIsMobile=false;
私有布尔值mIsMobileScrolling=false;
private int mSmoothScrollAmountAtEdge=0;
私有final int INVALID_ID=-1;
private long mAboveItemId=无效的\u ID;
private long mMobileItemId=无效的\u ID;
private long mBelowItemId=无效的\u ID;
专用位图可绘制MH超小区;
私有Rect-mhcolcurrentBounds;
私有Rect-mHoverCellOriginalBounds;
私有final int无效\u指针\u ID=-1;
private int mActivePointerId=无效的\u指针\u ID;
私有布尔值mIsWaitingForScrollFinish=false;
private int mScrollState=onscrollllistener.SCROLL\u STATE\u IDLE;
公共DynamicListView(上下文){
超级(上下文);
init(上下文);
}
公共DynamicListView(上下文上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
init(上下文);
}
公共DynamicList视图(上下文、属性集属性){
超级(上下文,attrs);
init(上下文);
}
公共void init(上下文){
设置长ClickListener(监视器长ClickListener);
setOnScrollListener(mScrollListener);
DisplayMetrics=context.getResources().getDisplayMetrics();
mSmoothScrollAmountAtEdge=(int)(平滑滚动边缘处的数量/metrics.density);
}
/**
*侦听listview中任何项目的长时间单击。当单元格
*如果选定,将创建并设置悬停单元格。
*/
private AdapterView.OnItemLongClickListener监视器LongClickListener=
新的AdapterView.OnItemLongClickListener(){
长单击公共布尔值(AdapterView arg0、视图arg1、int pos、长id){
mTotalOffset=0;
int位置=点位置(mDownX,mDownY);
int itemNum=position-getFirstVisiblePosition();
View selectedView=getChildAt(itemNum);
mMobileItemId=getAdapter().getItemId(位置);
mHoverCell=GetAndAddressHoverView(selectedView);
selectedView.setVisibility(不可见);
mCellIsMobile=true;
updateNeighborViewsForID(mMobileItemId);
返回true;
}
};
/**
*使用适当的位图和适当的颜色创建悬停单元格
*悬停单元格的BitmapDrawable每隔一天都会绘制在位图的顶部
*进行一次无效调用。
*/
私有位图可绘制getAndAddHoverView(视图v){
int w=v.getWidth();
inth=v.getHeight();
int top=v.getTop();
int left=v.getLeft();
位图b=getBitmapWithBorder(v);
BitmapDrawable drawable=新的BitmapDrawable(getResources(),b);
mHoverCellOriginalBounds=新矩形(左、上、左+w、上+h);
mHoverCellCurrentBounds=新矩形(mHoverCellOrigina
public class DynamicListView extends ListView {

private final int SMOOTH_SCROLL_AMOUNT_AT_EDGE = 15;
private final int MOVE_DURATION = 150;
private final int LINE_THICKNESS = 15;

public ArrayList<String> mCheeseList;

private int mLastEventY = -1;

private int mDownY = -1;
private int mDownX = -1;

private int mTotalOffset = 0;

private boolean mCellIsMobile = false;
private boolean mIsMobileScrolling = false;
private int mSmoothScrollAmountAtEdge = 0;

private final int INVALID_ID = -1;
private long mAboveItemId = INVALID_ID;
private long mMobileItemId = INVALID_ID;
private long mBelowItemId = INVALID_ID;

private BitmapDrawable mHoverCell;
private Rect mHoverCellCurrentBounds;
private Rect mHoverCellOriginalBounds;

private final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;

private boolean mIsWaitingForScrollFinish = false;
private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;

public DynamicListView(Context context) {
    super(context);
    init(context);
}

public DynamicListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

public DynamicListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public void init(Context context) {
    setOnItemLongClickListener(mOnItemLongClickListener);
    setOnScrollListener(mScrollListener);
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    mSmoothScrollAmountAtEdge = (int)(SMOOTH_SCROLL_AMOUNT_AT_EDGE / metrics.density);
}

/**
 * Listens for long clicks on any items in the listview. When a cell has
 * been selected, the hover cell is created and set up.
 */
private AdapterView.OnItemLongClickListener mOnItemLongClickListener =
        new AdapterView.OnItemLongClickListener() {
            public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int pos, long id) {
                mTotalOffset = 0;

                int position = pointToPosition(mDownX, mDownY);
                int itemNum = position - getFirstVisiblePosition();

                View selectedView = getChildAt(itemNum);
                mMobileItemId = getAdapter().getItemId(position);
                mHoverCell = getAndAddHoverView(selectedView);
                selectedView.setVisibility(INVISIBLE);

                mCellIsMobile = true;

                updateNeighborViewsForID(mMobileItemId);

                return true;
            }
        };

/**
 * Creates the hover cell with the appropriate bitmap and of appropriate
 * size. The hover cell's BitmapDrawable is drawn on top of the bitmap every
 * single time an invalidate call is made.
 */
private BitmapDrawable getAndAddHoverView(View v) {

    int w = v.getWidth();
    int h = v.getHeight();
    int top = v.getTop();
    int left = v.getLeft();

    Bitmap b = getBitmapWithBorder(v);

    BitmapDrawable drawable = new BitmapDrawable(getResources(), b);

    mHoverCellOriginalBounds = new Rect(left, top, left + w, top + h);
    mHoverCellCurrentBounds = new Rect(mHoverCellOriginalBounds);

    drawable.setBounds(mHoverCellCurrentBounds);

    return drawable;
}

/** Draws a black border over the screenshot of the view passed in. */
private Bitmap getBitmapWithBorder(View v) {
    Bitmap bitmap = getBitmapFromView(v);
    Canvas can = new Canvas(bitmap);

    Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

    Paint paint = new Paint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(LINE_THICKNESS);
    paint.setColor(Color.BLACK);

    can.drawBitmap(bitmap, 0, 0, null);
    can.drawRect(rect, paint);

    return bitmap;
}

/** Returns a bitmap showing a screenshot of the view passed in. */
private Bitmap getBitmapFromView(View v) {
    Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas (bitmap);
    v.draw(canvas);
    return bitmap;
}

/**
 * Stores a reference to the views above and below the item currently
 * corresponding to the hover cell. It is important to note that if this
 * item is either at the top or bottom of the list, mAboveItemId or mBelowItemId
 * may be invalid.
 */
private void updateNeighborViewsForID(long itemID) {
    int position = getPositionForID(itemID);
    ListViewPagerAdapter adapter = ((ListViewPagerAdapter)getAdapter());
    mAboveItemId = adapter.getItemId(position - 1);
    mBelowItemId = adapter.getItemId(position + 1);
}

/** Retrieves the view in the list corresponding to itemID */
public View getViewForID (long itemID) {
    int firstVisiblePosition = getFirstVisiblePosition();
    ListViewPagerAdapter adapter = ((ListViewPagerAdapter)getAdapter());
    for(int i = 0; i < getChildCount(); i++) {
        View v = getChildAt(i);
        int position = firstVisiblePosition + i;
        long id = adapter.getItemId(position);
        if (id == itemID) {
            return v;
        }
    }
    return null;
}

/** Retrieves the position in the list corresponding to itemID */
public int getPositionForID (long itemID) {
    View v = getViewForID(itemID);
    if (v == null) {
        return -1;
    } else {
        return getPositionForView(v);
    }
}

/**
 *  dispatchDraw gets invoked when all the child views are about to be drawn.
 *  By overriding this method, the hover cell (BitmapDrawable) can be drawn
 *  over the listview's items whenever the listview is redrawn.
 */
@Override
protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
    if (mHoverCell != null) {
        mHoverCell.draw(canvas);
    }
}

@Override
public boolean onTouchEvent (MotionEvent event) {

    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            mDownX = (int)event.getX();
            mDownY = (int)event.getY();
            mActivePointerId = event.getPointerId(0);
            break;
        case MotionEvent.ACTION_MOVE:
            if (mActivePointerId == INVALID_POINTER_ID) {
                break;
            }

            int pointerIndex = event.findPointerIndex(mActivePointerId);

            mLastEventY = (int) event.getY(pointerIndex);
            int deltaY = mLastEventY - mDownY;

            if (mCellIsMobile) {
                mHoverCellCurrentBounds.offsetTo(mHoverCellOriginalBounds.left,
                        mHoverCellOriginalBounds.top + deltaY + mTotalOffset);
                mHoverCell.setBounds(mHoverCellCurrentBounds);
                invalidate();

                handleCellSwitch();

                mIsMobileScrolling = false;
                handleMobileCellScroll();

                return false;
            }
            break;
        case MotionEvent.ACTION_UP:
            touchEventsEnded();
            break;
        case MotionEvent.ACTION_CANCEL:
            touchEventsCancelled();
            break;
        case MotionEvent.ACTION_POINTER_UP:
            /* If a multitouch event took place and the original touch dictating
             * the movement of the hover cell has ended, then the dragging event
             * ends and the hover cell is animated to its corresponding position
             * in the listview. */
            pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
                    MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            final int pointerId = event.getPointerId(pointerIndex);
            if (pointerId == mActivePointerId) {
                touchEventsEnded();
            }
            break;
        default:
            break;
    }

    return super.onTouchEvent(event);
}

/**
 * This method determines whether the hover cell has been shifted far enough
 * to invoke a cell swap. If so, then the respective cell swap candidate is
 * determined and the data set is changed. Upon posting a notification of the
 * data set change, a layout is invoked to place the cells in the right place.
 * Using a ViewTreeObserver and a corresponding OnPreDrawListener, we can
 * offset the cell being swapped to where it previously was and then animate it to
 * its new position.
 */
private void handleCellSwitch() {
    final int deltaY = mLastEventY - mDownY;
    int deltaYTotal = mHoverCellOriginalBounds.top + mTotalOffset + deltaY;

    View belowView = getViewForID(mBelowItemId);
    View mobileView = getViewForID(mMobileItemId);
    View aboveView = getViewForID(mAboveItemId);

    boolean isBelow = (belowView != null) && (deltaYTotal > belowView.getTop());
    boolean isAbove = (aboveView != null) && (deltaYTotal < aboveView.getTop());

    if (isBelow || isAbove) {

        final long switchItemID = isBelow ? mBelowItemId : mAboveItemId;
        View switchView = isBelow ? belowView : aboveView;
        final int originalItem = getPositionForView(mobileView);

        if (switchView == null) {
            updateNeighborViewsForID(mMobileItemId);
            return;
        }

        swapElements(mCheeseList, originalItem, getPositionForView(switchView));

        ((BaseAdapter) getAdapter()).notifyDataSetChanged();

        mDownY = mLastEventY;

        final int switchViewStartTop = switchView.getTop();

        mobileView.setVisibility(View.VISIBLE);
        switchView.setVisibility(View.INVISIBLE);

        updateNeighborViewsForID(mMobileItemId);

        final ViewTreeObserver observer = getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @SuppressLint("NewApi")
            public boolean onPreDraw() {
                observer.removeOnPreDrawListener(this);

                View switchView = getViewForID(switchItemID);

                mTotalOffset += deltaY;

                int switchViewNewTop = switchView.getTop();
                int delta = switchViewStartTop - switchViewNewTop;

                switchView.setTranslationY(delta);

                ObjectAnimator animator = ObjectAnimator.ofFloat(switchView,
                        View.TRANSLATION_Y, 0);
                animator.setDuration(MOVE_DURATION);
                animator.start();

                return true;
            }
        });
    }
}

private void swapElements(ArrayList arrayList, int indexOne, int indexTwo) {
    Object temp = arrayList.get(indexOne);
    arrayList.set(indexOne, arrayList.get(indexTwo));
    arrayList.set(indexTwo, temp);
}


/**
 * Resets all the appropriate fields to a default state while also animating
 * the hover cell back to its correct location.
 */
private void touchEventsEnded () {
    final View mobileView = getViewForID(mMobileItemId);
    if (mCellIsMobile|| mIsWaitingForScrollFinish) {
        mCellIsMobile = false;
        mIsWaitingForScrollFinish = false;
        mIsMobileScrolling = false;
        mActivePointerId = INVALID_POINTER_ID;

        // If the autoscroller has not completed scrolling, we need to wait for it to
        // finish in order to determine the final location of where the hover cell
        // should be animated to.
        if (mScrollState != OnScrollListener.SCROLL_STATE_IDLE) {
            mIsWaitingForScrollFinish = true;
            return;
        }

        mHoverCellCurrentBounds.offsetTo(mHoverCellOriginalBounds.left, mobileView.getTop());

        ObjectAnimator hoverViewAnimator = ObjectAnimator.ofObject(mHoverCell, "bounds",
                sBoundEvaluator, mHoverCellCurrentBounds);
        hoverViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                invalidate();
            }
        });
        hoverViewAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                setEnabled(false);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mAboveItemId = INVALID_ID;
                mMobileItemId = INVALID_ID;
                mBelowItemId = INVALID_ID;
                mobileView.setVisibility(VISIBLE);
                mHoverCell = null;
                setEnabled(true);
                invalidate();
            }
        });
        hoverViewAnimator.start();
    } else {
        touchEventsCancelled();
    }
}

/**
 * Resets all the appropriate fields to a default state.
 */
private void touchEventsCancelled () {
    View mobileView = getViewForID(mMobileItemId);
    if (mCellIsMobile) {
        mAboveItemId = INVALID_ID;
        mMobileItemId = INVALID_ID;
        mBelowItemId = INVALID_ID;
        mobileView.setVisibility(VISIBLE);
        mHoverCell = null;
        invalidate();
    }
    mCellIsMobile = false;
    mIsMobileScrolling = false;
    mActivePointerId = INVALID_POINTER_ID;
}

/**
 * This TypeEvaluator is used to animate the BitmapDrawable back to its
 * final location when the user lifts his finger by modifying the
 * BitmapDrawable's bounds.
 */
private final static TypeEvaluator<Rect> sBoundEvaluator = new TypeEvaluator<Rect>() {
    public Rect evaluate(float fraction, Rect startValue, Rect endValue) {
        return new Rect(interpolate(startValue.left, endValue.left, fraction),
                interpolate(startValue.top, endValue.top, fraction),
                interpolate(startValue.right, endValue.right, fraction),
                interpolate(startValue.bottom, endValue.bottom, fraction));
    }

    public int interpolate(int start, int end, float fraction) {
        return (int)(start + fraction * (end - start));
    }
};

/**
 *  Determines whether this listview is in a scrolling state invoked
 *  by the fact that the hover cell is out of the bounds of the listview;
 */
private void handleMobileCellScroll() {
    mIsMobileScrolling = handleMobileCellScroll(mHoverCellCurrentBounds);
}

/**
 * This method is in charge of determining if the hover cell is above
 * or below the bounds of the listview. If so, the listview does an appropriate
 * upward or downward smooth scroll so as to reveal new items.
 */
public boolean handleMobileCellScroll(Rect r) {
    int offset = computeVerticalScrollOffset();
    int height = getHeight();
    int extent = computeVerticalScrollExtent();
    int range = computeVerticalScrollRange();
    int hoverViewTop = r.top;
    int hoverHeight = r.height();

    if (hoverViewTop <= 0 && offset > 0) {
        smoothScrollBy(-mSmoothScrollAmountAtEdge, 0);
        return true;
    }

    if (hoverViewTop + hoverHeight >= height && (offset + extent) < range) {
        smoothScrollBy(mSmoothScrollAmountAtEdge, 0);
        return true;
    }

    return false;
}

public void setCheeseList(ArrayList<String> cheeseList) {
    mCheeseList = cheeseList;
}

/**
 * This scroll listener is added to the listview in order to handle cell swapping
 * when the cell is either at the top or bottom edge of the listview. If the hover
 * cell is at either edge of the listview, the listview will begin scrolling. As
 * scrolling takes place, the listview continuously checks if new cells became visible
 * and determines whether they are potential candidates for a cell swap.
 */
private AbsListView.OnScrollListener mScrollListener = new AbsListView.OnScrollListener () {

    private int mPreviousFirstVisibleItem = -1;
    private int mPreviousVisibleItemCount = -1;
    private int mCurrentFirstVisibleItem;
    private int mCurrentVisibleItemCount;
    private int mCurrentScrollState;

    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
                         int totalItemCount) {
        mCurrentFirstVisibleItem = firstVisibleItem;
        mCurrentVisibleItemCount = visibleItemCount;

        mPreviousFirstVisibleItem = (mPreviousFirstVisibleItem == -1) ? mCurrentFirstVisibleItem
                : mPreviousFirstVisibleItem;
        mPreviousVisibleItemCount = (mPreviousVisibleItemCount == -1) ? mCurrentVisibleItemCount
                : mPreviousVisibleItemCount;

        checkAndHandleFirstVisibleCellChange();
        checkAndHandleLastVisibleCellChange();

        mPreviousFirstVisibleItem = mCurrentFirstVisibleItem;
        mPreviousVisibleItemCount = mCurrentVisibleItemCount;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        mCurrentScrollState = scrollState;
        mScrollState = scrollState;
        isScrollCompleted();
    }

    /**
     * This method is in charge of invoking 1 of 2 actions. Firstly, if the listview
     * is in a state of scrolling invoked by the hover cell being outside the bounds
     * of the listview, then this scrolling event is continued. Secondly, if the hover
     * cell has already been released, this invokes the animation for the hover cell
     * to return to its correct position after the listview has entered an idle scroll
     * state.
     */
    private void isScrollCompleted() {
        if (mCurrentVisibleItemCount > 0 && mCurrentScrollState == SCROLL_STATE_IDLE) {
            if (mCellIsMobile && mIsMobileScrolling) {
                handleMobileCellScroll();
            } else if (mIsWaitingForScrollFinish) {
                touchEventsEnded();
            }
        }
    }

    /**
     * Determines if the listview scrolled up enough to reveal a new cell at the
     * top of the list. If so, then the appropriate parameters are updated.
     */
    public void checkAndHandleFirstVisibleCellChange() {
        if (mCurrentFirstVisibleItem != mPreviousFirstVisibleItem) {
            if (mCellIsMobile && mMobileItemId != INVALID_ID) {
                updateNeighborViewsForID(mMobileItemId);
                handleCellSwitch();
            }
        }
    }

    /**
     * Determines if the listview scrolled down enough to reveal a new cell at the
     * bottom of the list. If so, then the appropriate parameters are updated.
     */
    public void checkAndHandleLastVisibleCellChange() {
        int currentLastVisibleItem = mCurrentFirstVisibleItem + mCurrentVisibleItemCount;
        int previousLastVisibleItem = mPreviousFirstVisibleItem + mPreviousVisibleItemCount;
        if (currentLastVisibleItem != previousLastVisibleItem) {
            if (mCellIsMobile && mMobileItemId != INVALID_ID) {
                updateNeighborViewsForID(mMobileItemId);
                handleCellSwitch();
            }
        }
    }
};
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<com.bin.widget.DynamicListView
    android:id="@+id/campaignListView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
                android:background="#0000"
     >
</com.bin.widget.DynamicListView>

</RelativeLayout>