2015-04-26 64 views
55

使用support-v4庫22.1.0 android支持嵌套滾動(pre android 5.0)。不幸的是,這個功能沒有真正的記錄。有兩個接口(NestedScrollingParentNestedScrollingChild)以及兩個輔助代表類(NestedScrollingChildHelperNestedScrollingParentHelper)。如何在Android上實現NestedScrolling?

有沒有人在Android上使用NestedScrolling?

我試圖設置一個小例子,我使用NestedScrollView,它實現了NestedScrollingParentNestedScrollingChild

我的佈局是這樣的:

<android.support.v4.widget.NestedScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/parent" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context=".MainActivity"> 

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

    <View 
     android:id="@+id/header" 
     android:layout_width="match_parent" android:layout_height="100dp" 
     android:background="#AF1233"/> 

    <android.support.v4.widget.NestedScrollView 
     android:id="@+id/child" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     > 

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

     <TextView 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:background="#12AF33" 
      android:text="@string/long_text"/> 

     </FrameLayout> 
    </android.support.v4.widget.NestedScrollView> 

    </LinearLayout> 

</android.support.v4.widget.NestedScrollView> 

我想顯示在NestedScrollView(ID =父),一個header view和另一NestedScrollView(ID =小孩)。

的想法是,通過使用調整在運行時子滾動視圖的高度的OnPredrawListener

public class MainActivity extends Activity { 

    @Override protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    final NestedScrollView parentScroll = (NestedScrollView) findViewById(R.id.parent); 
    final NestedScrollView nestedScroll = (NestedScrollView) findViewById(R.id.child); 
    parentScroll.setNestedScrollingEnabled(false); 
    final View header = findViewById(R.id.header); 

    parentScroll.getViewTreeObserver() 
     .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
      @Override public boolean onPreDraw() { 
      if (parentScroll.getHeight() > 0) { 
       parentScroll.getViewTreeObserver().removeOnPreDrawListener(this); 
       nestedScroll.getLayoutParams().height = parentScroll.getHeight() - 40; 
       nestedScroll.setLayoutParams(nestedScroll.getLayoutParams()); 
       nestedScroll.invalidate(); 
       return false; 
      } 
      return true; 
      } 
     }); 

    } 
} 

所以頭部視圖將被滾動遠部分,40個像素將保持可見,因爲我設置嵌套子滾動視圖的高度爲parentScroll.getHeight() - 40。 好了,在運行時設置高度並滾動父滾動視圖就像預期一樣工作(滾動標題,40像素保持可見,然後子滾動視圖填充標題下方的屏幕的其餘部分)。我希望「NestedScrolling」意味着我可以在屏幕上的任何位置製作一個滾動手勢(由父滾動視圖捕獲的觸摸事件),並且如果父滾動視圖已到達結尾,則嵌套的子滾動視圖開始滾動。 然而,似乎不是這種情況(既不是簡單的滾動手勢也不是爲了打手勢)。

觸摸事件始終由嵌套的子滾動視圖處理,如果觸摸事件在其邊界開始,否則由父滾動視圖開始。

這是「嵌套滾動」的預期行爲還是有一個選項來更改該行爲?

我也嘗試用NestedRecyclerView替換嵌套的子滾動視圖。我子類RecyclerView,並在那裏我所有的委託方法來實現NestedScrollingChildHelperNestedScrollingChild

public class NestedRecyclerView extends RecyclerView implements NestedScrollingChild { 

    private final NestedScrollingChildHelper scrollingChildHelper = 
     new NestedScrollingChildHelper(this); 


    public void setNestedScrollingEnabled(boolean enabled) { 
    scrollingChildHelper.setNestedScrollingEnabled(enabled); 
    } 

    public boolean isNestedScrollingEnabled() { 
    return scrollingChildHelper.isNestedScrollingEnabled(); 
    } 

    public boolean startNestedScroll(int axes) { 
    return scrollingChildHelper.startNestedScroll(axes); 
    } 

    public void stopNestedScroll() { 
    scrollingChildHelper.stopNestedScroll(); 
    } 

    public boolean hasNestedScrollingParent() { 
    return scrollingChildHelper.hasNestedScrollingParent(); 
    } 

    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, 
     int dyUnconsumed, int[] offsetInWindow) { 

    return scrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, 
     dyUnconsumed, offsetInWindow); 
    } 

    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { 
    return scrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow); 
    } 

    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 
    return scrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed); 
    } 

    public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 
    return scrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY); 
    } 
} 

NestedRecyclerView根本不會滾動。所有觸摸事件都由父滾動視圖捕獲。

+0

我面臨同樣的問題,並認爲這個小部件應該改進,以允許父代未使用滾動到其子。 –

+0

我認爲使回收視圖成爲nestedScrollingChild並不容易,因爲它使用LayoutManager滾動和放置其項目。因此,只有在使用NestedScrollingChildHelper實現NestedScrollingChild時將不起作用,因爲在滾動期間不會調用這些函數。 –

+0

林不知道。我想NestedScrollingParent/NestedScrollingChild用於轉發觸摸事件。我希望'NestedScrollingChild'在內部做到這一點,我看不出有什麼理由爲什麼它應該爲'ScrollView'而不是'RecyclerView'工作......'LayoutManager'不應該是一個問題... – sockeqwe

回答

3

我花了相當多的時間在這個剛剛通過android代碼試圖找出NestedScrollView中發生了什麼。以下應該工作。

public abstract class ParentOfNestedScrollView extends NestedScrollView{ 

    public ParentOfNestedScrollView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    /* 
    Have this return the range you want to scroll to until the 
    footer starts scrolling I have it as headerCard.getHeight() 
    on most implementations 
    */ 
    protected abstract int getScrollRange(); 

    /* 
    This has the parent do all the scrolling that happens until 
    you are ready for the child to scroll. 
    */ 
    @Override 
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed){ 
     if (dy > 0 && getScrollY() < getScrollRange()) { 
      int oldScrollY = getScrollY(); 
      scrollBy(0, dy); 
      consumed[1] = getScrollY() - oldScrollY; 
     } 
    } 

    /* 
    Sometimes the parent scroll intercepts the event when you don't 
    want it to. This prevents this from ever happening. 
    */ 
    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     return false; 
    } 
} 

我的一些代碼從這個question借來的。從這裏我只需要擴展這個類。我的xml有一個孩子作爲一個NestedScrollView作爲一個孩子,父母是這樣的。這並不符合我的願望,這是一項正在進行的工作。

+0

我在這個問題上失去了一天,你的解決方案救了我,謝謝! –

相關問題