2012-11-01 49 views
12

我有一個(Sherlock)FragmentActivity和2個選項卡片段。左邊的片段是一個GridView,用於顯示相冊的圖片,右邊的片段由用於查看單個圖片的ViewPager組成。從左側的片段中,您可以滾動瀏覽圖片並選擇一個。將標籤(或劃過)切換到正確的片段將顯示圖片,並且由於它是ViewPager,您可以滑動到上一張或下一張圖片。禁用在FragmentActivity中的標籤之間滑動

這個效果很好,除了FragmentActivity想攔截右滑動並移回左邊的選項卡。我想阻止FragmentActivity在正確選項卡上攔截滑動。如果我不得不禁用標籤之間的滑動操作,它會令人滿意。我只想將滑動專用於當前選項卡,而不是用於在選項卡之間移動。

以下圖片顯示了當前的行爲。右圖顯示了當我向右滑動時發生的情況。正如你所看到的左側標籤開始出現。我只需要滑動即可應用到右側標籤,這樣我就可以在圖像之間滑動,而不會出現左側標籤。

enter image description here

我看到的解決方案,以控制ViewPager內刷卡,但還沒有找到一個解決方案來控制標籤片段之間滑動。

這裏是爲GridView片段和ViewPager片段的XML:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="fill_parent" 
       android:layout_height="fill_parent" 
       android:orientation="vertical"> 
    <FrameLayout android:id="@android:id/tabcontent" 
       android:layout_width="fill_parent" 
       android:layout_height="fill_parent"> 
    <GridView xmlns:android="http://schemas.android.com/apk/res/android" 
       android:id="@+id/gridview" 
       android:layout_width="fill_parent" 
       android:layout_height="fill_parent" 
       android:columnWidth="100dip" 
       android:gravity="center" 
       android:horizontalSpacing="4dip" 
       android:numColumns="auto_fit" 
       android:stretchMode="columnWidth" 
       android:verticalSpacing="4dip" /> 
    </FrameLayout> 
</LinearLayout> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="fill_parent" 
       android:layout_height="fill_parent" 
       android:orientation="vertical"> 

    <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" 
            android:id="@+id/pager" 
            android:layout_width="fill_parent" 
            android:layout_height="0px" 
            android:layout_weight="1"/> 
</LinearLayout> 

這裏ViewPager片段的代碼摘要:

public class FragmentFlash extends SherlockFragment { 

    private GestureDetector gestureDetector; 
    View.OnTouchListener gestureListener; 
    private ViewPager pager = null; 
    private int pagerPosition; 

    @Override 
     public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     pagerPosition = 0; 
     // Gesture detection 
     gestureDetector = new GestureDetector(new MyGestureDetector()); 
     gestureListener = new View.OnTouchListener() { 
      public boolean onTouch(View v, MotionEvent event) { 
       return gestureDetector.onTouchEvent(event); 
      } 
     }; 
     } 

    @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
           Bundle savedInstanceState) { 
     View v = inflater.inflate(R.layout.flash, container, false); 
     pager = (ViewPager) v.findViewById(R.id.pager); 
     pager.setOnTouchListener(gestureListener); 
     return v; 
    } 

    class MyGestureDetector extends SimpleOnGestureListener { 
     private static final int SWIPE_MIN_DISTANCE = 10; 
     private static final int SWIPE_MAX_OFF_PATH = 250; 
     private static final int SWIPE_THRESHOLD_VELOCITY = 50; 

     @Override 
     public boolean onDown(MotionEvent e) { 
     return true;//false; make onFling work with fragments 
     } 

     @Override 
     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 
     try { 
      if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) 
       return false; 
      else 
       // right to left swipe 
       if(distanceX > SWIPE_MIN_DISTANCE) { 
        if (pagerPosition < imageUrls.length-1) 
        pager.setCurrentItem(++pagerPosition); 
       // left to right swipe 
       } else if (distanceX < -SWIPE_MIN_DISTANCE) { 
        if (pagerPosition > 0) 
        pager.setCurrentItem(--pagerPosition); 
       } 
      return true; 
     } catch (Exception e) { 
      // nothing 
     } 
     return false; 
     } 
    } 

    private class ImagePagerAdapter extends PagerAdapter { 

     private String[] images; 
     private LayoutInflater inflater; 

     ImagePagerAdapter(String[] images) { 
     this.images = images; 
     inflater = mContext.getLayoutInflater(); 
     } 

     @Override 
     public void destroyItem(View container, int position, Object object) { 
     ((ViewPager) container).removeView((View) object); 
     } 

     @Override 
     public void finishUpdate(View container) { 
     } 

     @Override 
     public int getCount() { 
     return images.length; 
     } 

     @Override 
     public Object instantiateItem(View view, int position) { 
     final View imageLayout = inflater.inflate(R.layout.item_pager_image, null); 
     final ImageView imageView = (ImageView) imageLayout.findViewById(R.id.image); 
     final ProgressBar spinner = (ProgressBar) imageLayout.findViewById(R.id.loading); 

     byte[] image = ;//get byte array from file at images[position]; 
     if (null != image) { 
      Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length); 
      imageView.setImageBitmap(bitmap); 
     } 
     ((ViewPager) view).addView(imageLayout, 0); 

     return imageLayout; 
     } 

     @Override 
     public boolean isViewFromObject(View view, Object object) { 
     return view.equals(object); 
     } 

     @Override 
     public void restoreState(Parcelable state, ClassLoader loader) { 
     } 

     @Override 
     public Parcelable saveState() { 
     return null; 
     } 

     @Override 
     public void startUpdate(View container) { 
     } 
    } 

    public void pagerPositionSet(int pagerPosition, String[] imageUrls) { 
     Log.i(Flashum.LOG_TAG, "FragmentFlash pagerPositionSet: " + pagerPosition); 
     if (pagerPosition >= 0) 
     this.pagerPosition = pagerPosition; 
     if (pager != null) { 
     pager.setAdapter(new ImagePagerAdapter(imageUrls)); 
     pager.setCurrentItem(this.pagerPosition); 
     } 
    } 

} 

這是item_pager_image.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:padding="1dip" > 

    <ImageView 
     android:id="@+id/image" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" 
     android:adjustViewBounds="true" 
     android:contentDescription="@string/descr_image" /> 

    <ProgressBar 
     android:id="@+id/loading" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" 
     android:visibility="gone" /> 

</FrameLayout> 

回答

17

好吧,我終於想通了這一點。勞倫斯道森是在正確的軌道上,而不是應用CustomViewPager的片段,它需要應用到FragmentActivity。您會發現,在由活動管理的選項卡之間切換也是ViewPager適配器。因此,XML對於該活動是

<TabHost 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/tabhost" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <LinearLayout 
     android:orientation="vertical" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <TabWidget 
      android:id="@android:id/tabs" 
      android:orientation="horizontal" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_weight="0"/> 

     <FrameLayout 
      android:id="@android:id/tabcontent" 
      android:layout_width="0dp" 
      android:layout_height="0dp" 
      android:layout_weight="0"/> 

     <com.Flashum.CustomViewPager 
      android:id="@+id/pager" 
      android:layout_width="match_parent" 
      android:layout_height="0dp" 
      android:layout_weight="1"/> 

    </LinearLayout> 
</TabHost> 

,並且,除了建議的定製ViewPager,構造使它能夠引起onInterceptTouchEvent返回false。這可以防止FragmentActivity在滑動上進行操作,以便它可以專用於片段!

public class CustomViewPager extends ViewPager { 

    private boolean enabled; 

    public CustomViewPager(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     this.enabled = **false**; 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     if (this.enabled) { 
      return super.onTouchEvent(event); 
     } 

     return false; 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     if (this.enabled) { 
      return super.onInterceptTouchEvent(event); 
     } 

     return false; 
    } 

    public void setPagingEnabled(boolean enabled) { 
     this.enabled = enabled; 
    } 
} 
+0

「而不是將CustomViewPager應用到需要應用到FragmentActivity的片段上。我沒有說明你需要將這個應用到片段,我提供的鏈接也沒有。您的答案只是從已提供的鏈接中複製代碼,該鏈接已經完全解釋瞭如何覆蓋onInterceptTouchEvent以禁用滑動。 – Ljdawson

9

您需要重寫ViewPager的onInterceptTouchEvent方法,您可以通過擴展ViewPager做到這一點,或訪問上添加此此鏈接爲一個偉大的教程:

http://blog.svpino.com/2011/08/disabling-pagingswiping-on-android.html

+1

我試過這段代碼,發現它只是用來控制ViewPager片段中的滑動操作。它不會阻止FragmentActivity嘗試在選項卡之間滑動。換句話說,當我向右滑動時,不僅會調用MyGestureDetector :: onScroll(),而且左邊的選項卡將開始出現在左邊,表示FragmentActivity也在檢測和處理滑動。 – cdavidyoung

+0

我不知道爲什麼你甚至有一個手勢探測器,ViewPager爲你處理所有的滑動 – Ljdawson

+0

我這樣做,以便我可以調整滑動的靈敏度。現在用非常小的划動,我可以保持在正確的選項卡內。但是,通過正常的滑動操作,FragmentActivity會檢測並接管。順便說一句,我曾嘗試禁用我的手勢檢測器,即使使用您引用的自定義ViewPager也沒有幫助。 – cdavidyoung