2011-11-30 75 views
27

我正在尝试使用包含ScrollViews的ViewFlipper创建布局。这个想法是检测水平滑动移动到上一个/下一个ScrollView。此外,ScrollView还包含另一个ViewFlipper,其中包含ImageView,并带有一个垂直滑动检测器,以转至上一个/下一个ImageView。当我用LinearLayout替换ScrollView时,两个手势检测器都可以正常工作,但使用ScrollView时,都不工作(手势监听器甚至不是触发器)。为什么使用ScrollView会禁用我的手势检测器?我怎样才能使它工作?手势检测和ScrollView问题

活动

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

     } 
    } 
} 

父布局

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

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> 

回答

53

我必须在我的活动添加

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

+1

你不得不把它添加到哪里? –

+0

@mirroredAbstraction:在活动中。 – jul

+2

我正在使用片段,任何方式在片段中做到这一点? –

10

我的回答是sam作为我的最后一个,除了我会更加明确。

变化

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

<your.packagename.CustomScrollView ... etc> 

创建一个类

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

该代码来自顶部的答案在这里:HorizontalScrollView within ScrollView Touch Handling(所以去,如果给它一票了答案很有用)。

如果想要得到的垂直方向,然后更改

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

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

CustomScrollView只会截距在一个轴挥动,无论是水平或垂直根据上面的2行的代码。由于它只拦截一个轴上的滑动,其余的事件将传递给它的子项,现在您可以在您的活动中使用您的手势/触摸侦听器处理事件。

您还需要将任何参考文件/数据转换为ScrollView以更改为新的自定义文件(CustomScrollView)。

+1

滚动时,应用程序从不运行onScroll方法。 – jul

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

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

在TouchListener上设置您的主滚动视图,并为我实现此代码。我跳到将有助于你。