【问题标题】:Android: Detect when ScrollView stops scrollingAndroid:检测 ScrollView 何时停止滚动
【发布时间】:2012-01-01 04:22:11
【问题描述】:

我在 Android 中使用ScrollView,其中ScrollView 的可见部分与Scrollview 中的一个单元格大小相同。每个“单元格”的高度相同。所以我想要做的是在ScrollView 滚动后卡入位置。

目前我正在检测用户何时触摸ScrollView 以及他们何时开始滚动并从那里开始工作,但它有很多错误。当用户只是轻弹它并滚动然后减速时,它也需要工作。

在 iPhone 上,有一个类似于 didDecelerate 的函数,当 ScrollView 完成滚动时,我可以在那里执行任何我想要的代码。 Android有这样的事情吗?或者是否有一些我可以查看的代码来找出更好的方法?

我查看了 Android 文档,但找不到类似的内容。

【问题讨论】:

    标签: android scrollview


    【解决方案1】:

    这是一个旧线程,但我想添加一个我想出的更短的解决方案:

     buttonsScrollView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
    
                handler.removeCallbacksAndMessages(null)
    
                handler.postDelayed({
                      //YOUR CODE TO BE EXECUTED HERE
                    },1000)
            }
    

    自然会有 1000 毫秒的延迟。如果需要,请进行调整。

    【讨论】:

      【解决方案2】:

      我的解决方案是 Lin Yu Cheng 伟大解决方案的一个变体,并且还检测滚动何时开始和停止。

      第一步:定义一个 Horizo​​ntalScrollView 和 OnScrollChangedListener:

      CustomHorizontalScrollView scrollView = (CustomHorizontalScrollView) findViewById(R.id.horizontalScrollView);
      
      horizontalScrollListener = new CustomHorizontalScrollView.OnScrollChangedListener() {
          @Override
          public void onScrollStart() {
              // Scrolling has started. Insert your code here...
          }
      
          @Override
          public void onScrollEnd() {
               // Scrolling has stopped. Insert your code here...
          }
      };
      
      scrollView.setOnScrollChangedListener(horizontalScrollListener);
      

      步骤 2. 添加 CustomHorizo​​ntalScrollView 类:

      public class CustomHorizontalScrollView extends HorizontalScrollView {
          public interface OnScrollChangedListener {
              // Developer must implement these methods.
              void onScrollStart();
              void onScrollEnd();
          }
      
          private long lastScrollUpdate = -1;
          private int scrollTaskInterval = 100;
          private Runnable mScrollingRunnable;
          public OnScrollChangedListener mOnScrollListener;
      
          public CustomHorizontalScrollView(Context context) {
              this(context, null, 0);
              init(context);
          }
      
          public CustomHorizontalScrollView(Context context, AttributeSet attrs) {
              this(context, attrs, 0);
              init(context);
          }
      
          public CustomHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
              super(context, attrs, defStyle);
              init(context);
          }
      
          private void init(Context context) {
              // Check for scrolling every scrollTaskInterval milliseconds
              mScrollingRunnable = new Runnable() {
                  public void run() {
                      if ((System.currentTimeMillis() - lastScrollUpdate) > scrollTaskInterval) {
                          // Scrolling has stopped.
                          lastScrollUpdate = -1;
                          //CustomHorizontalScrollView.this.onScrollEnd();
                          mOnScrollListener.onScrollEnd();
                      } else {
                          // Still scrolling - Check again in scrollTaskInterval milliseconds...
                          postDelayed(this, scrollTaskInterval);
                      }
                  }
              };
          }
      
          public void setOnScrollChangedListener(OnScrollChangedListener onScrollChangedListener) {
              this.mOnScrollListener = onScrollChangedListener;
          }
      
          public void setScrollTaskInterval(int scrollTaskInterval) {
              this.scrollTaskInterval = scrollTaskInterval;
          }
      
          //void onScrollStart() {
          //    System.out.println("Scroll started...");
          //}
      
          //void onScrollEnd() {
          //    System.out.println("Scroll ended...");
          //}
      
          @Override
          protected void onScrollChanged(int l, int t, int oldl, int oldt) {
              super.onScrollChanged(l, t, oldl, oldt);
              if (mOnScrollListener != null) {
                  if (lastScrollUpdate == -1) {
                      //CustomHorizontalScrollView.this.onScrollStart();
                      mOnScrollListener.onScrollStart();
                      postDelayed(mScrollingRunnable, scrollTaskInterval);
                  }
      
                  lastScrollUpdate = System.currentTimeMillis();
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        这是另一个解决方案,在我看来非常简单和干净,自然受到上述答案的启发。基本上一旦用户结束手势检查 getScrollY() 是否仍在变化,经过短暂的延迟(这里是 50 毫秒)。

        public class ScrollViewWithOnStopListener extends ScrollView {
        
            OnScrollStopListener listener;
        
            public interface OnScrollStopListener {
                void onScrollStopped(int y);
            }
        
            public ScrollViewWithOnStopListener(Context context) {
                super(context);
            }
        
            public ScrollViewWithOnStopListener(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
        
            @Override
            public boolean onTouchEvent(MotionEvent ev) {
                switch (ev.getAction()) {
                    case MotionEvent.ACTION_UP:
                        checkIfScrollStopped();
                }
        
                return super.onTouchEvent(ev);
            }
        
            int initialY = 0;
        
            private void checkIfScrollStopped() {
                initialY = getScrollY();
                this.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        int updatedY = getScrollY();
                        if (updatedY == initialY) {
                            //we've stopped
                            if (listener != null) {
                                listener.onScrollStopped(getScrollY());
                            }
                        } else {
                            initialY = updatedY;
                            checkIfScrollStopped();
                        }
                    }
                }, 50);
            }
        
            public void setOnScrollStoppedListener(OnScrollStopListener yListener) {
                listener = yListener;
            }
        }
        

        【讨论】:

          【解决方案4】:

          我认为这在过去已经出现。 AFAIK,您无法轻松检测到这一点。我的建议是您查看ScrollView.java(这就是我们在Android 领域的工作方式:))并弄清楚如何扩展该类以提供您正在寻找的功能。这是我首先要尝试的:

           @Override
           protected void onScrollChanged(int l, int t, int oldl, int oldt) {
               if (mScroller.isFinished()) {
                   // do something, for example call a listener
               }
           }
          

          【讨论】:

          • 很好,我没有注意到 isFinished 方法!
          • 谢谢。如何访问这个 isFinished() 方法?我查看了 ScrollView.java 文件,并且 mScroller 是私有的,我无法确定可以访问它。
          • 嗯,确实。我看的不够近。这就是为什么我说我会尝试first :)。您可以执行其他操作,例如跟踪对onScrollChangedscrollTo 或任何其他滚动相关方法的调用。或者,您可以复制整个 ScrollView 代码并将该字段设为 protected。不过,我不建议这样做。
          • 通过反射访问了 mScroller。也不起作用,每次滚动视图到达您的手指位置时都会触发 isFinished(),这几乎是连续的。当用户松开手指并且滚动条停止滚动时,应该触发滚动停止事件。
          • 这个答案看起来很有希望,但由于它有点死胡同,也许应该删除它?
          【解决方案5】:

          这是我的解决方案,其中包括滚动跟踪和滚动结束:

          public class ObservableHorizontalScrollView extends HorizontalScrollView {
              public interface OnScrollListener {
                  public void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY);
                  public void onEndScroll(ObservableHorizontalScrollView scrollView);
              }
          
              private boolean mIsScrolling;
              private boolean mIsTouching;
              private Runnable mScrollingRunnable;
              private OnScrollListener mOnScrollListener;
          
              public ObservableHorizontalScrollView(Context context) {
                  this(context, null, 0);
              }
          
              public ObservableHorizontalScrollView(Context context, AttributeSet attrs) {
                  this(context, attrs, 0);
              }
          
              public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
                  super(context, attrs, defStyle);
              }
          
              @Override
              public boolean onTouchEvent(MotionEvent ev) {
                  int action = ev.getAction();
          
                  if (action == MotionEvent.ACTION_MOVE) {
                      mIsTouching = true;
                      mIsScrolling = true;
                  } else if (action == MotionEvent.ACTION_UP) {
                      if (mIsTouching && !mIsScrolling) {
                          if (mOnScrollListener != null) {
                              mOnScrollListener.onEndScroll(this);
                          }
                      }
          
                      mIsTouching = false;
                  }
          
                  return super.onTouchEvent(ev);
              }
          
              @Override
              protected void onScrollChanged(int x, int y, int oldX, int oldY) {
                  super.onScrollChanged(x, y, oldX, oldY);
          
                  if (Math.abs(oldX - x) > 0) {
                      if (mScrollingRunnable != null) {
                          removeCallbacks(mScrollingRunnable);
                      }
          
                      mScrollingRunnable = new Runnable() {
                          public void run() {
                              if (mIsScrolling && !mIsTouching) {
                                  if (mOnScrollListener != null) {
                                      mOnScrollListener.onEndScroll(ObservableHorizontalScrollView.this);
                                  }
                              }
          
                              mIsScrolling = false;
                              mScrollingRunnable = null;
                          }
                      };
          
                      postDelayed(mScrollingRunnable, 200);
                  }
          
                  if (mOnScrollListener != null) {
                      mOnScrollListener.onScrollChanged(this, x, y, oldX, oldY);
                  }
              }
          
              public OnScrollListener getOnScrollListener() {
                  return mOnScrollListener;
              }
          
              public void setOnScrollListener(OnScrollListener mOnEndScrollListener) {
                  this.mOnScrollListener = mOnEndScrollListener;
              }
          
          }
          

          【讨论】:

            【解决方案6】:

            我的方法是通过每次调用 onScrollChanged() 时更改的时间戳来确定滚动状态。 很容易确定滚动的开始和结束时间。 您还可以更改阈值(我使用 100 毫秒)来修复灵敏度。

            public class CustomScrollView extends ScrollView {
                private long lastScrollUpdate = -1;
            
                private class ScrollStateHandler implements Runnable {
            
                    @Override
                    public void run() {
                        long currentTime = System.currentTimeMillis();
                        if ((currentTime - lastScrollUpdate) > 100) {
                            lastScrollUpdate = -1;
                            onScrollEnd();
                        } else {
                            postDelayed(this, 100);
                        }
                    }
                }
            
                @Override
                protected void onScrollChanged(int l, int t, int oldl, int oldt) {
                    super.onScrollChanged(l, t, oldl, oldt);
                    if (lastScrollUpdate == -1) {
                        onScrollStart();
                        postDelayed(new ScrollStateHandler(), 100);
                    }
            
                    lastScrollUpdate = System.currentTimeMillis();
                }
            
                private void onScrollStart() {
                    // do something
                }
            
                private void onScrollEnd() {
                    // do something
                }
            
            }
            

            【讨论】:

            【解决方案7】:

            这里有一些很好的答案,但是我的代码可以检测到滚动停止的时间,而无需扩展 ScrollView 类。 每个视图实例都可以调用 getViewTreeObserver()。当持有这个 ViewTreeObserver 实例时,您可以使用函数 addOnScrollChangedListener() 添加一个 OnScrollChangedListener。

            声明如下:

            private ScrollView scrollListener;
            private volatile long milesec;
            
            private Handler scrollStopDetector;
            private Thread scrollcalled = new Thread() {
            
                @Override
                public void run() { 
                    if (System.currentTimeMillis() - milesec > 200) {
                        //scroll stopped - put your code here
                    }
                }
            }; 
            

            并在您的 onCreate(或其他地方)添加:

                scrollListener = (ScrollView) findViewById(R.id.scroll);
            
                scrollListener.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
            
                    @Override
                    public void onScrollChanged() {
                        milesec = System.currentTimeMillis();
                        scrollStopDetector.postDelayed(scrollcalled, 200);
                    }
                });
            

            您可能希望在两次检查之间花费更长或更慢的时间,但是当滚动此侦听器时,调用速度非常快,因此它的工作速度非常快。

            【讨论】:

            • 我没有尝试过这种情况,但根据我的经验,我猜想从 onScrollChanged 对 postDelayed 的重复和相互调用会导致内存泄漏。
            【解决方案8】:

            我对 ZeroG 的回答做了一些改进。主要是取消多余的任务调用,并将整个事情实现为一个私有的 OnTouchListener,所以所有的滚动检测代码都在一个地方。

            将以下代码粘贴到您自己的 ScrollView 实现中:

            private class ScrollFinishHandler implements OnTouchListener
            {
                    private static final int SCROLL_TASK_INTERVAL = 100;
            
                    private Runnable    mScrollerTask;
                    private int         mInitialPosition = 0;
            
                    public ScrollFinishHandler()
                    {
                        mScrollerTask = new Runnable() {
            
                            public void run() {
            
                                int newPosition = getScrollY();
                                if(mInitialPosition - newPosition == 0)
                                {//has stopped
            
                                   onScrollStopped(); // Implement this on your main ScrollView class
                                }else{
                                    mInitialPosition = getScrollY();
                                    ExpandingLinearLayout.this.postDelayed(mScrollerTask, SCROLL_TASK_INTERVAL);
                                }
                            }
                        };
                    }
            
                    @Override
                    public boolean onTouch(View v, MotionEvent event) 
                    {
                        if (event.getAction() == MotionEvent.ACTION_UP) 
                        {
            
                            startScrollerTask();
                        }
                        else
                        {
                            stopScrollerTask();
                        }
            
                        return false;
                    }
            
            }
            

            然后在你的 ScrollView 实现中:

            setOnTouchListener( new ScrollFinishHandler() );
            

            【讨论】:

              【解决方案9】:

              这是另一个修复,恕我直言,ScrollView 中缺少 OnEndScroll 事件错误。

              它的灵感来自hambonious 答案。 只需将此类放入您的项目中(更改包以匹配您自己的)并使用以下 xml

              package com.thecrag.components.ui;
              
              import android.content.Context;
              import android.util.AttributeSet;
              import android.widget.ScrollView;
              
              public class ResponsiveScrollView extends ScrollView {
              
                  public interface OnEndScrollListener {
                      public void onEndScroll();
                  }
              
                  private boolean mIsFling;
                  private OnEndScrollListener mOnEndScrollListener;
              
                  public ResponsiveScrollView(Context context) {
                      this(context, null, 0);
                  }
              
                  public ResponsiveScrollView(Context context, AttributeSet attrs) {
                      this(context, attrs, 0);
                  }
              
                  public ResponsiveScrollView(Context context, AttributeSet attrs, int defStyle) {
                      super(context, attrs, defStyle);
                  }
              
                  @Override
                  public void fling(int velocityY) {
                      super.fling(velocityY);
                      mIsFling = true;
                  }
              
                  @Override
                  protected void onScrollChanged(int x, int y, int oldX, int oldY) {
                      super.onScrollChanged(x, y, oldX, oldY);
                      if (mIsFling) {
                          if (Math.abs(y - oldY) < 2 || y >= getMeasuredHeight() || y == 0) {
                              if (mOnEndScrollListener != null) {
                                  mOnEndScrollListener.onEndScroll();
                              }
                              mIsFling = false;
                          }
                      }
                  }
              
                  public OnEndScrollListener getOnEndScrollListener() {
                      return mOnEndScrollListener;
                  }
              
                  public void setOnEndScrollListener(OnEndScrollListener mOnEndScrollListener) {
                      this.mOnEndScrollListener = mOnEndScrollListener;
                  }
              
              }
              

              再次更改包名称以匹配您的项目

              <com.thecrag.components.ui.ResponsiveScrollView
                      android:id="@+id/welcome_scroller"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:layout_above="@+id/welcome_scroll_command_help_container"
                      android:layout_alignParentLeft="true"
                      android:layout_alignParentRight="true"
                      android:layout_below="@+id/welcome_header_text_thecrag"
                      android:layout_margin="6dp">
                  ....
              </com.thecrag.components.ui.ResponsiveScrollView>
              

              【讨论】:

              • +1 不错,简单的答案。我将差值 2 更改为 0.5f 以反映原始 ScrollViewMAX_SCROLL_FACTOR 值。
              • 这个实现很好,但是当滚动视图在开始时没有填充时它失败了。这是一种解决方法(对于水平滚动视图,因此将所有 x 替换为 y 以获得垂直滚动视图):@Override protected void onScrollChanged(int x, int y, int oldX, int oldY) { super.onScrollChanged(x, y , 旧X, 旧Y); if (Math.abs(x - oldX) = getMeasuredWidth() || x == 0) { lastStopX = x; if (mOnEndScrollListener != null) { mOnEndScrollListener.onScrollEnded(); } } }
              • 这并不总是有效。与模拟器一样,并不总是调用 public void fling(int velocityY) 。滚动结束阈值有时超过 20 像素。
              【解决方案10】:

              我对这个问题的方法是使用计时器来检查以下 2 个“事件”。

              1) onScrollChanged() 停止被调用

              2) 用户的手指从滚动视图中抬起

              public class CustomScrollView extends HorizontalScrollView {
              
              public CustomScrollView(Context context, AttributeSet attrs) {
                  super(context, attrs);
              }
              
              Timer ntimer = new Timer();
              MotionEvent event;
              
              @Override
              protected void onScrollChanged(int l, int t, int oldl, int oldt) 
              {
                  checkAgain();
                  super.onScrollChanged(l, t, oldl, oldt);
              }
              
              public void checkAgain(){
                  try{
                      ntimer.cancel();
                      ntimer.purge();
                  }
                  catch(Exception e){}
                  ntimer = new Timer();
                  ntimer.schedule(new TimerTask() {
              
                      @Override
                      public void run() {
              
                          if(event.getAction() == MotionEvent.ACTION_UP){
                              // ScrollView Stopped Scrolling and Finger is not on the ScrollView
                          }
                          else{
                              // ScrollView Stopped Scrolling But Finger is still on the ScrollView
                              checkAgain();
                          }
                      }
                  },100);
              
              }
              
              @Override
              public boolean onTouchEvent(MotionEvent event) {
                  this.event = event; 
                  return super.onTouchEvent(event);
                  }
              }
              

              【讨论】:

                【解决方案11】:

                我最近不得不实现您描述的功能。我所做的是通过比较第一次触发 onTouchEvent 时 getScrollY() 返回的值与变量 newCheck 定义的时间后返回的值来检查 ScrollView 是否停止滚动.

                参见下面的代码(工作解决方案):

                public class MyScrollView extends ScrollView{
                
                private Runnable scrollerTask;
                private int initialPosition;
                
                private int newCheck = 100;
                private static final String TAG = "MyScrollView";
                
                public interface OnScrollStoppedListener{
                    void onScrollStopped();
                }
                
                private OnScrollStoppedListener onScrollStoppedListener;
                
                public MyScrollView(Context context, AttributeSet attrs) {
                    super(context, attrs);
                
                    scrollerTask = new Runnable() {
                
                        public void run() {
                
                            int newPosition = getScrollY();
                            if(initialPosition - newPosition == 0){//has stopped
                
                                if(onScrollStoppedListener!=null){
                
                                    onScrollStoppedListener.onScrollStopped();
                                }
                            }else{
                                initialPosition = getScrollY();
                                MyScrollView.this.postDelayed(scrollerTask, newCheck);
                            }
                        }
                    };
                }
                
                public void setOnScrollStoppedListener(MyScrollView.OnScrollStoppedListener listener){
                    onScrollStoppedListener = listener;
                }
                
                public void startScrollerTask(){
                
                    initialPosition = getScrollY();
                    MyScrollView.this.postDelayed(scrollerTask, newCheck);
                }
                
                }
                

                然后我有:

                scroll.setOnTouchListener(new OnTouchListener() {
                
                        public boolean onTouch(View v, MotionEvent event) {
                
                            if (event.getAction() == MotionEvent.ACTION_UP) {
                
                                scroll.startScrollerTask();
                            }
                
                            return false;
                        }
                });
                scroll.setOnScrollStoppedListener(new OnScrollStoppedListener() {
                
                        public void onScrollStopped() {
                
                            Log.i(TAG, "stopped");
                
                        }
                });
                

                顺便说一句,我在我的应用程序中使用了其他回复中的一些想法来执行此操作。 希望这可以帮助。有任何问题请随时询问我(们)。 干杯。

                【讨论】:

                • 谢谢,一直在寻找类似的东西。用于 Horizo​​ntalScrollView 代替,它(显然)也有效。只有 getScrollY() 必须替换为 getScrollX()
                • 在这里都试过了。这是唯一有效的。
                • 即使单击滚动视图,它也会显示“已停止”。它应该只适用于用户滚动滚动视图。那我们需要做什么呢?
                • 当你触摸屏幕时它会调用 onScrollStopped()。如果您向下滚动,则立即向上滚动 onScrollStopped() 方法将调用.. 如果您连续向上滚动和向下滚动,它将一直调用 onScrollStopped()。
                【解决方案12】:

                我将 (Horizo​​ntal)ScrollView 子类化并做了这样的事情:

                @Override
                protected void onScrollChanged(int x, int y, int oldX, int oldY) {
                    if (Math.abs(x - oldX) > SlowDownThreshold) {  
                        currentlyScrolling = true;
                    } else {
                        currentlyScrolling = false;
                        if (!currentlyTouching) {
                            //scrolling stopped...handle here
                        }
                    }
                    super.onScrollChanged(x, y, oldX, oldY);
                }
                

                我为 SlowDownThreshold 使用了 1 的值,因为它似乎总是与最后一个 onScrollChanged 事件的差异。

                为了在缓慢拖动时使其行为正确,我必须这样做:

                @Override
                public boolean onInterceptTouchEvent(MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            currentlyTouching = true;
                    }
                    return super.onInterceptTouchEvent(event);
                }
                
                @Override
                public boolean onTouch(View view, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_UP:
                        case MotionEvent.ACTION_CANCEL:
                            currentlyTouching = false;
                            if (!currentlyScrolling) {
                                //I handle the release from a drag here
                                return true;
                            }
                    }
                    return false;
                }
                

                【讨论】:

                • 不错的答案。唯一的一个补充。在 onInterceptTouchEvent() 中,您还处理 MotionEvent.ACTION_UP 和 MotionEvent.ACTION_CANCEL 否则 currentTouching 将保持为真,以防您在点击时打开另一个活动。
                • 另一个修复:在 onScrollChanged() 中,即使减速尚未达到 1,您也必须检查滚动结束。像这样: boolean end = (oldx > x) ? (x = getMaxScrollAmount()); if (Math.abs(x - oldx) > 1 && !end) { 滚动开始; } else { 滚动结束 }
                • 这在某些设备上不起作用,例如 GS3。在我的 GS3 上,y 和旧 y 之间的差异可以在滚动中间为 1。它在我的 Nexus 4 上完美运行。我不知道为什么。
                • 在三星 Galaxy Note 2 和华硕 Memo Pad 7 上也无法使用。我还在这些设备上的滚动中间看到了 1 的增量。
                【解决方案13】:

                对于您描述的简单案例,您可能可以在自定义滚动视图中使用覆盖 fling 方法。每次用户从屏幕上抬起手指时,都会调用 Fling 方法来执行“减速”。

                所以你应该做的是这样的:

                1. 子类 ScrollView。

                  public class MyScrollView extends ScrollView { 
                  
                      private Scroller scroller;  
                      private Runnable scrollerTask; 
                  
                      //...
                  
                      public MyScrollView(Context context, AttributeSet attrs) {
                          super(context, attrs);
                  
                          scroller = new Scroller(getContext()); //or OverScroller for 3.0+
                          scrollerTask = new Runnable() {
                              @Override
                              public void run() {
                                  scroller.computeScrollOffset();
                                  scrollTo(0, scroller.getCurrY());
                  
                                  if (!scroller.isFinished()) {
                                      MyScrollView.this.post(this);
                                  } else {
                                      //deceleration ends here, do your code
                                  }
                              }
                          };
                          //...
                      }
                  }
                  
                2. 子类 fling 方法,不要调用超类实现。

                  @Override  
                  public void fling(int velocityY) {  
                      scroller.fling(getScrollX(), getScrollY(), 0, velocityY, 0, 0, 0, container.getHeight());
                      post(scrollerTask);  
                  
                      //add any extra functions you need from android source code:
                      //show scroll bars
                      //change focus
                      //etc.
                  }
                  
                3. 如果用户在抬起手指之前停止滚动(velocityY == 0),则不会触发 Fling。如果您还想拦截此类事件,请覆盖 onTouchEvent。

                  @Override
                  public boolean onTouchEvent(MotionEvent ev) {
                      boolean eventConsumed = super.onTouchEvent(ev);
                      if (eventConsumed && ev.getAction() == MotionEvent.ACTION_UP) {
                          if (scroller.isFinished()) {
                              //do your code
                          }
                      }
                      return eventConsumed;
                  }
                  

                注意虽然这可行,但覆盖 fling 方法可能不是一个好主意。它是公开的,但几乎没有为子类化而设计。现在它做了 3 件事——它为私有 mScroller 启动投掷,处理可能的焦点变化并显示滚动条。这可能会在未来的 android 版本中改变。例如,私有 mScroller 实例在 2.3 和 3.0 之间将其类从 Scroller 更改为 OvershootScroller。你必须记住所有这些小差异。无论如何,为未来不可预见的后果做好准备。

                【讨论】:

                • 第二步 (2.) 中的 container.getHeight() 是什么?
                • container 是 scrollView 内部的视图。由于 scrollView 只能包含 1 个孩子,您可以将容器替换为 getChildAt(0)。
                【解决方案14】:
                        this.getListView().setOnScrollListener(new OnScrollListener(){
                        @Override
                        public void onScrollStateChanged(AbsListView view, int scrollState) {}
                
                        @Override
                        public void onScroll(AbsListView view, int firstVisibleItem,
                            int visibleItemCount, int totalItemCount) {
                                     if( firstVisibleItem + visibleItemCount >= totalItemCount ) 
                                              // Last item is shown...
                
                            }
                

                希望sn-p帮助:)

                【讨论】:

                • 不幸的是,我使用的是 ScrollView,而不是 ListView。不过还是谢谢。
                • 喂? ScrollView 不是 ListView。
                【解决方案15】:

                尝试在 StackOverflow 上查看 this question - 它与您的问题不完全相同,但它提供了一个关于如何管理 ScrollView 的滚动事件的想法。

                基本上,您需要通过扩展ScrollView 并覆盖onScrollChanged(int x, int y, int oldx, int oldy) 来创建自己的CustomScrollView。然后你需要在你的布局文件中引用它而不是像com.mypackage.CustomScrollView这样的标准ScrollView

                【讨论】:

                • 这个 onScrollChanged() 实际上是我现在正在使用的。不过还是谢谢。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-03-11
                • 2012-02-27
                • 1970-01-01
                • 2011-12-02
                • 2011-09-04
                相关资源
                最近更新 更多