2011-11-30 10 views
27

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

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

hijos de ViewFlipper layout

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

Respuesta

53

he tenido que añadir

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

en mi actividad.

+1

tienes que agregarlo donde? –

+0

@mirroredAbstraction: En la actividad. – jul

+2

Estoy usando Fragment, ¿hay alguna manera de hacer esto en Fragments? –

10

Mi respuesta es la sam e como mi último, excepto que voy a ser más explícito.

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

Ese código proviene de la respuesta más aquí: HorizontalScrollView within ScrollView Touch Handling (Así que ve darle un voto a si el 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)) { 

El CustomScrollView sólo se interceptan en función golpes en un eje, ya sea horizontal o verticalmente las 2 líneas de código . Como solo intercepta toques en un eje, el resto de los eventos se transmitirán a sus hijos, ahora puede manejar el evento con su oyente de gesto/toque en su actividad.

También deberá cambiar las referencias/moldes al ScrollView en el nuevo personalizado (CustomScrollView).

+1

Al desplazarse, la aplicación nunca ejecuta su método onScroll. – jul

0
parentScrollView.setOnTouchListener(new View.OnTouchListener() { 

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

establezca su scrollview principal en TouchListener e implemente este código este trabajo para mí. Espero serle útil.