top setnestedscrollingenabled scrolling recyclerview not inside ejemplo disable android android-recyclerview horizontal-scrolling nestedscrollview

android - setnestedscrollingenabled - recyclerview not scrolling



NestedScrollView y Horizontal RecyclerView Smooth Scrolling (3)

Así que el problema de desplazamiento suave está arreglado ahora. Fue causado por un error en NestedScrollView en la biblioteca de soporte de diseño (actualmente 23.1.1).

Puede leer sobre el problema y la solución simple aquí: https://code.google.com/p/android/issues/detail?id=194398

En resumen, después de realizar un lanzamiento, nestedscrollview no registró una completa en el componente de la rueda de desplazamiento y, por lo tanto, necesitaba un evento ''ACTION_DOWN'' adicional para evitar que el progenitor nestedscrollview interceptara (comiera) los eventos posteriores. Entonces, lo que sucedió fue si intentó desplazar su lista secundaria (o viewpager), después de un lanzamiento, el primer toque libera el enlace NSV principal y los toques subsiguientes funcionarán. Eso estaba haciendo el UX realmente malo.

Esencialmente es necesario agregar esta línea en el evento ACTION_DOWN del NSV:

computeScroll();

Esto es lo que estoy usando:

public class MyNestedScrollView extends NestedScrollView { private int slop; private float mInitialMotionX; private float mInitialMotionY; public MyNestedScrollView(Context context) { super(context); init(context); } private void init(Context context) { ViewConfiguration config = ViewConfiguration.get(context); slop = config.getScaledEdgeSlop(); } public MyNestedScrollView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public MyNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private float xDistance, yDistance, lastX, lastY; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final float x = ev.getX(); final float y = ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: xDistance = yDistance = 0f; lastX = ev.getX(); lastY = ev.getY(); // This is very important line that fixes computeScroll(); break; case MotionEvent.ACTION_MOVE: final float curX = ev.getX(); final float curY = ev.getY(); xDistance += Math.abs(curX - lastX); yDistance += Math.abs(curY - lastY); lastX = curX; lastY = curY; if (xDistance > yDistance) { return false; } } return super.onInterceptTouchEvent(ev); }

}

Utilice esta clase en lugar de su nestedscrollview en el archivo xml, y las listas secundarias deben interceptar y manejar los eventos táctiles correctamente.

Few, en realidad hay muchos errores como estos que me dan ganas de deshacerme de la biblioteca de soporte de diseño y volver a visitarla cuando esté más madura.

Tengo una vista de nido vertical única que contiene un montón de vistas de reciclaje con una configuración de administrador de diseño horizontal. La idea es bastante similar a cómo se ve la nueva tienda de Google Play. Soy capaz de hacerlo funcional pero no es suave en absoluto. Aquí están los problemas:

1) El elemento de recyclerview horizontal no puede interceptar el evento táctil la mayoría de las veces, aunque lo toque directamente. La vista de desplazamiento parece tener prioridad para la mayoría de los movimientos. Es difícil para mí obtener un gancho en el movimiento horizontal. Este UX es frustrante ya que necesito intentarlo varias veces antes de que funcione. Si verifica la tienda de juegos, es capaz de interceptar el evento táctil realmente bien y simplemente funciona bien. Noté que en la tienda de juegos la forma en que lo configuran son muchas vistas de reciclaje horizontales dentro de una vista de reciclaje vertical. No scrollview.

2) La altura de las vistas de reciclaje horizontales se debe establecer manualmente y no hay una manera fácil de calcular la altura de los elementos secundarios.

Aquí está el diseño que estoy usando:

<android.support.v4.widget.NestedScrollView android:id="@+id/scroll" android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" android:background="@color/dark_bgd" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:id="@+id/main_content_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone" tools:visibility="gone" android:orientation="vertical"> <android.support.v7.widget.RecyclerView android:id="@+id/starring_list" android:paddingLeft="@dimen/spacing_major" android:paddingRight="@dimen/spacing_major" android:layout_width="match_parent" android:layout_height="180dp" />

Este patrón de IU es muy básico y es muy probable que se use en muchas aplicaciones diferentes. He leído muchas SO donde la gente dice que es una mala idea poner una lista dentro de una lista, pero es un patrón de interfaz de usuario muy común y moderno que se utiliza en todas partes. Piense en la interfaz tipo netflix con una serie de listas de desplazamiento horizontal dentro una lista vertical. ¿No hay una manera suave de lograr esto?

Imagen de ejemplo de la tienda:


Dado que la solución falc0nit3 ya no funciona (actualmente el proyecto usa 28.0.0 versión 28.0.0 de la biblioteca de soporte), encontré otra.

La razón de fondo del problema sigue siendo la misma, la vista desplazable come en el evento hacia abajo devolviendo true en el segundo toque, donde no debería hacerlo, ya que, naturalmente, el segundo toque en la vista de lanzamiento detiene el desplazamiento y se puede usar con el próximo evento de move para inicio opuesto scroll El problema se reproduce como con NestedScrollView como con RecyclerView . Mi solución es detener el desplazamiento manualmente antes de que la vista nativa pueda interceptarlo en onInterceptTouchEvent . En este caso, no se comerá el evento ACTION_DOWN , porque ya se ha detenido.

Entonces, para NestedScrollView :

class NestedScrollViewFixed(context: Context, attrs: AttributeSet) : NestedScrollView(context, attrs) { override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { if (ev.actionMasked == MotionEvent.ACTION_DOWN) { onTouchEvent(ev) } return super.onInterceptTouchEvent(ev) } }

Para RecyclerView :

class RecyclerViewFixed(context: Context, attrs: AttributeSet) : RecyclerView(context, attrs) { override fun onInterceptTouchEvent(e: MotionEvent): Boolean { if (e.actionMasked == MotionEvent.ACTION_DOWN) { this.stopScroll() } return super.onInterceptTouchEvent(e) } }

A pesar de que la solución para RecyclerView parece fácil de leer, para NestedScrollView es un poco complicada. Desafortunadamente, no hay una forma clara de detener el desplazamiento manual en el widget, cuya única responsabilidad es gestionar el desplazamiento (omg). Estoy interesado en el método abortAnimatedScroll() , pero es privado. Es posible utilizar la reflexión para abortAnimatedScroll() , pero para mí, mejor es llamar al método, que llama a abortAnimatedScroll() sí. Mire el manejo de ACTION_DOWN de ACTION_DOWN :

/* * If being flinged and user touches, stop the fling. isFinished * will be false if being flinged. */ if (!mScroller.isFinished()) { Log.i(TAG, "abort animated scroll"); abortAnimatedScroll(); }

Básicamente, la detención del lanzamiento se administra en este método, pero un poco más tarde, de lo que tenemos que llamarlo para solucionar el error

Desafortunadamente, debido a esto no podemos simplemente crear OnTouchListener y establecerlo en el exterior, por lo que solo la herencia cumple con los requisitos


He tenido éxito en hacer un desplazamiento horizontal en un padre con desplazamiento vertical con un ViewPager:

<android.support.v4.widget.NestedScrollView ... <android.support.v4.view.ViewPager android:id="@+id/pager_known_for" android:layout_width="match_parent" android:layout_height="350dp" android:minHeight="350dp" android:paddingLeft="24dp" android:paddingRight="24dp" android:clipToPadding="false"/>

clase pública UniversityKnownForPagerAdapter extiende PagerAdapter {

public UniversityKnownForPagerAdapter(Context context) { mContext = context; mInflater = LayoutInflater.from(mContext); } @Override public Object instantiateItem(ViewGroup container, int position) { View rootView = mInflater.inflate(R.layout.card_university_demographics, container, false); ... container.addView(rootView); return rootView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View)object); } @Override public int getCount() { return 4; } @Override public boolean isViewFromObject(View view, Object object) { return (view == object); }

Solo problema: debe proporcionar una altura fija para el paginador de la vista