Android 在ViewPager中区分用户滚动和编程页面更改

Android 在ViewPager中区分用户滚动和编程页面更改,android,android-viewpager,Android,Android Viewpager,我的应用程序中有一个android.support.v4.view.ViewPager,我想区分编程启动的平滑滚动和用户启动的触摸滚动 我已经看过了ViewPager.OnPageChangeListener,我相信答案可能就在那里,但我只是不确定如何回答。好的,所以结果证明我对ViewPager.OnPageChangeListener中的答案是正确的。具体来说,它在于使用onPageScrollStateChanged(int-state)。基本上,ViewPager中的页面可以处于三种状态

我的应用程序中有一个
android.support.v4.view.ViewPager
,我想区分编程启动的平滑滚动和用户启动的触摸滚动


我已经看过了
ViewPager.OnPageChangeListener
,我相信答案可能就在那里,但我只是不确定如何回答。

好的,所以结果证明我对
ViewPager.OnPageChangeListener
中的答案是正确的。具体来说,它在于使用
onPageScrollStateChanged(int-state)
。基本上,
ViewPager
中的页面可以处于三种状态:

  • 拖动:表示用户当前正在拖动寻呼机
  • 空闲:表示寻呼机处于空闲、已设置状态
  • 沉降:表示寻呼机正在沉降到最终位置
  • 因此,只有当用户实际拖动当前页面时,才会出现拖动状态。因此,当用户刷卡页面时,状态按以下顺序出现:拖动->结算->空闲。现在,在“设置”和“空闲”状态之间调用
    onPageSelected(int位置)
    方法。因此,为了确定页面更改是否由用户滚动引起,只需检查前一个状态是否为“拖动”,当前状态是否为“设置”。然后,您可以保留一个
    boolean
    变量来跟踪页面更改是否由用户发起,并在
    onPageSelected(int位置)
    方法中进行检查

    这是我的
    onPageScrollStateChanged
    方法

    public void onPageScrollStateChanged(int state) 
    {
        if (previousState == ViewPager.SCROLL_STATE_DRAGGING
                && state == ViewPager.SCROLL_STATE_SETTLING)
            userScrollChange = true;
    
        else if (previousState == ViewPager.SCROLL_STATE_SETTLING
                && state == ViewPager.SCROLL_STATE_IDLE)
            userScrollChange = false;
    
        previousState = state;
    }
    

    if
    else-if
    语句不必如此明确,但我这样做是为了清晰明了。

    关于使用
    ViewPager.OnPageChangeListener,您是对的。

    @Override
    public void onPageSelected(int arg0) {
        // programmatically-initiated                           
    }
    
    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
    
    }
    
    @Override
    public void onPageScrollStateChanged(int arg0) {
        // user-initiated touch scroll      
    }
    
    @Override
    public void onPageSelected(int arg0) {
    
    }
    
    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        if (progChange) {
            // programmatically-initiated
        } else {
            // user-initiated touch scroll
        }
    
        // Set progChange to false;
        progChange = false;                 
    }
    
    @Override
    public void onPageScrollStateChanged(int arg0) {
    
    }
    
    或者,您可以使用布尔标志来区分以编程方式启动的平滑滚动和用户启动的触摸滚动。例如,如果使用
    setCurrentItem(int item)
    以编程方式更改页面,请尝试:

    boolean progChange = false;
    
    ....
    ....
    ....
    
    progChange = true;
    setCurrentItem(somePageId);     // Set progChange = true every time
    
    ....
    ....
    ....
    
    在您的
    ViewPager.OnPageChangeListener中

    @Override
    public void onPageSelected(int arg0) {
        // programmatically-initiated                           
    }
    
    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
    
    }
    
    @Override
    public void onPageScrollStateChanged(int arg0) {
        // user-initiated touch scroll      
    }
    
    @Override
    public void onPageSelected(int arg0) {
    
    }
    
    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        if (progChange) {
            // programmatically-initiated
        } else {
            // user-initiated touch scroll
        }
    
        // Set progChange to false;
        progChange = false;                 
    }
    
    @Override
    public void onPageScrollStateChanged(int arg0) {
    
    }
    

    我的答案是正确的,在下面的评论中

    首先,我分析完整侦听器的行为:

    USER
    onPageScrollStateChanged:        1             SCROLL_STATE_DRAGGING
    onPageScrollStateChanged:        2             SCROLL_STATE_SETTLING
    onPageSelected:              SELECTION     
    onPageScrollStateChanged:        0             SCROLL_STATE_IDLE
    
    PROGRAMATIC
    onPageScrollStateChanged:        2             SCROLL_STATE_SETTLING
    onPageSelected:              SELECTION
    onPageScrollStateChanged:        0             SCROLL_STATE_IDLE  
    
    调查结果:
    • 如您所见,在这两种情况下,当
      onPageScrollStateChanged
      移动到
      SCROLL\u STATE\u IDLE
      时,事件结束,这意味着IDLE是周期的结束

    • 用户事件是
      SCROLL\u STATE\u drawing
      然后
      SCROLL\u STATE\u SETTLING
      ,这是编程事件的两种
      状态
      不同于只有一种
      状态

    • onPageSelected
      发生在周期结束之前,但在我们能够确定更改是由用户触发还是以编程方式触发之后,因此之前发生的任何事情都会在这一点上告诉我们是否是用户

    解决方案: 因此,我使用了一个
    列表
    ,它在每次循环结束时都会重置,为了能够知道用户是否在
    onPageSelected
    方法中触发了事件,我检查了
    列表
    的大小如果大小为2,则表示用户滚动寻呼机。

    abstract class PagerListenerActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {
    
        private static final int USER_SCROLL = 2;
        private List<Integer> validator = new ArrayList<>();
    
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }
    
        @Override
        public void onPageSelected(int position) {
            if (validator.size() == USER_SCROLL) {
                userScroll(position);
            }
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
            validator.add(state);
            if (ViewPager.SCROLL_STATE_IDLE == state) {
                validator.clear();
            }
    
        }
    
        protected abstract void userScroll(int position);
    }
    
    抽象类PagerListener活动扩展了AppCompatActivity实现了ViewPager.OnPageChangeListener{
    私有静态最终int用户_SCROLL=2;
    私有列表验证程序=新的ArrayList();
    @凌驾
    已滚动页面上的公共无效(int-position、float-positionOffset、int-positionOffsetPixels){
    }
    @凌驾
    已选择页面上的公共无效(内部位置){
    if(validator.size()=用户\u滚动){
    用户滚动(位置);
    }
    }
    @凌驾
    公共无效onPageScrollStateChanged(int状态){
    添加(状态);
    如果(ViewPager.SCROLL\u STATE\u IDLE==STATE){
    validator.clear();
    }
    }
    受保护的抽象空用户滚动(int位置);
    }
    

    现在,这个类可以方便地被另一个需要它的人继承。

    在2016年仍然是一个很好的答案。事实上,我将使用一个
    wasUserScroll()
    方法将其制作成一个抽象基类,供所有人使用。:)我应该为
    previousState
    变量设置什么初始值?如果用户正在拖动并以编程方式调用setCurrentItem,
    userScrollChange
    将为true。