web-dev-qa-db-ja.com

FragmentActivityのタブ間のスワイプを無効にする

2つのタブ付きフラグメントを持つ(Sherlock)FragmentActivityがあります。左側のフラグメントはアルバムの写真を表示するGridViewであり、右側のフラグメントは個々の写真を表示するために使用されるViewPagerで構成されています。左側のフラグメントから、画像をスクロールして1つを選択できます。右側のフラグメントにタブ(またはスワイプ)すると画像が表示され、ViewPagerであるため、前または次の画像にスワイプできます。

これは、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>
12
cdavidyoung

わかりました、私はついにこれを理解しました。 Laurence Dawsonは正しい方向に進んでいましたが、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;
    }
}
17
cdavidyoung

ViewPagerのonInterceptTouchEventメソッドをオーバーライドする必要があります。これを行うには、ViewPagerを拡張するか、次のリンクにアクセスして、これを追加するための優れたチュートリアルを参照してください。

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

9
Ljdawson