¿Cómo implementar NestedScrolling en Android?

Con soporte-v4 biblioteca 22.1.0 android apoya el desplazamiento anidado (pre android 5.0). Desafortunadamente, esta característica no está documentada. Hay dos interfaces ( NestedScrollingParent y NestedScrollingChild ), así como dos clases de delegado auxiliar ( NestedScrollingChildHelper y NestedScrollingParentHelper ).

¿Alguien ha trabajado con NestedScrolling en Android?

He intentado configurar un pequeño ejemplo, donde utilizo NestedScrollView que implementa tanto NestedScrollingParent como NestedScrollingChild .

Mi diseño se ve así:

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

Quiero mostrar una header view y otro NestedScrollView (id = child) en un NestedScrollView (id = parent).

La idea era, para ajustar la altura de la vista de desplazamiento secundaria en tiempo de ejecución mediante un 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; } }); } } 

Por lo tanto, la vista de cabecera se desplaza parcialmente, 40 píxeles se mantendrán visibles desde que establezca la altura de la vista de desplazamiento de niño anidado a parentScroll.getHeight() - 40 . Muy bien, el ajuste de la altura en tiempo de ejecución y el desplazamiento de la vista de desplazamiento principal funciona de la manera esperada (el encabezado se desplaza hacia fuera, 40 píxeles permanecen visibles y el desplazamiento secundario llena el resto de la pantalla debajo del encabezado).

Espero que "NestedScrolling" signifique que puedo hacer un gesto de desplazamiento en cualquier parte de la pantalla (evento táctil capturado por la vista de desplazamiento principal) y si la vista de desplazamiento principal ha llegado al final, la vista de desplazamiento de los nidos anidados comienza a desplazarse. Sin embargo, eso no parece ser el caso (ni para los gestos de desplazamiento simple ni para los gestos de fling).

El evento táctil siempre es manejado por scrollview de niño anidado si el evento táctil comienza en sus límites, de lo contrario por la vista de desplazamiento principal.

¿Es ese el comportamiento esperado de "desplazamiento anidado" o hay una opción para cambiar ese comportamiento?

También intenté reemplazar la vista de desplazamiento secundario anidado con un NestedRecyclerView . He subclasificado RecyclerView e implementado NestedScrollingChild donde delegar todos los métodos a NestedScrollingChildHelper :

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

Pero el NestedRecyclerView no se desplaza en absoluto. Todos los eventos táctiles son capturados por la vista de desplazamiento principal.

Pasé bastante tiempo en esto simplemente pasando por el código android tratando de averiguar qué está pasando en NestedScrollView. Lo siguiente debería funcionar.

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

Parte de mi código fue tomado de esta pregunta . De esto sólo extender esta clase según sea necesario. Mi xml tiene el niño como NestedScrollView como un niño y el padre como este. Esto no maneja flings tan bien como me gustaría, eso es un trabajo en progreso.

  • Atributo "titleTextStyle" ya se ha definido en android studio 1.2.1?
  • Quitar el botón de nuevo de SearchView en la barra de herramientas AppCompat
  • Cómo utilizar MultiChoiceModeListener en ListVIew con y sin soporte?
  • Obtener AppCompat no admite la excepción de características del tema actual después de actualizar a la versión AppCompat v22.1.0 issue
  • YouTubePlayer junto con la biblioteca AppCompat v7
  • Error: (3, 5) Ningún recurso encontrado que coincida con el nombre dado
  • Personalización predeterminada Theme.AppCompat.Dialog.Alert con android.support.v7.app.AlertDialog
  • La barra de herramientas no es visible en dispositivos Android 4.X
  • DialogFragment con AppCompatDialog se bloquea si se establece STYLE_NO_TITLE
  • OnPrepareOptionsMenu en Fragmento no se llama como de AppCompat v22 (API 10)
  • OnPrepareActionMode no se llama al crear ActionMode
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.