Detección de gestos y edición ScrollView

Estoy tratando de crear un diseño con un ViewFlipper que contiene ScrollViews. La idea es detectar desplazamientos horizontales para pasar a ScrollView anterior / siguiente. Además, ScrollView contiene otro ViewFlipper que contiene ImageView con un detector de desplazamiento vertical para ir al anterior / siguiente ImageView. Cuando reemplazo el ScrollView por un LinearLayout ambos detectores de gestos funcionan correctamente, pero con el ScrollView, ninguno funciona (los oyentes de gesto ni siquiera son activadores). ¿Por qué usar un ScrollView deshabilita mis detectores de gestos? ¿Cómo puedo hacer que funcione?

Gracias

Actividad

public class ProduitHome extends Activity{ private Resources res; float density; private int position, parent_id;; private int num_products; private Produit produit; private ImageDownloader mImageLoader; private ViewFlipper product_viewflipper; private ScrollView current_product_layout; Animation next_product_out, next_product_in, previous_product_in, previous_product_out; private GestureDetector galleryGestureDetector; private View.OnTouchListener galleryGestureListener; private GestureDetector productGestureDetector; private View.OnTouchListener productGestureListener; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.produit_home); num_products = GlobalData.map_list_produits.get(parent_id).size(); product_viewflipper = (ViewFlipper) findViewById(R.id.product_viewflipper); LayoutInflater inflater = getLayoutInflater(); // Add num_products view to the viewflipper for(int i=0; i<num_products; i++){ ScrollView product_detail = (ScrollView) inflater.inflate(R.layout.produit_detail, null); product_viewflipper.addView(product_detail); } // Set data and show current product current_product_layout = (ScrollView) product_viewflipper.getChildAt(position); product_viewflipper.setDisplayedChild(position); setProductData(); // Set swipe listener to switch product productGestureDetector = new GestureDetector(new ProductGestureListener()); productGestureListener = new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (productGestureDetector.onTouchEvent(event)) { return true; } else{ return false; } } }; product_viewflipper.setOnTouchListener(productGestureListener); // Set switch product animation next_product_out = AnimationUtils.loadAnimation(this, R.anim.next_product_out); next_product_in = AnimationUtils.loadAnimation(this, R.anim.next_product_in); previous_product_in = AnimationUtils.loadAnimation(this, R.anim.previous_product_in); previous_product_out = AnimationUtils.loadAnimation(this, R.anim.previous_product_out); } class VerticalSwipeListener extends SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { final int SWIPE_MIN_DISTANCE = 80; final int SWIPE_MAX_OFF_PATH = 250; final int SWIPE_THRESHOLD_VELOCITY = 200; try { if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH) return false; ViewFlipper gallery = (ViewFlipper)current_product_layout.findViewById(R.id.product_gallery); if(e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) { gallery.showNext(); } else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) { gallery.showPrevious(); } ((RadioGroup)current_product_layout.findViewById(R.id.gallery_nav)).check(gallery.getDisplayedChild()); } catch (Exception e) { } return false; } } class ProductGestureListener extends SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { final int SWIPE_MIN_DISTANCE = 120; final int SWIPE_MAX_OFF_PATH = 250; final int SWIPE_THRESHOLD_VELOCITY = 200; if(!Utils.IsOnline(ProduitHome.this)){ SRPDialogs.show(ProduitHome.this, SRPDialogs.NOT_CONNECTED); } else{ try { if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) return false; if(e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { // show next product } else if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { // show previous product } } catch (Exception e) { } } return false; } } public void setProductData(){ produit = GlobalData.map_produits.get(GlobalData.map_list_produits.get(parent_id).get(position).id); TextView name = (TextView) current_product_layout.findViewById(R.id.name); name.setText(produit.libelle); // Load gallery int nPics = produit.list_url_pic.size(); if(nPics>0){ ViewFlipper gallery = (ViewFlipper) current_product_layout.findViewById(R.id.product_gallery); gallery.removeAllViews(); mImageLoader = new ImageDownloader(res, ((BitmapDrawable)res.getDrawable(R.drawable.default_row_pic)).getBitmap(), 1); final ViewFlipper.LayoutParams params_vf = new ViewFlipper.LayoutParams(ViewFlipper.LayoutParams.FILL_PARENT, ViewFlipper.LayoutParams.FILL_PARENT); for(String url : produit.list_url_pic){ // Add images to viewflipper ImageView imageView_p = new ImageView(this); imageView_p.setLayoutParams(params_vf); imageView_p.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView_p.setTag(url); imageView_p.setImageResource(R.drawable.default_row_pic); mImageLoader.download(url, imageView_p); gallery.addView(imageView_p); } // Swipe detector to switch picture in gallery galleryGestureDetector = new GestureDetector(new VerticalSwipeListener()); galleryGestureListener = new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (galleryGestureDetector.onTouchEvent(event)) { return true; } else{ return false; } } }; } } } 

Diseño de los padres

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/product_home" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/grey_bg"> <!-- more stuff --> <ViewFlipper android:id="@+id/product_viewflipper" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_below="@id/header_logo" /> <!-- more stuff --> </RelativeLayout> 

Diseño de niños de ViewFlipper

 <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/grey_bg"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="center_horizontal"> <!-- more stuff --> <RelativeLayout android:layout_below="@id/bg_content_top" android:layout_above="@id/bg_content_bottom" android:layout_width="300dp" android:layout_height="fill_parent" android:background="@drawable/bg_content" android:paddingRight="3dp" android:paddingLeft="3dp" android:layout_centerHorizontal="true"> <!-- more stuff --> <RelativeLayout android:id="@+id/content" android:layout_below="@id/title_container" android:layout_above="@id/bg_content_bottom" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="7dp" android:paddingRight="7dp" android:paddingTop="10dp" android:paddingBottom="10dp"> <ViewFlipper android:id="@+id/product_gallery" android:clickable="true" android:focusable="false" android:layout_width="100dp" android:layout_height="150dp" android:layout_marginRight="10dp" android:layout_below="@id/title_container" android:layout_toRightOf="@id/gallery_nav" /> <!-- more stuff --> </RelativeLayout> </RelativeLayout> <!-- more stuff --> </LinearLayout> </ScrollView> 

Tuve que agregar

 @Override public boolean dispatchTouchEvent(MotionEvent ev){ super.dispatchTouchEvent(ev); return productGestureDetector.onTouchEvent(ev); } 

En mi actividad.

Mi respuesta es la misma que la última, excepto que voy a ser más explícita.

Cambio

 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/grey_bg"> 

a

  <your.packagename.CustomScrollView ... etc> 

Crear una clase

 public class CustomScrollView extends ScrollView { private GestureDetector gestureDetector; View.OnTouchListener gestureListener; public CustomScrollView(Context context, AttributeSet attrs) { super(context, attrs); gestureDetector = new GestureDetector(new YScrollDetector()); setFadingEdgeLength(0); } @Override public boolean onTouchEvent(MotionEvent ev) { return super.onTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //Call super first because it does some hidden motion event handling boolean result = super.onInterceptTouchEvent(ev); //Now see if we are scrolling vertically with the custom gesture detector if (gestureDetector.onTouchEvent(ev)) { return result; } //If not scrolling vertically (more y than x), don't hijack the event. else { return false; } } // Return false if we're scrolling in the x direction class YScrollDetector extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { try { if (Math.abs(distanceY) > Math.abs(distanceX)) { return true; } else { return false; } } catch (Exception e) { // nothing } return false; } } 

Que el código viene de la respuesta superior aquí: HorizontalScrollView en ScrollView Touch Handling (así que déle un voto si la respuesta es útil). Si desea obtener la dirección perpendicular a continuación, cambiar

 if (Math.abs(distanceY) > Math.abs(distanceX)) { 

a

 if (Math.abs(distanceY) < Math.abs(distanceX)) { 

La vista de control de aduanas sólo interceptará los deslizamientos en un eje, ya sea horizontal o verticalmente dependiendo de las 2 líneas de código anteriores. Puesto que sólo intercepta los swipes en un eje el resto de los eventos se pasará a sus hijos, ahora puede manejar el evento con su gesture / touch oyente en su actividad.

También tendrá que cambiar cualquier referencia / molde a ScrollView a la nueva personalizada (CustomScrollView).

 parentScrollView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return productGestureDetector.onTouchEvent(event); } }); 

Establecer su scrollview principal en TouchListener e implementar este código este trabajo para mí. Voy a ser útil para usted.

  • Cómo puedo crear un diseño nestedScroll como este?
  • Desplazamiento en Horizontal ScrollView pierde el foco del elemento enfocado,
  • SimpleOnGestureListener no funciona para ScrollView
  • ¿Efecto de desplazamiento personalizado para scrollview?
  • RecyclerView dentro de ScrollView / NestedScrollView no se desplaza correctamente
  • Agregar elementos de forma programática a scrollview top, pero no debe desplazarse a la parte superior
  • Desplácese nestedscrollview para finalizar antes de que los rollos de reciclerview para niños
  • Espacio en blanco se agrega al final cuando pongo Webview dentro de scrollview en android
  • Scrollview no se desplaza hacia abajo completamente
  • ScrollView Inside Horizontal Scrollview no funciona correctamente
  • Correctamente desplazando un EditText a la vista cuando se enfoca
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.