2012-05-23 37 views
103

Tôi đang sử dụng HorizontalScrollView trong bố cục và tôi cần phải xác định người dùng đã đạt đến điểm bắt đầu và điểm kết thúc của cuộn.Tôi có thể có onScrollListener cho một ScrollView không?

Đối với ListView Tôi đã thử một số onScrollListener và có thể tìm điểm bắt đầu và điểm kết thúc của cuộn.

Tôi đã cố gắng thực hiện tương tự trong Scrollview của mình nhưng có vẻ như không thể. Có cách nào khác để đạt được những gì tôi cần.

Xin cảm ơn trước.

+3

Có thể. Xem câu trả lời của người dùng2695685. Trong ngắn hạn sau trong 'onStart' sẽ làm các trick:' hsv.getViewTreeObserver(). AddOnScrollChangedListener (mới ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i (TAG, "cuộn:" + hsv. getScrollX());}}); 'trong onStart() trong đó' hsv' là một tác phẩm 'HorizontalScrollView'. – JohnnyLambada

+0

chấp nhận bất kỳ câu trả lời hữu ích nào .. nếu người khác đăng câu trả lời của riêng bạn .. –

+7

Tại sao phát hiện sự kiện cuộn bằng ScrollView rất khó trong Android? Đây là hạt imo. – worked

Trả lời

310

Mọi phiên bản Xem cuộc gọi getViewTreeObserver(). Bây giờ khi giữ một thể hiện của ViewTreeObserver, bạn có thể thêm OnScrollChangedListener() vào nó bằng cách sử dụng phương thức addOnScrollChangedListener().

Bạn có thể xem thêm thông tin về lớp học này here.

Nó cho phép bạn biết về mọi sự kiện cuộn - nhưng không có tọa độ. Bạn có thể nhận được chúng bằng cách sử dụng getScrollY() hoặc getScrollX() từ bên trong trình nghe mặc dù.

scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() { 
    @Override 
    public void onScrollChanged() { 
     int scrollY = rootScrollView.getScrollY(); // For ScrollView 
     int scrollX = rootScrollView.getScrollX(); // For HorizontalScrollView 
     // DO SOMETHING WITH THE SCROLL COORDINATES 
    } 
}); 
+3

Câu trả lời này phải được đánh dấu đúng. 'hsv.getViewTreeObserver(). addOnScrollChangedListener (mới ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i (TAG," cuộn: "+ hsv.getScrollX());}});' trong onStart () 'hsv' là tác phẩm' HorizontalScrollView'. Tôi nghi ngờ như vậy sẽ làm việc cho một ScrollView là tốt. – JohnnyLambada

+3

chính xác. đây là câu trả lời hay nhất. không cần phải mở rộng HorizontalScrollView. Chỉ cần thử nghiệm với một ScrollView, hoạt động tuyệt vời: cuối cùng ScrollView sv = (ScrollView) findViewById (R.id.scrollViewArticle); sv.getViewTreeObserver(). AddOnScrollChangedListener (mới ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { Log.d ("onScrollChanged Y", String.valueOf (sv.getScrollY())); } }); –

+5

mục này phải được đánh dấu là câu trả lời đúng. –

14

Đây là một nguồn gốc HorizontalScrollView tôi đã viết để xử lý thông báo về cuộn và cuộn kết thúc. Nó đúng cách xử lý khi người dùng đã ngừng tích cực di chuyển khi nó hoàn toàn decelerates sau khi người dùng cho phép đi:

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; 
    } 

} 
+0

Dường như điều này tốt hơn là sử dụng phương thức ViewTreeObserver. Chỉ vì khi bạn có một hoạt động mà bạn có nhiều đoạn được tải (ví dụ 3 đoạn với các tab trượt) với ListViews và ScrollViews và bạn cần đăng ký các sự kiện cho chế độ xem cụ thể. Trong khi nếu ViewTreeObserver được đăng ký, nó sẽ kích hoạt các sự kiện ngay cả khi nó không phải là chế độ xem đang kích hoạt. –

+3

@ZaBlanc - Bạn có thể vui lòng liên lạc với tôi về cách khởi tạo lớp này và người nghe từ Hoạt động của tôi, tổ chức ScrollView không? Tôi đã thực hiện nó tốt, nhưng người nghe sẽ không trả lại bất kỳ giá trị nào được nêu ra. –

+0

Điều này thực sự hoạt động! và không cần sdk> 23 cho nó :) –

31

Điều này có thể rất hữu ích. Sử dụng NestedScrollView thay vì ScrollView. Thư viện hỗ trợ 23.1 đã giới thiệu một số OnScrollChangeListener đến NestedScrollView. Vì vậy, bạn có thể làm một cái gì đó như thế này.

myScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { 
     @Override 
     public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { 
      Log.d("ScrollView","scrollX_"+scrollX+"_scrollY_"+scrollY+"_oldScrollX_"+oldScrollX+"_oldScrollY_"+oldScrollY); 
      //Do something 
     } 
    }); 
+0

Chắc chắn dễ dàng hơn việc theo dõi xem bạn đã thêm người nghe trước với getViewTreeObserver() hay chưa. Cảm ơn! –

+0

Nhưng cách sử dụng NestedScrollView làm chế độ xem cuộn ngang? Không thể tìm thấy bất kỳ tài nguyên nào – GensaGames

+0

Điều gì sẽ xảy ra nếu tôi muốn sử dụng cuộn ngang? –

0
// --------Start Scroll Bar Slide-------- 
    final HorizontalScrollView xHorizontalScrollViewHeader = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewHeader); 
    final HorizontalScrollView xHorizontalScrollViewData = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewData); 
    xHorizontalScrollViewData.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { 
     @Override 
     public void onScrollChanged() { 
      int scrollX; int scrollY; 
      scrollX=xHorizontalScrollViewData.getScrollX(); 
      scrollY=xHorizontalScrollViewData.getScrollY(); 
      xHorizontalScrollViewHeader.scrollTo(scrollX, scrollY); 
     } 
    }); 
    // ---------End Scroll Bar Slide--------- 
+0

Mã này có thể sử dụng thấp hơn API17. –

+0

hãy thử thêm một số mô tả để hỗ trợ bạn mã mà sẽ làm cho tất cả mọi người hiểu bột –

+0

Mã này rất giống với [answer] khác (https://stackoverflow.com/a/23365539/5728095), phải không? – Sergii

Các vấn đề liên quan