通过UI反馈动态控制ViewPager可以滚动的方向

时间:2012-11-07 13:07:24

标签: android android-viewpager

我正在使用一个使用多个页面进行滑动的应用程序,但在某些页面上,我希望能够阻止滚动到下一页,直到他们选择了某些内容。

目前我已经扩展了ViewPager:

/* (non-Javadoc)
 * @see android.support.v4.view.ViewPager#onInterceptTouchEvent(android.view.MotionEvent)
 */
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (this.canGoLeft || this.canGoRight) {
        return super.onInterceptTouchEvent(event);
    }

    return false;
}

/* (non-Javadoc)
 * @see android.support.v4.view.ViewPager#onTouchEvent(android.view.MotionEvent)
 */
@Override
public boolean onTouchEvent(MotionEvent ev) {
    boolean lockScroll = false;
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
        lastX = ev.getX();
        lockScroll = false;
        return super.onTouchEvent(ev);
    case MotionEvent.ACTION_MOVE:
        if (canGoLeft && lastX < ev.getX()) {
            lockScroll = false;
        } else if (canGoRight && lastX > ev.getX()) {
            lockScroll = false;
        } else {
            lockScroll = true;
        }


        lastX = ev.getX();

        break;
    }

    lastX = ev.getX();

    if (lockScroll) {
        //make callback to prevent movement
        if (mOnPreventCallback != null) {
            mOnPreventCallback.onPreventMovement();
        }
        return false;
    } else {
        return super.onTouchEvent(ev);
    }
}

注意:我已尝试实施防止滑动到之前,但您仍然可以滑动到上一页,但您需要从最左侧滑动并向右滑动一下。它很有气质但不能完全阻止滑动。

我想在这里做三件事:

  1. 阻止滚动到下一个屏幕,直到他们选择了某个项目或其他内容
  2. 防止在整个(部分实施)中滚动到上一个屏幕
  3. 向用户提供反馈,以显示已停用滚动功能,例如Android显示带有渐变的顶部和底部屏幕的方式。

5 个答案:

答案 0 :(得分:4)

当我遇到类似的问题时,我使用gestureDetector制作了自己的Listener,并且根本没有响应滑动,你可以轻松调整它以便在某些条件下不响应向右滑动。这应该回答你的数字1和2。

这是听众:

public class OnSwipeTouchListener implements OnTouchListener {

@SuppressWarnings("deprecation")
private final GestureDetector gestureDetector = new GestureDetector(new GestureListener());

public boolean onTouch(final View v, final MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
}

private final class GestureListener extends SimpleOnGestureListener {

    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }
    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        onTouch(e);
        return true;
    }


    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        onSwipeRight();
                    } else {
                        onSwipeLeft();
                    }
                }
            } else {
               // onTouch(e);
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}
public void onTouch(MotionEvent e) {
}
public void onSwipeRight() {
//call this only if your condition was set
}

public void onSwipeLeft() {
//nothing, this means,swipes to left will be ignored
}

public void onSwipeTop() {
}

public void onSwipeBottom() {
}
}

这是一个使用示例:

viewPager.setOnTouchListener(new OnSwipeTouchListener() {
public void onSwipeRight() {
  if(your conditionIsMet){
// move your pager view to the right
     }
   }

});

可能有一个更简单,更优雅的解决方案,但这对我来说效果很好。

答案 1 :(得分:2)

我一直在谷歌搜索高低,以解决这个问题... 我试图改写ontouchevent等......

我认为这对我来说是最好的解决方案(而且不那么笨拙) 只是为了实现最大或最小跟踪器并将其设置为当前页面

        maxPageToScroll = viewPager.getCurrentItem();
        minPageToScroll = viewPager.getCurrentItem();

然后添加到“onPageSelected”方法:

public void onPageSelected(int position) {

        if (position < minPageToScroll) {
            viewPager.setCurrentItem(maxPageToScroll);
        }
        else if (position > maxPageToScroll) {
            viewPager.setCurrentItem(maxPageToScroll);
            // you can alert here that user needs to do certain actions before proceeding
        }
        else { 
            // enter normal commands here
        }

因此,当满足条件时,您只需将maxpage增加一个..

        maxPageToScroll = viewPager.getCurrentItem() + 1;

请注意,这不会阻止用户表单滚动...它只会阻止视图寻呼机更改页面。

答案 2 :(得分:1)

我认为不需要扩展ViewPager。您需要做的是修改提供给PagerAdapter的页面列表。这意味着,您检查某个页面是否标记为“已完成”,然后才将下一页添加到列表中。这就是ViewPager的工作方式。

看看Roman Nurik's wizard-pager implementation。在MainActivity中有一个名为recalculateCutOffPage的方法,它完成了我所说的。

答案 3 :(得分:1)

您可以使用自定义视图寻呼机

public class CustomViewPager extends ViewPager
{   
float mStartDragX;
OnSwipeOutListener mListener;
Context context;
public static boolean enabled;

public CustomViewPager(Context context, AttributeSet attrs)
{
    super(context, attrs);
    this.context = context;
    enabled = true;
}


@Override
public boolean onTouchEvent(MotionEvent event)
{

    if (enabled) //view pager scrolling enable if true
    {
        return super.onTouchEvent(event);
    }
    return false;
}


@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{

    if (enabled)enter code here
    {
        return super.onInterceptTouchEvent(ev);
    }
    else  // view pager disable scrolling 
    {
        float x = ev.getX();
        switch (ev.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                mStartDragX = x;

                break;
            case MotionEvent.ACTION_MOVE:
                if (mStartDragX < x - 100)//100 value velocity
                {
                    //Left scroll 
                    //return super.onInterceptTouchEvent(ev); 
                }
                else
                    if (mStartDragX > x + 100)
                    {
                        //Right scroll 
                        //return super.onInterceptTouchEvent(ev);
                    }
                break;
        }
    }

    return false;

}


public void setOnSwipeOutListener(OnSwipeOutListener listener)
{
    mListener = listener;
}

public interface OnSwipeOutListener
{

    public void onSwipeOutAtStart();


    public void onSwipeOutAtEnd();
}

}

答案 4 :(得分:-1)

我为一个具有最大页面的向导实施了viewpager,用户无法通过该页面。

最后解决方案在适配器中。 我更改了PagerAdapter的计数,这样就阻止了用户传递最大页面:

@Override
public int getCount() {
    return mProgress; //max page + 1
}

当用户进入下一页时:

private void setWizardProgress(int progress) {
    if(progress > mProgress) {
        mProgress = progress;
        mWizardPagerAdapter.notifyDataSetChanged();
    }
}

这样,当用户处于最大页面时,他无法向右滚动,直到更新进度。