2015-09-17 16 views
8

Tôi có một ListView trong một ScrollView để hiển thị bình luận và tôi muốn làm như sau:đèo sự kiện chuyển động để cha mẹ scrollview khi listview ở phía trên/dưới

Khi người dùng swipes xuống, đầu tiên ScrollView nên hoàn toàn cuộn xuống dưới danh sách ở dưới cùng. Sau khi hoàn toàn xuống, Listiew sẽ bắt đầu cuộn.

Tương tự, khi người dùng cuộn lên, đầu tiên là ListView (thứ tự được đảo ngược tại đây!) Sẽ cuộn lên, trước khi ScrollView bắt đầu cuộn.

Cho đến nay tôi đã làm như sau:

listView.setOnTouchListener(new View.OnTouchListener() { 
     // Setting on Touch Listener for handling the touch inside ScrollView 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 

      // If going up but the list is already at up, return false indicating we did not consume it. 
      if(event.getAction() == MotionEvent.ACTION_UP) { 
       if (listView.getChildCount() == 0 && listView.getChildAt(0).getTop() == 0) { 
        Log.e("Listview", "At top!"); 
        return false; 
       } 
      } 

      // Similar behaviour but when going down check if we are at the bottom. 
      if(event.getAction() == MotionEvent.ACTION_DOWN) { 
       if (listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1 && 
         listView.getChildAt(listView.getChildCount() - 1).getBottom() <= listView.getHeight()) { 
        Log.e("Listview","At bottom!"); 
        v.getParent().requestDisallowInterceptTouchEvent(false); 
        return false; 
       } 
      } 
      v.getParent().requestDisallowInterceptTouchEvent(true); 
      return false; 
     } 
    }); 

Các bản ghi kích hoạt tại thời điểm thích hợp, tuy nhiên ScrollView sẽ không di chuyển ngay cả khi tôi trả về false.

Tôi cũng đã cố gắng thêm v.getParent().requestDisallowInterceptTouchEvent(false); vào các câu lệnh, nhưng điều đó cũng không hoạt động.

Tôi làm cách nào để nó hoạt động?

+0

tôi đã cố gắng làm điều này (làm tổ một listview trong scrollview của tôi) và tôi không thể có được nó để làm việc. Tôi đã kết thúc bằng cách sử dụng hai NestedScrollView – PeonProgrammer

+0

Tôi nhìn vào lớp NestedScrollView quá, nhưng như chỉ vào danh sách chủ đề khác có một số chức năng bổ sung hơn ví dụ một LinearLayout bên trong scrollview – Gooey

+0

Nói chung tôi sẽ khuyên bạn nên sử dụng một cái nhìn tiêu đề trong một ListView, thay vào đó làm tổ một ListView bên trong một ScrollView - Các container cuộn lồng nhau pre-RecyclerView có phần hơi đau. –

Trả lời

8

Bạn có thể tạo tùy chỉnh ScrollViewListView và ghi đè

onInterceptTouchEvent(MotionEvent event) 

như thế này:

@Override 
public boolean onInterceptTouchEvent(MotionEvent event) { 
    View view = (View) getChildAt(getChildCount()-1); 
    int diff = (view.getBottom()-(getHeight()+getScrollY())); 

    if(event.getAction() == MotionEvent.ACTION_DOWN) { 
     if (diff ==0) { 
      return false; 
     } 
    } 

    return super.onInterceptTouchEvent(event); 
} 

Bằng cách này mỗi cảm ứng Down về ListView trong khi bạn đang ở dưới cùng của ScrollView sẽ đi đến ListView.

Đây chỉ là một việc thực hiện phác thảo nhưng tôi nghĩ bạn có thể bắt đầu từ điều này bằng cách làm điều tương tự để phát hiện khi bạn đang ở phía trên cùng của ListView

Là một lưu ý tôi sẽ cố gắng một thực hiện dễ dàng hơn bằng cách sử dụng chỉ một ListView với nội dung hiện tại của bạn ScrollView được thêm làm tiêu đề của ListView bằng cách sử dụng listView.addHeaderView(scrollViewContent).Tôi không biết nếu điều này phù hợp với nhu cầu của bạn.

EDIT:

Phát hiện khi nên bắt đầu di chuyển các ScrollView. Giữ một tham chiếu của ListView trong ScrollView. Khi người dùng đang cuộn lên và ListView ở trên cùng, hãy để sự kiện đó được tiêu thụ theo số ScrollView.

private void init(){ 
    ViewConfiguration vc = ViewConfiguration.get(getContext()); 
    mTouchSlop = vc.getScaledTouchSlop(); 
} 

@Override 
public boolean onInterceptTouchEvent(MotionEvent event) { 
    final int action = MotionEventCompat.getActionMasked(event); 

    switch (action) { 
     case MotionEvent.ACTION_DOWN:{ 
      yPrec = event.getY(); 
     } 
     case MotionEvent.ACTION_MOVE: { 
      final float dy = event.getY() - yPrec; 

      if (dy > mTouchSlop) { 
       // Start scrolling! 
       mIsScrolling = true; 
      } 
      break; 
     } 
    } 

    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 
     mIsScrolling = false; 
    } 

    // Calculate the scrolldiff 
    View view = (View) getChildAt(getChildCount()-1); 
    int diff = (view.getBottom()-(getHeight()+getScrollY())); 

     if ((!mIsScrolling || !listViewReference.listIsAtTop()) && diff == 0) { 
      if (event.getAction() == MotionEvent.ACTION_MOVE) { 
       return false; 
      } 
    } 

    return super.onInterceptTouchEvent(event); 
} 

@Override 
public boolean onTouchEvent(MotionEvent ev) { 
    final int action = MotionEventCompat.getActionMasked(ev); 
    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 
     mIsScrolling = false; 
    } 
    return super.onTouchEvent(ev); 
} 


public void setListViewReference(MyListView listViewReference) { 
    this.listViewReference = listViewReference; 
} 

Phương pháp listIsAtTop trong ListView trông như thế này:

public boolean listIsAtTop() { 
    if(getChildCount() == 0) return true; 
    return (getChildAt(0).getTop() == 0 && getFirstVisiblePosition() ==0); 
} 
+0

Vấn đề với phương pháp này là có sự phụ thuộc vòng tròn giữa listview và scrollview. Tôi đã thử thực hiện một cái gì đó với phương pháp đánh chặn cảm ứng, nhưng khi thứ tự được đảo ngược khi cuộn lên, scrollview phải "kiểm tra" nếu listview được thực hiện đầu tiên. – Gooey

+0

Xem bản chỉnh sửa của tôi cho câu trả lời. Tôi đã thực hiện một thử nghiệm và nó hoạt động nhưng tôi không chắc chắn đây là những gì bạn đang cố gắng để đạt được. Bạn chỉ cần thiết lập một tham chiếu đến listview trong scrollview. Mã có thể yêu cầu thêm một số tinh chỉnh và dọn dẹp. – GeorgeP

0

Hãy thử này:

  1. Đầu tiên tìm thấy nếu bạn đạt được tại scrollview Bottom. Đăng ký onScrollChanged vào chế độ xem Cuộn của bạn

    @Override 
    protected void onScrollChanged(int l, int t, int oldl, int oldt) 
    { 
        // Grab the last child placed in the ScrollView, we need it to determinate the bottom position. 
        View view = (View) getChildAt(getChildCount()-1); 
    
        // Calculate the scrolldiff 
        int diff = (view.getBottom()-(getHeight()+getScrollY())); 
    
        // if diff is zero, then the bottom has been reached 
        if(diff == 0) 
        { 
         // notify that we have reached the bottom 
         // Add code here to start scrolling the ListView 
         Log.d(ScrollTest.LOG_TAG, "MyScrollView: Bottom has been reached"); 
        } 
    
        super.onScrollChanged(l, t, oldl, oldt); 
    } 
    
  2. Kiểm tra xem bạn có đạt đến đỉnh của ListView không. Kiểm tra xem firstVisibleItem là 0: -

    tableListView.setOnScrollListener(new OnScrollListener() { 
    
         public void onScrollStateChanged(AbsListView view, int scrollState) { 
    
         } 
    
         public void onScroll(AbsListView view, int firstVisibleItem, 
           int visibleItemCount, int totalItemCount) { 
          if (visibleItemCount == 0) 
          // you have reached at top of lustView 
          { 
           java.lang.System.out.println("you have reached at top of lustView!"); 
          } 
          else { 
           if ((firstVisibleItem + visibleItemCount) == totalItemCount) { 
            // put your stuff here 
            java.lang.System.out.println("end of the line reached!"); 
           } 
          } 
    
         } 
        }); 
    

Tôi hy vọng làm việc này cho bạn. Nếu gặp phải bất kỳ sự cố nào, vui lòng cho tôi biết.

+0

Phát hiện nếu tôi đạt đến phần trên cùng hoặc dưới cùng là mã của tôi đã làm, tôi muốn chuyển các sự kiện chuyển động đến chế độ xem phụ huynh tùy thuộc vào trạng thái này. – Gooey

4

Bạn không nên đặt ListView bên trong ScrollView, nhưng bạn có thể đạt được yêu cầu của mình bằng cách sử dụng ExpandableHeightListView. Điều này sẽ làm cho Listview đầy đủ chiều cao bên trong ScrollView. Không cần thêm TouchListener.

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical"> 

     <RelativeLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" > 
      <!-- your content --> 
     </RelativeLayout> 

     <my.widget.ExpandableHeightListView 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" /> 
    </LinearLayout> 
</ScrollView> 

Và một cách khác để đạt được yêu cầu của bạn là RecyclerView với tiêu đề.

+0

Trong khi nó hoạt động, nó không thực sự là những gì tôi hỏi. Điều này chỉ hiển thị tất cả các mục bên dưới nội dung, cũng có thể ném các lượt xem bên trong một LinearLayout sau đó. – Gooey

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