GestureListener - onFling() does not stop events from propagating

590 views Asked by At

I'm practicing with SimpleGestureListener and I can catch the fling events just fine, but even when my onFling() returns true, the fragments in the layout catch the fling and react to it. I don't want this to happen.

The activity has a ViewPager that loads fragments (these fragments load images from a folder in the SD card, and there're as many framments added to the ViewPager as images are in the folder). I've attached my custom GestureListener to the RelativeLayout that serves as main container of the activity's layout. I've only overridden the onFling() event.

Code as follows:

Activity:

public class MainActivity extends FragmentActivity {

private GestureDetector gestureDetector;
private ViewPager vwpMain;
private PagerAdapter pgaMain;
private RelativeLayout layout;
private LinearLayout topLayout, bottomLayout;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
    layout = (RelativeLayout) findViewById(R.id.container);
    topLayout = (LinearLayout) findViewById(R.id.topPanel);
    bottomLayout = (LinearLayout) findViewById(R.id.bottomPanel);
    vwpMain = (ViewPager) findViewById(R.id.vwpMain);
    pgaMain = new MyPagerAdapter(getSupportFragmentManager());
    vwpMain.setAdapter(pgaMain);
    gestureDetector = new GestureDetector(this, new MyGestureListener(
            getApplicationContext(), topLayout, bottomLayout));
    layout.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            gestureDetector.onTouchEvent(event);
            return true;
        }
    });
}

public boolean dispatchTouchEvent(MotionEvent ev) {
    super.dispatchTouchEvent(ev);
    return gestureDetector.onTouchEvent(ev);
}

private class MyPagerAdapter extends FragmentPagerAdapter {

    public MyPagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    @Override
    public Fragment getItem(int pos) {
        return ImageFragment.create(pos);
    }

    @SuppressLint("SdCardPath")
    @Override
    public int getCount() {
        File f = new File("/mnt/sdcard/FragmentImages/");
        return f.listFiles().length;
    }
}
}

GestureListener:

public class MyGestureListener extends SimpleOnGestureListener {

private static final int SWIPE_MIN_DISTANCE = 75;
private static final int SWIPE_MAX_OFF_PATH = 100;
private static final int SWIPE_THRESHOLD_VELOCITY = 50;

public Context context;
public View topView, bottomView;

private enum ActivePanel {
    Top, Bottom, None
}

private ActivePanel currentPanel;

public MyGestureListener(Context _context, View top, View bottom) {
    super();
    context = _context;
    topView = top;
    bottomView = bottom;
    currentPanel = ActivePanel.None;
}

// @Override
// public boolean onDown(MotionEvent event) {
// return true;
// }

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
        float velocityY) {
    boolean result = false;
    float dX = e2.getX() - e1.getX();
    float dY = e1.getY() - e2.getY();
    if (Math.abs(dY) < SWIPE_MAX_OFF_PATH
            && Math.abs(velocityX) >= SWIPE_THRESHOLD_VELOCITY
            && Math.abs(dX) >= SWIPE_MIN_DISTANCE) {
        if (dX > 0) {
            Log.d("Fragment", "Swiping right");
        } else {
            Log.d("Fragment", "Swiping left");
        }
        if (currentPanel != ActivePanel.None) {
            result = true;
        }
    } else if (Math.abs(dX) < SWIPE_MAX_OFF_PATH
            && Math.abs(velocityY) >= SWIPE_THRESHOLD_VELOCITY
            && Math.abs(dY) >= SWIPE_MIN_DISTANCE) {
        if (dY > 0) {
            Log.d("Fragment", "Swiping up");
            switch (currentPanel) {
            case None:
                // Show bottom panel
                Animation showBottomPanel = AnimationUtils.loadAnimation(
                        context, R.anim.show_bottom);
                bottomView.bringToFront();
                bottomView.startAnimation(showBottomPanel);
                bottomView.setVisibility(View.VISIBLE);
                currentPanel = ActivePanel.Bottom;
                break;
            case Top:
                // Hide top panel
                Animation hideTopPanel = AnimationUtils.loadAnimation(
                        context, R.anim.hide_top);
                topView.bringToFront();
                topView.startAnimation(hideTopPanel);
                topView.setVisibility(View.GONE);
                currentPanel = ActivePanel.None;
                break;
            case Bottom:
                // Do nothing
                break;
            }
        } else {
            Log.d("Fragment", "Swiping down");
            switch (currentPanel) {
            case None:
                // Show top panel
                Animation showTopPanel = AnimationUtils.loadAnimation(
                        context, R.anim.show_top);
                topView.bringToFront();
                topView.setVisibility(View.VISIBLE);
                topView.startAnimation(showTopPanel);
                currentPanel = ActivePanel.Top;
                break;
            case Top:
                // Do nothing
                break;
            case Bottom:
                // Hide bottom panel
                Animation hideBottomPanel = AnimationUtils.loadAnimation(
                        context, R.anim.hide_bottom);
                bottomView.bringToFront();
                bottomView.startAnimation(hideBottomPanel);
                bottomView.setVisibility(View.GONE);
                currentPanel = ActivePanel.None;
                break;
            }
        }
        result = false;
    } else {
        result = false;
    }
    return result;
}
}

Layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin_noborder"
    android:paddingLeft="@dimen/activity_horizontal_margin_noborder"
    android:paddingRight="@dimen/activity_horizontal_margin_noborder"
    android:paddingTop="@dimen/activity_vertical_margin_noborder"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/topPanel"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#88000000"
        android:gravity="center"
        android:orientation="horizontal"
        android:visibility="gone" >

        <TextView
            android:id="@+id/topPanelTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/topPanelText"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="@android:color/white" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/bottomPanel"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#88000000"
        android:gravity="center"
        android:orientation="horizontal"
        android:visibility="gone" >

        <TextView
            android:id="@+id/bottomPanelTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/bottomPanelText"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="@android:color/white" />
    </LinearLayout>

    <android.support.v4.view.ViewPager
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/vwpMain"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>
1

There are 1 answers

0
Léster On BEST ANSWER

In case someone is struggling with this, I found a great answer here: http://blog.svpino.com/2011/08/disabling-pagingswiping-on-android.html

Basically, create a new class that inherits from ViewPager as follows:

public class CustomViewPager extends ViewPager {

    private boolean enabled;

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

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

and then change your ViewPager in your layout to the new class instead:

<mypackage.customviewpager 
    android:id="@+id/photosViewPager" 
    android:layout_height="match_parent" 
    android:layout_width="match_parent"
    //rest of properties here
    />

Each time you want to disable viewpager interaction, call setPagingEnabled with false and with true to reeenable.